1 回答
TA贡献1966条经验 获得超4个赞
开始考虑设计。在网络应用程序中,您通常必须管理以下职责:
已连接的客户端及其状态(连接状态、心跳……)
收到客户的消息
发送给客户端的消息
将这些职责分开以保持代码干净、可读和可维护是有意义的。
分离可以意味着线程和类。
例如,您可以按如下方式实现它:
该类ClientAcceptor负责打开套接字并接受客户端。一旦客户端连接,它将进一步的工作委托给控制器,然后等待其他客户端:
public class ClientAcceptor implements Runnable {
@Override
public void run() {
while (true) {
ServerSocket server;
try {
server = new ServerSocket(1992);
Socket client = server.accept();
if (client.isConnected()) {
controller.createClientHandler(client);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
然后控制器可以创建一个处理程序(如果控制器决定这样做,例如它也可以拒绝客户端)。本ClientHandler类可以如下所示:
public class ClientHandler {
private Thread receiveThread;
private Thread sendThread;
private boolean connected;
private Socket clientSocket;
private String clientName;
private LinkedBlockingDeque<byte[]> sendQueue;
public ClientHandler(String name, Socket s) {
clientSocket = s;
clientName = name;
receiveThread = new Thread(() -> receive());
sendThread = new Thread(() -> send());
connected = clientSocket.isConnected();
receiveThread.start();
sendThread.start();
}
private void receive() {
BufferedInputStream in = null;
try {
in = new BufferedInputStream(clientSocket.getInputStream());
} catch (IOException e) {
connected = false;
}
while (connected) {
try {
byte[] bytes = in.readAllBytes();
if (bytes != null && bytes.length > 0) {
controller.handleReceivedPacket(clientName, bytes);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
private void send() {
BufferedOutputStream out = null;
try {
out = new BufferedOutputStream(clientSocket.getOutputStream());
} catch (IOException e) {
connected = false;
}
while (connected) {
byte[] toSend = sendQueue.getFirst();
if (toSend != null && toSend.length > 0) {
try {
out.write(toSend);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public void send(byte[] packet) {
sendQueue.add(packet);
}
public void close() {
connected = false;
}
}
该ClientHandler负责接收和发射数据。如果数据包到达,它会通知控制器,控制器会解析数据包。的ClientHandler还提供了一个公共API来发送数据(其被存储在队列中,并通过一个线程来处理),并关闭连接。
上面的代码示例既未经测试,也不完整。以它为起点。
添加回答
举报
