互联网程序设计第二讲

本文介绍了一个简单的网络对话程序设计教程,包括客户端与服务器之间的TCP套接字通信原理及实现步骤。通过具体代码示例,讲解了如何使用Java的Socket和ServerSocket类进行网络聊天程序的开发。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

第二讲 网络对话程序设计

完成日期:2018.9.17
GitHub:https://github.com/fyinh/network_programming_course/tree/master/ch02


学会基本的网络对话(网络聊天)的程序设计。
[开发帮助]
  打开NetBeans的帮助菜单,选中Javadoc应用,启动Java SE的Javadoc,可查找相关类的使用说明。

一、 简单网络对话程序

设计任务:

  客户端向服务器发送一字符串,并能读取服务器返回的字符串。

知识点:

  TCP套接字技术,C/S软件架构程序设计。

重点理解:

  Java客户套接字类Socket和服务器套接字类ServerSocket,以及字符串读/写类BuffferedReader/PrintWriter。
在这里插入图片描述
  在Java网络程序设计中,有两个套接字类:服务进程中的是ServerSocket类,客户进程中的是Socket类。

  服务进程首先开启一个或多个监听端口,客户进程向服务进程发起TCP三次握手连接,分别见下方附录1、2中的代码。

  TCP连接成功后,逻辑上可理解如下图所示,通信进程的双方具有两个流(输出流和输入流)。逻辑上可将两个流理解为两个通信管道的全双工通信模式,一个用于向对方发送数据,另一个用于接收对方的数据。
在这里插入图片描述

套接字类有两个基本的方法可以获得两个通信管道的入口:
Socket.getInputStream()方法可获得输入字节流的入口地址;
Socket.getOutputStream()方法可获得输出字节流的出口地址;

功能详细描述:

客户端程序1:TCPClient.java具有网络接收和发送能力的程序。
客户端程序2:TCPClientJFrame.java为界面模块。
服务器程序:TCPServer.java具有网络接收和发送功能。

网络对话方式是:

  客户端程序发送一条信息给服务器TCPServer.java,服务器接收并回送该信息到客户端,客户端接收并显示该信息。
  附件中提供TCPClient.java和TCPServer.java源程序,可在自己的机器上运行它。

二、程序设计第一步

过程:

(1)新建一个程序包,建议命名为socketTCP;
(2)制作并运行TCPServer程序,通过命令行窗口(netstat -an)察看是否已开启8008监听端口。
(3)TCPServer的运行问题:
  TCPServer只能运行一次,且自身不能终止运行,要终止它运行,需要点击“运行”、“停止构建”。

三、程序设计第二步

  制作并理解TCPCilent.java程序;

过程:

(1)定义对象构造方法:

socket=new Socket(host,port);//向服务进程发起TCP三次握手连接.

  Socket连接成功后,通过调用GET方法,可获得字节输出流和字节输入流,输出流用于发送信息,输入流用于接收信息。
(2)定义网络信息发送方法供外部调用:

public void send(String msg) {
	pw.println(msg); //写入网卡输出流,由系统调用底层函数,经网卡发送。
}

(3)定义网络信息接收方法供外部调用:

 public String receive(){
 	String msg;
     try {
     	msg = br.readLine();//接收一行信息,阻塞语句。
     } catch (IOException ex) { msg=null;  }
     return msg;
}

(4)定义网络连接关闭方法供外部调用:

public void close() {
	try {
	if(socket!=null)  
	socket.close();//实现四次握手断开,如下图所示.
	} catch (IOException ex) {  }
}

在这里插入图片描述

四、程序设计第三步:

(1)制作TCPClientJFrame.java主程序界面模块;
(2)创建新界面并命名为TCPClientJFrame.java程序(或利用上一讲原IOJFrame框架,重构、复制),其界面布局如下图所示。
在这里插入图片描述
注意:
  若采用了重构、复制的方法,其运行结果不如预期的话,需要查看main(){}方法中的程序名是否和TCPClientJFrame一致,并手动修改。
(3)在“连接”按钮中设置如下动作:

String ip=jTextField2.getText();
String port=jTextField3.getText();
try {
	ec=new TCPClient(ip,port);
	jTextArea1.append("服务器连接成功.\r\n");
} catch (IOException ex) {
    jTextArea1.append("服务器连接失败.\r\n");
} 

