设计思路
- 即时通信, 是指一个客户端的消息发出去, 其他客户端可以接收到
- 即时通信需要进行端口转发的设计思想
- 服务端需要把在线的Socket管道存储起来
- 一旦收到一个消息要推送给其他管道
代码实现
客户端
public class ClientDemo {
public static void main(String[] args) throws IOException {
/**
* 创建Socket通信管道请求有服务端的连接
* 参数一:服务端的IP地址
* 参数二:服务端的端口
*/
Socket socket = new Socket("127.0.0.1",9999);
//创建一个独立的线程专门负责这个客户端的读消息(服务端随时可能转发消息过来)
new ClientReaderThread(socket).start();
//从socket通信管道中得到一个字节输出流,负责发送数据
OutputStream os = socket.getOutputStream();
//把字节流包装成打印流
PrintStream ps = new PrintStream(os);
Scanner sc = new Scanner(System.in);
while (true){
System.out.println("请说:");
String msg = sc.nextLine();
ps.println(msg);
ps.flush();
}
}
}
class ClientReaderThread extends Thread{
private Socket socket;
public ClientReaderThread(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try{
//从socket通信管道中得到一个字节输入流
InputStream is = socket.getInputStream();
//把字节输入流包装成缓冲字符输入流接收消息
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String line;
while ((line = br.readLine()) != null) {
System.out.println("收到消息: " + line);
}
} catch (Exception e){
System.out.println("服务端不转发你的消息了,关闭了通信管道");
}
}
}
服务端
public class ServerDemo {
//定义一个静态的List集合存储当前全部在线的socket管道
public static List<Socket> allOnlineSocket = new ArrayList<>();
public static void main(String[] args) throws IOException {
//注册端口
ServerSocket serverSocket = new ServerSocket(9999);
while (true) {
//每接收到一个客户端的Socket管道,交给一个独立的子线程负责读取信息
Socket socket = serverSocket.accept();
System.out.println(socket.getRemoteSocketAddress() + "上线了");
allOnlineSocket.add(socket);
new ServerReaderThread(socket).start();
}
}
}
class ServerReaderThread extends Thread {
private Socket socket;
public ServerReaderThread(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try {
//从socket通信管道中得到一个字节输入流
InputStream is = socket.getInputStream();
//把字节输入流包装成缓冲字符输入流接收消息
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String line;
while ((line = br.readLine()) != null) {
System.out.println(socket.getRemoteSocketAddress() + "发来了" + line);
//把这个消息进行端口转发给全部客户端socket管道
sendMsgToALL(line, socket);
}
} catch (Exception e) {
System.out.println(socket.getRemoteSocketAddress() + "下线了");
ServerDemo.allOnlineSocket.remove(socket);
}
}
private void sendMsgToALL(String msg, Socket socket) throws IOException {
for (Socket s : ServerDemo.allOnlineSocket) {
if (s != socket) {
PrintStream ps = new PrintStream(s.getOutputStream());
ps.println(msg);
ps.flush();
}
}
}
}