Contents
  1. 1. 一.需求
  2. 2. 二.解决方案
  3. 3. 三.实践
  4. 4. 四.总结
  5. 5. 参考文献

一.需求

需求如题. 当多个客户端连接服务器时,服务器如何给指定的客户端发送消息.

二.解决方案

核心思想: 在服务器端,需保存不同客户端的socket列表及客户端相关信息.
socket含有发送方和接收方的ip和端口号,所以通过socket就能向指定的客户端发送消息.

经查阅资料,得到如下解决方案:

  1. 用户连接时,立即向服务器发送自己的唯一ID,服务器端将ID和对应的socket用map存储. 向客户端发送消息时,就可以通过ID,找到对应的socket,然后向其发送消息.
  2. 如果客户端ip固定,服务器每收到一个Socket都用Map存起来.

三.实践

说明:采用第一种解决方案,模拟服务器向指定的客户端发送消息.

服务端循环监听,第一个服务器进来,向其发送其自身序号,第二个进来,遍历socke列表,向列表中的每一个客户端发送其对应的序号,从而达到服务器向指定客户端发送消息的功能.
服务器端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
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();
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
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客户端来模拟场景.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#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()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#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 服务器向指定的客户端发消息,网上给的资源不多,大多是关于服务器群发. 这里给出了具体解决方案,并通过实例证实了该方案的可行性.

有时看的资料越多,越不明白.这并总是好事.
这个时候就需要静下来理理思路,然后针对具体的解决方案,编程实现.
实践才是检验真理的唯一标准,设计代码的时候你就离成功又近了一步.

参考文献

  1. java socket编程中,如何让服务器主动向指定ip地址的客户端发送信息
  2. socket 服务器给指定的客户端发消息该怎么处理
  3. socket 服务器给指定的客户端发消息该怎么处理
comments powered by HyperComments
Contents
  1. 1. 一.需求
  2. 2. 二.解决方案
  3. 3. 三.实践
  4. 4. 四.总结
  5. 5. 参考文献
Fork me on GitHub