(4)在“发送”按钮中添加网络发送和接收方法:

String msg1=jTextField1.getText();  
ec.send(msg1);//发送一串字符。
String msg2=ec.receive(); //接收一行字符串。
jTextArea1.append(msg2);  

附录1:TCPClient.java源文件如下

import java.net.*;
import java.io.*;

public class TCPClient {
    //套接字程序设计.  
    private Socket socket = null;
    //用于字节和字符之间转换用的变量.
    private PrintWriter pw = null;
    private BufferedReader br = null;
    
    public TCPClient(String ip, String port) throws IOException{
        socket = new Socket(ip,Integer.parseInt(port));
        //主动向服务器发起连接,实现TCP中三次握手的过程。
        //若不成功(网络问题,地址错误,服务器资源紧张等),抛出错误,其错误信息交由调用者处理。
        //若成功,做下面两件事情。  
        
        OutputStream socketOut = socket.getOutputStream();
        pw = new PrintWriter(new OutputStreamWriter(socketOut,"GB2312"),true);
        //得到网络输出字节流地址,并装饰成网络输出字符流

        InputStream socketIn = socket.getInputStream();
        br = new BufferedReader(new InputStreamReader(socketIn,"GB2312"));
        //得到网络输入字节流地址,并装饰成网络输入字符流
    }
    
    public void send(String msg){
        pw.println(msg);
        //输出字符流,由Socket调用系统底层函数,经网卡发送字节流。
    }
    
    public String receive(){
        String msg;
        try {
            msg = br.readLine();
            //从网络输入字符流中读信息,每次只能接收一行信息.
            //若不够一行(无行结束符),该语句阻塞(阻塞语句),直到条件满足,程序才往下运行
        } catch (IOException ex) { 
            msg=null;  
        }
        return msg;
    }
    
    public void close() {
        try {
            if(socket!=null)  
            socket.close();//实现四次握手断开.
        } catch (IOException ex) {  }
    }
    
    //模块内测试与运行,需先运行TCPServer。
    public static void main(String args[]) throws IOException{
        TCPClient ec=new TCPClient("127.0.0.1","8008");
        ec.send("123456789");//发送一行字符串
        System.out.println(ec.receive());//接收一行字符串并在屏幕上显示
        ec.close();      
    }
}

附件2:TCPServer.java源文件如下

import java.io.*;
import java.net.*;

/**
 *
 * @author 高佬_
 */
public class TCPServer {
    private int port = 8008;
    private ServerSocket serverSocket = null;//服务器套接字。
    
    public TCPServer() throws IOException {
        serverSocket = new ServerSocket(8008);//开启8008号监听端口。
        System.out.println("服务器启动");
    }
    
    private PrintWriter putWriter(Socket socket)throws IOException{
        OutputStream socketOut = socket.getOutputStream();//获得输出流缓冲区的地址。
        return new PrintWriter(new OutputStreamWriter(socketOut,"GB2312"),true);
    }
    
    private BufferedReader getReader(Socket socket)throws IOException{
        InputStream socketIn = socket.getInputStream();//获得输入流缓冲区的地址
        return new BufferedReader(new InputStreamReader(socketIn,"GB2312"));
    }
    
    public void service(){
        while(true){
            Socket socket = null;
            try{
                socket = serverSocket.accept();
                //阻塞语句,监听并等待客户发起连接,有连接请求就生成一个套接字。
                System.out.println("New income: " + socket.getInetAddress());
                //本地服务器观测台显示请求的用户信息。
                BufferedReader br =getReader(socket);//定义字符串输入流。
                PrintWriter pw = putWriter(socket);//定义字符串输出流。
                
                String msg;
                while ((msg = br.readLine())!= null) //阻塞语句,从输入流中读入一行字符串。
                {
                    pw.println("来自服务器:"+msg);//向输出流中输出一行字符串。
                    pw.println("来自服务器2:"+msg);
                    if (msg.equals("bye")) //如果客户发送的消息为“bye”,就结束通信
                    break;
                }
            } catch (IOException e) {
                e.printStackTrace();
            }finally {
                try{
                    if(socket!=null)
                    socket.close();  //断开连接
                }catch (IOException e) {e.printStackTrace();}
            }
        }  
    }
    public static void main(String args[])throws IOException {
        new TCPServer().service();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值