Socket TCP 协议实现服务端和客户端的简单通信-结合线程池的使用
程序员文章站
2022-03-04 08:53:02
...
前言
没啥说的,就是记录一下代码,方便以后查看
对了,本篇客户端逻辑中有一个制造慢服务的 thread.sleep ,模拟客户端很慢很慢对情况
服务端和客户端都使用了线程池
当前模式的弊端
网络通信目前流行 NIO 模式,将网络IO 等待时间从业务处理线程中抽离出来。本文并没有体现 NIO,当客户端是一个长连接当时候,服务器资源就会被占用——等待戈多(客户端发送数据)。
服务端代码
启动 main 方法,服务端启动,注意是 while(true)哦
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* 使用线程池实现 Socket 服务端 处理 Socket 请求
* @author jie.wu
*
*/
public class ConcurentSocketServer {
private static ExecutorService threadPool = Executors.newCachedThreadPool();
/**
* 处理客户端请求的线程类
* */
static class HandleMsg implements Runnable {
// 客户端套接字对象
private Socket clientSocket;
// 新增构造方法
public HandleMsg(Socket clientSocket) {
this.clientSocket = clientSocket;
}
@Override
public void run() {
// 获取客户端输入流
InputStream inputStream = null;
OutputStream outputStream = null;
PrintWriter printWriter = null;
try {
// 开始时间
Long beginTime = System.currentTimeMillis();
//处理客户端信息
inputStream = clientSocket.getInputStream();
byte b[] = new byte[1024];
StringBuffer sbf = new StringBuffer();
for (int n; (n = inputStream.read(b)) != -1;) {
sbf.append(new String(b, 0, n));
}
clientSocket.shutdownInput();
// 向客户端反馈信息
outputStream = clientSocket.getOutputStream();
printWriter = new PrintWriter(outputStream);
printWriter.write("我是服务端");
printWriter.flush();
clientSocket.shutdownOutput();
// 结束时间
long endTime = System.currentTimeMillis();
System.out.println("耗时" + (endTime - beginTime) + "ms 客户端传递进来的信息为:" + sbf.toString());
} catch (IOException e) {
e.printStackTrace();
} finally {
// 关闭资源
try {
if (inputStream != null)
inputStream.close();
if (printWriter != null)
printWriter.close();
if (outputStream != null)
outputStream.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
@SuppressWarnings("resource")
public static void main(String[] args) {
ServerSocket serverSocket = null;
Socket clientSocket = null;
try {
serverSocket = new ServerSocket(10000);
} catch (IOException e) {
e.printStackTrace();
}
// 对客户端请求对处理
while (true) {
try {
clientSocket = serverSocket.accept();
// 使用多线程进行处理
threadPool.execute(new HandleMsg(clientSocket));
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
客户端代码
也使用了线程池,同时模拟了客户端慢调用,使用 thread.sleep 对发送信息过程进行了减速
运行main 方法,线程池将发送10条请求
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* 使用线程池实现 Socket 客户端 发送 Socket 请求
*
* @author jie.wu
*
*/
public class ConcurentSocketClient {
private static ExecutorService threadPool = Executors.newCachedThreadPool();
static class HandleMsg implements Runnable {
//记录线程编号
private int threadNumber;
//重写构造方法
public HandleMsg(int threadNumber) {
this.threadNumber = threadNumber;
}
@Override
public void run() {
Socket socket = null;
OutputStream outputStream = null;
PrintWriter printWriter = null;
InputStream inputStream = null;
try {
socket = new Socket("127.0.0.1", 10000);
outputStream = socket.getOutputStream();
printWriter = new PrintWriter(outputStream);
printWriter.write("你好,");
// 客户端睡眠
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
printWriter.write("我是客户端" + threadNumber);
printWriter.flush();
socket.shutdownOutput();
// 获取服务器端返回的信息
inputStream = socket.getInputStream();
byte b[] = new byte[1024];
StringBuffer sbf = new StringBuffer();
for (int n; (n = inputStream.read(b)) != -1;) {
sbf.append(new String(b, 0, n));
}
System.out.println("服务器端反馈进来的信息为:" + sbf.toString());
socket.shutdownInput();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
// 关闭资源
try {
if (printWriter != null)
printWriter.close();
if (outputStream != null)
outputStream.close();
if (inputStream != null)
inputStream.close();
if (socket != null)
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
threadPool.execute(new HandleMsg(i));
}
}
}
运行结果
客户端
服务器端反馈进来的信息为:我是服务端
服务器端反馈进来的信息为:我是服务端
服务器端反馈进来的信息为:我是服务端
服务器端反馈进来的信息为:我是服务端
服务器端反馈进来的信息为:我是服务端
服务器端反馈进来的信息为:我是服务端
服务器端反馈进来的信息为:我是服务端
服务器端反馈进来的信息为:我是服务端
服务器端反馈进来的信息为:我是服务端
服务器端反馈进来的信息为:我是服务端
服务端
耗时1027ms 客户端传递进来的信息为:你好,我是客户端4
耗时1028ms 客户端传递进来的信息为:你好,我是客户端2
耗时1026ms 客户端传递进来的信息为:你好,我是客户端6
耗时1030ms 客户端传递进来的信息为:你好,我是客户端5
耗时1033ms 客户端传递进来的信息为:你好,我是客户端0
耗时1033ms 客户端传递进来的信息为:你好,我是客户端3
耗时1034ms 客户端传递进来的信息为:你好,我是客户端1
耗时1032ms 客户端传递进来的信息为:你好,我是客户端9
耗时1034ms 客户端传递进来的信息为:你好,我是客户端8
耗时1036ms 客户端传递进来的信息为:你好,我是客户端7
参考文献
[1]、https://blog.csdn.net/bestcxx/article/details/73753649
[2]、《Java 高并发程序设计》 2016年8月
推荐阅读
-
linux网络编程之用socket实现简单客户端和服务端的通信(基于TCP)
-
Python3学习(六):使用socket实现TCP协议的简单服务器和客户端
-
【Socket网络通信】利用TCP/IP协议实现从服务端的文件中读取数据打印到客户端的控制台,服务端对客户端输入过来的数据做出响应...
-
基于TCP协议的socket编程实现简单聊天室——客户端多线程
-
Day.55————C++ socket编程实现简单的UDP、TCP通信(服务端+客户端)
-
【Socket网络通信】利用TCP/IP协议实现服务端与客户端的双向聊天
-
Socket TCP 协议实现服务端和客户端的简单通信
-
使用Qt中的tcp通信协议,构建客户端和服务端,实现聊天功能
-
使用 Java Socket 和 ServerSocket 实现客户端服务端通信的例子
-
Socket TCP 协议实现服务端和客户端的简单通信-结合线程池的使用