java socket非阻塞“一对一”聊天

一、socket双向通信的问题

在上篇博客中,利用socket 实现了一个非常简单的服务端和客户端通信的小程序,**但仔细思考一下,这其中有什么问题呢?**还是先把上篇博客的代码贴出来吧(为了说明问题,代码有的地方稍有改变,只是写法不同而已)
1.服务端

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;

public class SocketServer {
    public static void main(String[] args) throws Exception {
        ServerSocket serverSocket = new ServerSocket(10086);
        Socket socket = serverSocket.accept();
        System.out.println("one client has conneted server,"+socket.getRemoteSocketAddress());
        while (true){
            System.out.println("wait data...");
            //接受
            BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            System.out.println("[client]:"+br.readLine());
            System.out.println("wait write...");
            //发送
            BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
            Scanner scanner = new Scanner(System.in);
            String str = scanner.nextLine();
            bw.write(str);
            bw.write("\n");//约定一个结束标记,告诉客户端我这条数据发完了,你可以读了
            bw.flush();
            System.out.println("data sent..");
        }
    }yi
}

客户端:

2.客户端:

```bash
import java.io.*;
import java.net.Socket;
import java.util.Scanner;

public class SocketClient {
    public static void main(String[] args) throws IOException {
        Socket socket = new Socket("127.0.0.1",10086);

        while (true){
            //发送数据
            BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
            Scanner scanner = new Scanner(System.in);
            String str = scanner.nextLine();
            bw.write(str);
            bw.write("\n");//约定一个结束标记,告诉服务端端我这条数据发完了,你可以读了
            bw.flush();
            // 接收数据
            BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            System.out.println("[server]:"+br.readLine());
        }
    }
}

1、运行结果

3.效果图:
在这里插入图片描述
在这里插入图片描述

2、问题分析

4。结果分析:
  (1)socket有两处阻塞:首先accept()出会阻塞,知道有客户端发起连接;其次,socket 输入流与输出留都会发生阻塞,这非常重要。
  我们可以看到,服务端首先阻塞在"wait data"处,等待客户端发送数据,直到客户端发送了一条数据"hello,I’m client"。
  其次,我们可以看到客户端连续发送了两条数据,但服务段只先接受了第一条--“hello,I’m client”,其次打印"wait wite",而不是直接继续打印“我是客户端呢,嘻嘻”,为什么?因为写阻塞了,服务端没有接受到控制台的输入,所以等待写,一旦输入“数据呢?”,我们可以看到,数据发送,又打印一句话"wait data",继续阻塞在读数据,因为客户端之前发过了,会直接打印,然后写阻塞。。客户端同理。
 (2)既有读又有写时,socket 因为读写阻塞不能连续接受或发送。
我们总不能只有通过发送数据,才能接受别人发送的多条数据吧,这明显是不行的。该怎么解决?一种办法是利用多线程,读写各自一个线程,互不干扰,不用等到读完才能写,写完才能读?
下面给出多现程的代码:

二、 利用多线程解决阻塞问题

1.发送线程

import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.util.Scanner;

public class SendThread implements Runnable {
    Socket socket = null;
    String me = null;
    public SendThread(Socket socket,String me) {
        this.socket = socket;
        this.me =me;
    }
    @Override
    public void run() {
        while (true){
         if(remoteSocketIsClose(socket)) break;
            try {
                System.out.println("["+me+"想说]:");
                BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
                Scanner scanner = new Scanner(System.in);
                bw.write(scanner.nextLine());
                bw.write("\n");
                bw.flush();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
     //判断对方是否断开
     public boolean remoteSocketIsClose(Socket socket){
        try {
            socket.sendUrgentData(0xcc);
            return  false;
        } catch (IOException e) {
            System.out.println("远程socket已断开...");
            return  true;
        }
    }
}

2.接受线程

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;

public class RecevieThread implements Runnable {
    Socket socket = null;
    String him = null;
    public RecevieThread (Socket socket,String him) {
        this.socket = socket;
        this.him = him;
    }
    @Override
    public void run() {
     if(remoteSocketIsClose(socket)) break;
        while (true) {
            try {
                BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                System.out.println("["+ him +"]:" + br.readLine());
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    //判断对方是否断开
     public boolean remoteSocketIsClose(Socket socket){
        try {
            socket.sendUrgentData(0xcc);
            return  false;
        } catch (IOException e) {
            System.out.println("远程socket已断开...");
            return  true;
        }
    }

}

3.服务端

import java.net.ServerSocket;
import java.net.Socket;
public class SocketServer3 {
    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = new ServerSocket(10086);
        System.out.println("server is running at"+serverSocket.getLocalSocketAddress());
        Socket socket = serverSocket.accept();
        System.out.println("one client has connected the server ," + socket.getRemoteSocketAddress());
        new Thread(new RecevieThread(socket,"client")).start();
        new Thread(new SendThread(socket,"我")).start();   
    }
}

4.客户端

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

public class SocketClient3 {
    public static void main(String[] args) throws IOException {
        Socket socket = new Socket("127.0.0.1",10086);
        new Thread(new SendThread(socket,"我")).start();
        new Thread(new RecevieThread(socket,"server")).start();

    }
}

5.效果图

server:
在这里插入图片描述
client:
在这里插入图片描述
我们可以看到,读写互不阻塞,可以连续接受发送哟,这就是简单的socket非阻塞“一对一”通信小例子,欢迎批评指正,后续继续更新改进,一起学习

发布了17 篇原创文章 · 获赞 2 · 访问量 682

猜你喜欢

转载自blog.csdn.net/qq_43615903/article/details/104131622