Java通過(guò) Socket 實(shí)現(xiàn) TCP服務(wù)端
1 Java Socket簡(jiǎn)介
所謂socket 通常也稱作”套接字“,用于描述IP地址和端口,是一個(gè)通信鏈的句柄。應(yīng)用程序通常通過(guò)”套接字”向網(wǎng)絡(luò)發(fā)出請(qǐng)求或者應(yīng)答網(wǎng)絡(luò)請(qǐng)求。Socket和ServerSocket類庫(kù)位于Java.NET包中。ServerSocket用于服務(wù)器端,Socket是建立網(wǎng)絡(luò)連接時(shí)使用的。在連接成功時(shí),應(yīng)用程序兩端都會(huì)產(chǎn)生一個(gè)Socket實(shí)例,操作這個(gè)實(shí)例,完成所需的會(huì)話。對(duì)于一個(gè)網(wǎng)絡(luò)連接來(lái)說(shuō),套接字是平等的,并沒(méi)有差別,不因?yàn)樵诜?wù)器端或在客戶端而產(chǎn)生不同級(jí)別。
2 TCPServer代碼實(shí)例
import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket; import java.util.Date; import java.util.HashMap; import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * TCP服務(wù)器端,單例模式 * @author xiang * */ public class TCPServer implements Runnable { private static final Logger logger = LoggerFactory.getLogger(TCPServer.class); //成員變量/ private static TCPServer serverInstance; private static Map<String, SocketThread> socketMaps = new HashMap<String,SocketThread>(); //每個(gè)客戶端連接時(shí)都會(huì)新建一個(gè)SocketThread與之對(duì)應(yīng) private static ServerSocket serverSocket; //服務(wù)器套接字 private static int serPort = 9999; //服務(wù)器端口號(hào) private static boolean flag; //服務(wù)器狀態(tài)標(biāo)志 private static final int BUFFER_SIZE = 512; //數(shù)據(jù)接收字符數(shù)組大小 //構(gòu)造函數(shù)/ private TCPServer() { } /** * 獲取實(shí)例 * @return TCPServer實(shí)例serverInstance */ public static TCPServer getServerInstance(){ if(serverInstance==null) serverInstance = new TCPServer(); return serverInstance; } /** * 開(kāi)啟服務(wù)器 * @throws IOException */ public void openTCPServer() throws IOException{ if(serverSocket==null || serverSocket.isClosed()){ serverSocket = new ServerSocket(serPort); flag = true; } } /** * 關(guān)閉服務(wù)器 * @throws IOException */ public void closeTCPServer() throws IOException{ flag = false; if(serverSocket!=null) serverSocket.close(); /*for (Map.Entry<String, SocketThread> entry : socketMaps.entrySet()) { System.out.println("Key = " + entry.getKey() + ", Value = " + entry.getValue()); } */ for (SocketThread value : socketMaps.values()) value.closeConnect(); socketMaps.clear(); } /** * 服務(wù)器向客戶端發(fā)送數(shù)據(jù) * @param bytes[]:待發(fā)送的字符數(shù)組 * @param key 客戶端的key,為空或""時(shí)表示數(shù)據(jù)群發(fā) * @throws IOException */ public void sendMessage(String key,byte[] msgBytes){ if(key==null||key.equals("")){ for (SocketThread value : socketMaps.values()) value.sendMassage(msgBytes); }else{ SocketThread thread = socketMaps.get(key); if(thread!=null) thread.sendMassage(msgBytes); } } /** * 服務(wù)器向客戶端發(fā)送數(shù)據(jù) * @param key 客戶端的key,為空或""時(shí)表示數(shù)據(jù)群發(fā) * @param msgStr:待發(fā)送的字符串 * @throws IOException */ public void sendMessage(String key,String msgStr){ byte[] sendByte = msgStr.getBytes(); if(key==null||key.equals("")){ for (SocketThread value : socketMaps.values()) value.sendMassage(sendByte); }else{ SocketThread thread = socketMaps.get(key); if(thread!=null) thread.sendMassage(sendByte); } } @Override public void run() { logger.info("服務(wù)器線程已經(jīng)啟動(dòng)"); while(true){ try { while(flag){ logger.info("服務(wù)器線程在監(jiān)聽(tīng)狀態(tài)中"); Socket socket = serverSocket.accept(); String key = socket.getRemoteSocketAddress().toString(); SocketThread thread = new SocketThread(socket,key); thread.start(); socketMaps.put(key, thread); logger.info("有客戶端連接:"+key); } } catch (Exception e) { e.printStackTrace(); } } } /** * 處理連接后的數(shù)據(jù)接收請(qǐng)求內(nèi)部類 * @author xiang * */ private class SocketThread extends Thread{ private Socket socket; private String key; private OutputStream out; private InputStream in; //構(gòu)造函數(shù) public SocketThread(Socket socket,String key) { this.socket = socket; this.key = key; } /** * 發(fā)送數(shù)據(jù) * @param bytes * @throws IOException */ public void sendMassage(byte[] bytes){ try { if(out==null) out = socket.getOutputStream(); out.write(bytes); } catch (Exception e) { e.printStackTrace(); try { closeConnect(); } catch (IOException e1) { e1.printStackTrace(); } socketMaps.remove(key); } } /** * 關(guān)閉連接,釋放資源 * @throws IOException */ public void closeConnect() throws IOException{ if(out!=null) out.close(); if(in!=null) in.close(); if(socket!=null && socket.isConnected()) socket.close(); } @Override public void run() { byte[] receivBuf = new byte[BUFFER_SIZE]; int recvMsgSize; try { in = socket.getInputStream(); out = socket.getOutputStream(); while ((recvMsgSize = in.read(receivBuf)) != -1) { String receivedData = new String(receivBuf, 0, recvMsgSize); System.out.println("Reverve form[port" + socket.getPort() + "]:" + receivedData); System.out.println("Now the size of socketMaps is" + socketMaps.size()); /************************************************************** * * 接收數(shù)據(jù)后的處理過(guò)程 * **************************************************************/ } // response to client byte[] sendByte = "The Server has received".getBytes(); // out.write(sendByte, 0, sendByte.length); out.write(sendByte); System.out.println("To Cliect[port:" + socket.getPort() + "] 回復(fù)客戶端的消息發(fā)送成功"); closeConnect(); socketMaps.remove(key); } catch (Exception e) { e.printStackTrace(); try { closeConnect(); } catch (IOException e1) { e1.printStackTrace(); } } } ////////////// public int getport(){ return socket.getPort(); } } //. end SocketThread }
感謝閱讀,希望能幫助到大家,謝謝大家對(duì)本站的支持!
- 實(shí)現(xiàn)了基于TCP的Java Socket編程實(shí)例代碼
- Java實(shí)現(xiàn)Socket的TCP傳輸實(shí)例
- java實(shí)現(xiàn)一個(gè)簡(jiǎn)單TCPSocket聊天室功能分享
- Java基于Tcp協(xié)議的socket編程實(shí)例
- java實(shí)現(xiàn)基于Tcp的socket聊天程序
- java實(shí)現(xiàn)基于UDP協(xié)議網(wǎng)絡(luò)Socket編程(C/S通信)
- java Socket UDP實(shí)例詳解
- Java基于socket服務(wù)實(shí)現(xiàn)UDP協(xié)議的方法
- java實(shí)現(xiàn)TCP socket和UDP socket的實(shí)例
相關(guān)文章
SpringCloud Alibaba微服務(wù)實(shí)戰(zhàn)之遠(yuǎn)程Feign請(qǐng)求頭丟失問(wèn)題解決方案
這篇文章主要介紹了SpringCloud Alibaba微服務(wù)實(shí)戰(zhàn)之遠(yuǎn)程Feign請(qǐng)求頭丟失問(wèn)題,對(duì)SpringCloud Alibaba Feign請(qǐng)求頭問(wèn)題感興趣的朋友跟隨小編一起看看吧2024-02-02SpringData Repository Bean方法定義規(guī)范代碼實(shí)例
這篇文章主要介紹了SpringData Repository Bean方法定義規(guī)范代碼實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-08-08MySQL實(shí)現(xiàn)遠(yuǎn)程登錄的方法
Host 'Local' is not allowed to connect to this MySQL server 的解決方法,需要的朋友可以參考一下2013-03-03springboot打包實(shí)現(xiàn)項(xiàng)目JAR包和依賴JAR包分離
這篇文章主要介紹了springboot打包實(shí)現(xiàn)項(xiàng)目JAR包和依賴JAR包分離,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-02-02解析springboot整合谷歌開(kāi)源緩存框架Guava Cache原理
本文主要為大家解析了springboot整合谷歌開(kāi)源緩存框架Guava Cache的原理以及在實(shí)際開(kāi)發(fā)過(guò)程中的使用,附含源碼,有需要的朋友可以參考下2021-08-08IDEA中thymeleaf語(yǔ)法沒(méi)有提示的問(wèn)題及解決
這篇文章主要介紹了IDEA中thymeleaf語(yǔ)法沒(méi)有提示的問(wèn)題及解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-05-05SpringBoot中自定義注解實(shí)現(xiàn)參數(shù)非空校驗(yàn)的示例
這篇文章主要介紹了SpringBoot中自定義注解實(shí)現(xiàn)參數(shù)非空校驗(yàn),幫助大家更好的理解和使用springboot框架,感興趣的朋友可以了解下2020-11-11