文章目录
- TCP连接池
- 客户端
- 服务端
TCP连接池
设计
- 用
ConcurrentHashMap<Integer, Socket>
作为连接池 - 声明连接池的数量、端口和ip、TCP连接的状态(boolean数组)
- 初始化连接池
- 使用Socket只需要找到状态是未连接的即可
- 使用之后将此时连接状态设为未连接
package com.ossa.issavior.socket;import java.net.Socket;
import java.util.concurrent.ConcurrentHashMap;/*** TCP连接池的实现*/
public class SocketBuild {/*** 连接池数量*/private static final int CONNECTION_POOL_SIZE = 10;/*** ip*/private static final String API_SERVER_HOST = "127.0.0.1";/*** 端口*/private static final int API_SERVER_PORT = 8989;private static SocketBuild self = null;/*** 连接池*/private ConcurrentHashMap<Integer, Socket> socketPool = null;/*** 连接的状态(true-被占用,false-空闲)*/private boolean[] socketStatusArray = null;/*** 初始化连接池,最大TCP连接的数量为10*/private static synchronized void init() {self = new SocketBuild();self.socketPool = new ConcurrentHashMap<>();// 初始化连接数量self.socketStatusArray = new boolean[CONNECTION_POOL_SIZE];//初始化连接池System.out.println("初始化连接池.");buildConnectionPool();}/*** 建立连接池*/private synchronized static void buildConnectionPool() {if (self == null)init();System.out.println("准备建立连接池.");Socket socket;try {for (int i = 0; i < CONNECTION_POOL_SIZE; i++) {socket = new Socket(API_SERVER_HOST, API_SERVER_PORT);self.socketPool.put(i, socket);self.socketStatusArray[i] = false;}} catch (Exception e) {System.out.println("连接池建立失败!");throw new RuntimeException(e); }System.out.println("连接池建立成功.");}/*** 从连接池中获取一个空闲的Socket** @return 获取的TCP连接*/public static Socket buildConnection() {if (self == null)init();int i;for (i = 0; i < CONNECTION_POOL_SIZE; i++) {if (!self.socketStatusArray[i]) {self.socketStatusArray[i] = true;break;}}if (i <= CONNECTION_POOL_SIZE) {System.out.println("连接池中的第" + i + "个连接");return self.socketPool.get(i);} else {System.out.println("从连接池建立连接失败,没有空闲的连接");throw new RuntimeException("No enough pooled connection");}}/*** 当获得的socket不可用时,重新获得一个空闲的socket。** @param socket 不可用的socket*/public static void rebuildConnection(Socket socket) {if (self == null)init();Socket newSocket = null;try {for (int i = 0; i < CONNECTION_POOL_SIZE; i++) {if (self.socketPool.get(i) == socket) {System.out.println("重建连接池中的第" + i + "个连接");newSocket = new Socket(API_SERVER_HOST, API_SERVER_PORT);self.socketPool.put(i, newSocket);self.socketStatusArray[i] = true;}}} catch (Exception e) {System.out.println("重建连接失败!");throw new RuntimeException(e);}}/*** 将用完的socket放回池中,调整为空闲状态。此时连接并没有断开。** @param socket 使用完的socket*/public static void releaseConnection(Socket socket) {if (self == null) {init();}for (int i = 0; i < CONNECTION_POOL_SIZE; i++) {if (self.socketPool.get(i) == socket) {self.socketStatusArray[i] = false;System.out.println("释放连接 " + i);break;}}}/*** 断开池中所有连接*/public synchronized static void releaseAllConnection() {if (self == null)init();//关闭所有连接Socket socket;for (int i = 0; i < CONNECTION_POOL_SIZE; i++) {socket = self.socketPool.get(i);try {socket.close();self.socketStatusArray[i] = false;} catch (Exception e) {e.printStackTrace();}}System.out.println("全部连接已经关闭。");}/*** 重新建立连接池。*/public static void reset() {self = null;System.out.println("重建连接池...");init();}
}
客户端
设计
- 主线程负责从控制台获取内容(死循环),发送给服务端
- 子线程负责获取服务端发送的数据
package com.ossa.issavior.socket;import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class 康宝 {private final ExecutorService executorService = Executors.newCachedThreadPool();public static void main(String[] args) {康宝 client=new 康宝();client.startAction();}public void startAction(){Socket socket=null;BufferedReader reader=null;BufferedWriter writer=null;BufferedReader reader2=null;try {socket = SocketBuild.buildConnection();reader = new BufferedReader(new InputStreamReader(System.in));reader2=new BufferedReader(new InputStreamReader(socket.getInputStream()));writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));readSocketInfo(reader2);String lineString="";while(!(lineString=reader.readLine()).equals("exit")){writer.write(lineString+"\n");writer.flush();}} catch (Exception e) {e.printStackTrace();} finally {try {if (reader!=null) {reader.close();}if (writer!=null) {writer.close();}if (socket!=null) {SocketBuild.rebuildConnection(socket);}} catch (Exception e2) {e2.printStackTrace();}}}void readSocketInfo(BufferedReader reader){executorService.submit(()->{try {String lineString="";while( (lineString = reader.readLine())!=null ){System.out.println(lineString);}} catch (Exception e) {e.printStackTrace();}});}
}
服务端
- 通过死循环开启长连接,开启线程去处理消息
package com.ossa.issavior.socket;import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;public class 桐哥 {private final ExecutorService executorService = Executors.newCachedThreadPool();public static void main(String[] args) {桐哥 socketServer = new 桐哥();socketServer.startAction();}private final static Logger LOGGER = LoggerFactory.getLogger(桐哥.class);public void startAction() {ServerSocket serverSocket = null;try {serverSocket = new ServerSocket(8989); //端口号//通过死循环开启长连接,开启线程去处理消息while (true) {Socket socket = serverSocket.accept();executorService.submit(() -> {BufferedReader reader = null;BufferedReader readerIn = null;BufferedWriter writer = null;try {reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));//读取客户端消息readerIn = new BufferedReader(new InputStreamReader(System.in));//读取客户端消息writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));//向客户端写消息String lineString = "";while (!(lineString = reader.readLine()).equals("bye")) {LOGGER.info("康宝发来消息:" + lineString);writer.write("桐哥发来消息:" + readerIn.readLine() + "\n");writer.flush();}} catch (Exception e) {e.printStackTrace();} finally {try {if (reader != null) {reader.close();}if (writer != null) {writer.close();}if (socket != null) {socket.close();}} catch (Exception e2) {e2.printStackTrace();}}});}} catch (Exception e) {e.printStackTrace();} finally {try {if (serverSocket != null) {serverSocket.close();}} catch (Exception e2) {e2.printStackTrace();}}}}
简易版演示: