1、Server
先启动Server端,实际是启动了一个8080端口服务,accept()会一直阻塞,直到有client消息发送过来,才会继续下方逻辑。往后逻辑完成的是,对client消息进行读取,并给出一个响应返还到client
public class Server {
public static void main(String[] args) throws IOException, InterruptedException {
ServerSocket serverSocket = new ServerSocket();
serverSocket.bind(new InetSocketAddress(8080));
while (true) {
Socket accept = serverSocket.accept();
try (InputStream inputStream = accept.getInputStream();
OutputStream outputStream = accept.getOutputStream();) {
/*
读取client过来的数据
*/
byte[] buffer = new byte[1024];
//每次读取到数据长度
int len = 0;
String requestData = "";
while ((len = inputStream.read(buffer)) != -1) {
//buffer数组有1024字节,当buffer实际有效数据可能少于1024
System.out.println(new String(buffer, 0, len));
requestData = new String(buffer, 0, len);
}
/*
给client响应
*/
outputStream.write(("response:" + requestData).getBytes(StandardCharsets.UTF_8));
outputStream.flush();
System.out.println("------睡眠1秒------");
Thread.sleep(1000);
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
}
}
}
2、Client
再启动Client,此处启动了5个线程,线程任务逻辑是先给Server发送一段消息,再阻塞读取Server的响应都进行读取。
注意点:
//把buffer刷到socket,如果屏蔽这段会导致server接收到空数据
printWriter.flush();
//给一个写结束的标志位告诉server,结束server的inputStream.read()处的阻塞,让server逻辑继续往下走。如果屏蔽这段会导致Server代码inputStream.read方法处的阻塞,导致两个服务出现一个互相等待而僵死的情况
socket.shutdownOutput();
public class Client {
public static void main(String[] args) throws IOException {
ExecutorService executorService = Executors.newFixedThreadPool(5);
for (int i = 0; i < 5; i++) {
int finalI = i;
executorService.execute(() -> {
try (Socket socket = new Socket("localhost",8080);
OutputStream outputStream = socket.getOutputStream();
InputStream inputStream = socket.getInputStream();
PrintWriter printWriter = new PrintWriter(outputStream);
){
//client传输数据
printWriter.write("hello bio:"+ finalI);
printWriter.flush();
//给一个写结束的标志位告诉server,结束server的inputStream.read的阻塞
socket.shutdownOutput();
//server响应数据读取
int len = 0;
byte[] buffer = new byte[1024];
while ((len = inputStream.read(buffer)) != -1){
System.out.println(new String(buffer,0,len));
}
} catch (IOException e) {
e.printStackTrace();
}
});
}
executorService.shutdown();
}
}
3、输出结果
Server
hello bio:4
------睡眠1秒------
hello bio:0
------睡眠1秒------
hello bio:2
------睡眠1秒------
hello bio:3
------睡眠1秒------
hello bio:1
------睡眠1秒------
Client
response:hello bio:4
response:hello bio:0
response:hello bio:2
response:hello bio:3
response:hello bio:1
总结
Sever端accept()一个client后执行后面的数据处理任务也是同步的,即需要完成一个client消息读取和响应后,才能进行下一个,这里可把accept后的任务处理改成多线程处理,以此来同时接收更多的client
多线程Server
对比单线程版本,单线程需要执行5秒,该版本只需1秒
public class ServerThread {
public static void main(String[] args) throws IOException, InterruptedException {
ServerSocket serverSocket = new ServerSocket();
serverSocket.bind(new InetSocketAddress(8080));
ExecutorService executorService = Executors.newFixedThreadPool(5);
while (true) {
Socket accept = serverSocket.accept();
executorService.execute(() -> {
try (InputStream inputStream = accept.getInputStream();
OutputStream outputStream = accept.getOutputStream();) {
/*
读取client过来的数据
*/
byte[] buffer = new byte[1024];
//每次读取到数据长度
int len = 0;
String requestData = "";
while ((len = inputStream.read(buffer)) != -1) {
//buffer数组有1024字节,当buffer实际有效数据可能少于1024
System.out.println(new String(buffer, 0, len));
requestData = new String(buffer, 0, len);
}
/*
给client响应
*/
outputStream.write(("response:" + requestData).getBytes(StandardCharsets.UTF_8));
outputStream.flush();
System.out.println("------睡眠1秒------");
Thread.sleep(1000);
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
});
}
}
}