欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

基于TCP协议的socket编程实现简单聊天室——客户端多线程

程序员文章站 2022-06-06 16:07:07
...

前言

使用循环解决多次聊天,使用线程解决先发后收的问题。

服务器端

服务器只用一个main方法,包含创建ServerSocket对象,监听客户端连接,使用DataInputStream获取客户端传输的数据,使用DataOutputStream发送到客户端反馈,循环保证长时间通信。

    public static void main(String[] args) throws IOException {
        System.out.println("------------------服务端开启-----------------------");
        //创建ServerSocket对象
        ServerSocket serverSocket = new ServerSocket(9999);
        //监听是否有客户端连接
        Socket client = serverSocket.accept();
        //使用数据流
        DataInputStream dataInputStream = new DataInputStream(client.getInputStream());
        DataOutputStream dataOutputStream = new DataOutputStream(client.getOutputStream());

        while (true){
            String str = dataInputStream.readUTF();
            System.out.println("客户端发送数据为" +str);
            dataOutputStream.writeUTF("收到"+ str);
        }
    }

多线程发送

实现Runnable接口,我们的客户端使用BufferedReader读取字符流,使用DataOutputStream发送到服务器端。具体每行代码都有注释。


/**
 * @author gaozhihao
 * @date 2020/3/22 23:48
 */
public class Send implements Runnable{

	//缓冲字符流
    private BufferedReader bufferedReader ;
    //发送给服务器的数据流
    private DataOutputStream dataOutputStream ;
    //如果线程失败,结束线程
    private Boolean flag = true;

	//初始化BufferedReader 从键盘输入
    public Send(){
        bufferedReader = new BufferedReader(new InputStreamReader(System.in));
    }
    //有参构造传入Socket,并初始化DataOutputStream
    public Send(Socket socket){
    //调用无参构造方法
        this();
        try {
            dataOutputStream = new DataOutputStream(socket.getOutputStream());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    //读取数据
    private String getMessage(){
        String string = "";
        try {
        //键盘输入 复制给string
             string = bufferedReader.readLine();
        } catch (IOException e) {
            flag = false;
            CloseUtil.closeAll(bufferedReader);
        }
        return string;
    }

    //发送数据
    private void send(String str){
        try {
        //发送给服务器端字符串
            dataOutputStream.writeUTF(str);
        //刷新
            dataOutputStream.flush();
        } catch (IOException e) {
            flag = false;
            CloseUtil.closeAll(dataOutputStream);
        }
    }

    @Override
    public void run() {
    //当flag为true 发送键盘获取的数据
        while (flag){
            send(getMessage());
        }
    }
}

多线程接收

接收类和发送类是差不多的,主要是接收服务器端返回的数据流。


/**
 * @author gaozhihao
 * @date 2020/3/23 0:07
 */

public class Receive implements Runnable{

	//接收数据流
   private DataInputStream dataInputStream;
	//
   private Boolean flag = true;

	//有参构造传入Socket对象,初始化DataInputStream
   public Receive(Socket socket){
       try {
           dataInputStream = new DataInputStream(socket.getInputStream());
       } catch (IOException e) {
           if (dataInputStream != null){
               flag = false;
               CloseUtil.closeAll(dataInputStream);
           }

       }
   }

	//获取数据流中的数据
   private String getMessage(){
       String str = "";
       try {
           str = dataInputStream.readUTF();
       } catch (IOException e) {
           e.printStackTrace();
       }
       return str;
   }

    @Override
    public void run() {

       while (flag){
           System.out.println(this.getMessage());
       }
    }
}

客户端

客户端代码简单,主要是创建socket对象,并启动线程。

 public static void main(String[] args) throws IOException {
 		//使用InetAddress获取IP地址
        InetAddress inetAddress = InetAddress.getLocalHost();

        //创建socket对象
        Socket client = new Socket( inetAddress.getHostAddress(),9999);

		//启动发送和接收线程
        new Thread(new Send(client)).start();
        new Thread(new Receive(client)).start();
    }

运行效果

最终实现单个客户端与服务器多次通信。

相关标签: Socket