一、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非阻塞“一对一”通信小例子,欢迎批评指正,后续继续更新改进,一起学习
版权声明:本文为qq_43615903原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。