服务端
- 在server包下创建ChatServer.java,该类用监听有没有任何的客户端发起建立连接的要求,如果有的话接收连接的要求并接收任意用户发来的消息转发给在线的所有用户
public class ChatServer {
//端口号
private int DEFAULT_PORT = 8888;
//用户输入quit时退出聊天
private final String QUIT = "quit";
//线程池
private ExecutorService executorService;
//接收各个客户端发送的连接请求
private ServerSocket serverSocket;
//保存目前为止所有客户发送的消息。
// key:客户端的端口号 value:服务端向对应的客户端发送信息时的writer
private Map<Integer, Writer> connectedClients;
//初始化参数
public ChatServer() {
//创建含10个线程的线程池
executorService = Executors.newFixedThreadPool(10);
connectedClients = new HashMap<>();
}
/**
* 接收客户端的socket,建立客户端与服务端的连接
* 使用synchronized ,确保同一时间内只有一个线程来调用该函数
* (防止多个函数同时调用更改Map集合,确保线程安全)下面几个函数也是要使用synchronized
* @param socket
*/
public synchronized void addClient(Socket socket) throws IOException {
//判断该socket是可以进行操作的值
if (socket!=null){
int port = socket.getPort();//Key
BufferedWriter writer = new BufferedWriter(
new OutputStreamWriter(socket.getOutputStream())
);//Value
//将key,value写入Map中
connectedClients.put(port,writer);
System.out.println("客户端["+port+"]已经连接到服务器");
}
}
/**
* 断开指定客户端与服务器的连接
* @param socket
*/
public synchronized void removeClient(Socket socket) throws IOException {
if (socket!=null){
int port = socket.getPort();
//先判断当前客户端有没有在map中(之前有没有与客户端建立连接)
if (connectedClients.containsKey(port)){
//如果在,直接将writer流关闭
connectedClients.get(port).close();
}
//并将对应的值从map中去除
connectedClients.remove(port);
System.out.println("客户端["+port+"]断开连接");
}
}
/**
* 当服务器接收到某一客户发送够