之前介绍了 socket基础编程Java面试知识点(七十)Socket编程——C/S架构基础入门 ,包括单客户端和多客户端的情况,现在在说一下其他情况
简易聊天室
跟之前的多客户端的情况一样,也是需要多线程来保持多个连接,但是额外要引入一个线程池,需要服务器记录所有的连接客户端,这样一个客户端发送信息之后,就可以把这个信息发送给其他保持连接的客户端,代码如下:
【子线程服务类】
package test.socket.chatroom;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Map;
/**
* 单一服务器线程类
* 可以实现跟与当前线程服务器的连接的客户端的信息通讯
* 同时还保存着当前服务器的全部连接的线程,以便实现发送给其他客户端信息
* */
public class SingleServer implements Runnable {
// 创建线程连接池,存储线程名和线程
private Map<String,Socket> pool;
// 创建socket
private Socket socket;
private String name;
public SingleServer(Map<String,Socket> pool, String name,Socket socket) {
this.pool = pool;
this.socket = socket;
this.name = name;
// 将socket线程加入线程池中
this.pool.put(this.name,this.socket);
}
@Override
public void run() {
read();
}
// 获取当前线程的客户端的信息
private void read() {
try {
boolean flag = true;
while (flag) {
BufferedReader reader =
new BufferedReader(new InputStreamReader(socket.getInputStream()));
if (reader.ready()) {
String str = reader.readLine();
// 服务器获得之后可以保存在本地当做日志,这里简单打印
System.out.println(name+"客户端: "+str);
// 把接收到的信息发送给其他客户端并打印
Iterator it = pool.keySet().iterator();
while (it.hasNext()) {
String key = (String)it.next();
if (this.socket != pool.get(key)) {
write(pool.get(key),name+"客户端: "+str);
}
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 把信息发送到客户端
* */
private void write(Socket socket, String str) {
try {
PrintWriter writer
= new PrintWriter(socket.getOutputStream(),true);
writer.println(str);
} catch (IOException e) {
e.printStackTrace();
}
}
}
【服务器类】
package test.socket.chatroom;
import test.test.thread1;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
public class Server {
public static void main(String[] args) {
try {
// 监听端口
ServerSocket server = new ServerSocket(9999);
// 线程池
Map<String, Socket> pool = new HashMap<>();
System.out.println("服务器启动...");
int i = 0;
// 循环侦听
while (true) {
// 客户端id
i++;
String id = i+ "";
// 开启线程
SingleServer singleServer = new SingleServer(pool,id,server.accept());
Thread thread = new Thread(singleServer);
thread.start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
【客户端类】
package test.socket.chatroom;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
public class Client {
public static void main(String[] args) {
// 建立连接
try {
Socket socket = new Socket("localhost",9999);
System.out.println("客户端启动");
while (true) {
// 读取信息
BufferedReader reader
= new BufferedReader(new InputStreamReader(socket.getInputStream()));
if (reader.ready()) {
String str = reader.readLine();
System.out.println(str);
}
// 写信息
PrintWriter writer =
new PrintWriter(socket.getOutputStream(),true);
BufferedReader key =
new BufferedReader(new InputStreamReader(System.in));
if (key.ready()) {
String str = key.readLine();
writer.println(str);
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
【运行结果】
后期还可以加上发送时间,左右分区,加上身份验证等等
还有一些问题,服务器无法发送给全部客户端信息
待续…