一.需求
需求如題. 當多個客戶端連接服務器時,服務器如何給指定的客戶端發送消息.
二.解決方案
核心思想: 在服務器端,需保存不同客戶端的socket列表及客戶端相關信息.
socket含有發送方和接收方的ip和端口號,所以通過socket就能向指定的客戶端發送消息.
經查閱資料,得到如下解決方案:
用戶連接時,立即向服務器發送自己的唯一ID,服務器端將ID和對應的socket用map存儲. 向客戶端發送消息時,就可以通過ID,找到對應的socket,然后向其發送消息.
如果客戶端ip固定,服務器每收到一個Socket都用Map
三.實踐
說明:采用第一種解決方案,模擬服務器向指定的客戶端發送消息.
服務端循環監聽,第一個服務器進來,向其發送其自身序號,第二個進來,遍歷socke列表,向列表中的每一個客戶端發送其對應的序號,從而達到服務器向指定客戶端發送消息的功能.
服務器端
package server; import java.io.*; import java.net.*; import java.util.HashMap; /** * 主函數,實現服務器向指定客戶端發送消息的功能. * 客戶端用python書寫 * @author dingding * */ public class Run { private final static int PORT = 30000; public static HashMap<String, Socket> socketList = new HashMap<>(); public static String channelToken; //socket 令牌 private static BufferedReader bufferedReader; public static void main(String[] args) { try { ServerSocket server = new ServerSocket(PORT); System.out.println("server is listenning..."); while(true){//不斷循環隨時等待新的客戶端接入服務器 Socket clientSocket = server.accept(); bufferedReader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); channelToken = bufferedReader.readLine(); socketList.put(channelToken,clientSocket); //保存會話ID和socket //System.out.println(socketList.get(channelToken)); //System.out.println(socketList); new ServerThread(clientSocket,socketList); } } catch (IOException e) { e.printStackTrace(); } } }
package server; import java.io.*; import java.net.*; import java.util.*; public class ServerThread extends Thread{ private Socket client; private PrintWriter out; private HashMap<String, Socket> clientList = new HashMap<>(); public ServerThread(Socket socket,HashMap<String, Socket> socketList) throws IOException{ super(); client = socket; clientList = socketList; start(); } @Override public void run(){ Socket socket; System.out.println("Client: "+getName()+" come in..."); //每當客戶端連接上,就向相應的客戶端進行回應 Iterator<HashMap.Entry<String, Socket>> entries = clientList.entrySet().iterator(); while (entries.hasNext()){ HashMap.Entry<String, Socket> entry = entries.next(); System.out.println(entry.getKey()); if (!String.valueOf(entry.getKey()).equals("")) { System.out.println(entry.getValue()); System.out.println("-------------"); socket = entry.getValue(); if (socket!=null) { try { out = new PrintWriter(socket.getOutputStream()); //回復client的ID out.println(entry.getKey()); out.flush(); } catch (IOException e) { e.printStackTrace(); } } } } } }
兩個客戶端
用兩個python客戶端來模擬場景.
#coding = utf-8 import socket import threading HOST = "localhost" PORT = 30000 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect((HOST, PORT)) def test(): socketID = 'I am 111' sock.sendall((socketID+'\r').encode()) while True: data = sock.recv(1024).decode() print('from line: '+data) sock.close() if __name__ == '__main__': test()
#coding = utf-8 import socket import threading HOST = "localhost" PORT = 30000 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect((HOST, PORT)) def test(): socketID = 'I am 000' sock.sendall((socketID+'\r').encode()) while True: data = sock.recv(1024).decode() print('from line: '+data) sock.close() if __name__ == '__main__': test()
四.總結
socket 服務器向指定的客戶端發消息,網上給的資源不多,大多是關於服務器群發. 這里給出了具體解決方案,並通過實例證實了該方案的可行性.
有時看的資料越多,越不明白.這並總是好事.
這個時候就需要靜下來理理思路,然后針對具體的解決方案,編程實現.
實踐才是檢驗真理的唯一標准,設計代碼的時候你就離成功又近了一步.
參考文獻
---------------------
作者:Deen12520
來源:CSDN
原文:https://blog.csdn.net/dingding_12345/article/details/72790839
版權聲明:本文為博主原創文章,轉載請附上博文鏈接!