一.需求
需求如题. 当多个客户端连接服务器时,服务器如何给指定的客户端发送消息.
二.解决方案
核心思想: 在服务器端,需保存不同客户端的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 服务器向指定的客户端发消息,网上给的资源不多,大多是关于服务器群发. 这里给出了具体解决方案,并通过实例证实了该方案的可行性.
有时看的资料越多,越不明白.这并总是好事.
这个时候就需要静下来理理思路,然后针对具体的解决方案,编程实现.
实践才是检验真理的唯一标准,设计代码的时候你就离成功又近了一步.