Socket TCP 协议实现服务端和客户端的简单通信-结合线程池的使用

版权声明:本文为博主原创文章,如有错误劳烦指正。转载请声明出处,便于读取最新内容。——Bestcxx https://blog.csdn.net/bestcxx/article/details/83445002

前言

没啥说的,就是记录一下代码,方便以后查看
对了,本篇客户端逻辑中有一个制造慢服务的 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月

猜你喜欢

转载自blog.csdn.net/bestcxx/article/details/83445002