hnu202326010206 2 months ago
parent 555e70e198
commit bd19628cd7

@ -3,6 +3,7 @@ package server;
import com.google.gson.Gson;
import java.io.*;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
@ -30,8 +31,6 @@ public class WebSocketClient implements Runnable {
socket.setSendBufferSize(1024 * 1024); // 1MB
socket.setReceiveBufferSize(1024 * 1024); // 1MB
socket.setTcpNoDelay(true); // 禁用Nagle算法提高实时性
// 设置超时时间
socket.setSoTimeout(30000); // 30秒超时
} catch (Exception e) {
System.err.println("设置Socket参数失败: " + e.getMessage());
}
@ -104,10 +103,7 @@ public class WebSocketClient implements Runnable {
boolean fin = (b & 0x80) != 0;
int opcode = b & 0x0F;
// 调试信息
if (opcode != 0) { // 非继续帧才打印
System.out.println("读取帧: FIN=" + fin + ", opcode=" + opcode);
}
System.out.println("读取帧: FIN=" + fin + ", opcode=" + opcode);
// 处理控制帧
if (opcode == 8) { // Close frame
@ -293,11 +289,6 @@ public class WebSocketClient implements Runnable {
// 转发消息
server.forwardMediaMessage(message);
System.out.println("消息已转发");
} else if ("PING".equals(type)) {
// 心跳包响应
Map<String, Object> response = new HashMap<>();
response.put("type", "PONG");
sendMessage(gson.toJson(response));
}
} catch (com.google.gson.JsonSyntaxException e) {
System.err.println("JSON 解析失败: " + e.getMessage());
@ -325,10 +316,9 @@ public class WebSocketClient implements Runnable {
sendFrame(payload, 0, payloadLength, true);
} else {
// 大消息,分片发送
System.out.println("消息过大,分片发送,总大小: " + payloadLength + " 字节");
System.out.println("消息过大,分片发送");
int offset = 0;
int fragmentCount = 0;
long startTime = System.currentTimeMillis();
while (offset < payloadLength) {
int length = Math.min(maxFrameSize, payloadLength - offset);
@ -338,26 +328,12 @@ public class WebSocketClient implements Runnable {
offset += length;
fragmentCount++;
// 每发送5个片段暂停一下避免接收端处理不过来
if (fragmentCount % 5 == 0 && offset < payloadLength) {
try {
Thread.sleep(10); // 10毫秒延迟
} catch (InterruptedException e) {
// 恢复中断状态
Thread.currentThread().interrupt();
}
}
// 每发送20个片段打印进度
if (fragmentCount % 20 == 0 || offset >= payloadLength) {
System.out.println("已发送: " + offset + "/" + payloadLength + " 字节 (" +
String.format("%.1f", (offset * 100.0 / payloadLength)) + "%)");
if (fragmentCount % 10 == 0) {
System.out.println("已发送: " + offset + "/" + payloadLength + " 字节");
}
}
long endTime = System.currentTimeMillis();
System.out.println("分片发送完成,共 " + fragmentCount + " 个片段,耗时 " +
(endTime - startTime) + " 毫秒");
System.out.println("分片发送完成,共 " + fragmentCount + " 个片段");
}
} catch (IOException e) {
@ -392,9 +368,14 @@ public class WebSocketClient implements Runnable {
frameHeader.write(length & 0xFF);
} else {
frameHeader.write(127);
for (int i = 7; i >= 0; i--) {
frameHeader.write((int)((length >> (i * 8)) & 0xFF));
}
frameHeader.write((int)((length >> 56) & 0xFF));
frameHeader.write((int)((length >> 48) & 0xFF));
frameHeader.write((int)((length >> 40) & 0xFF));
frameHeader.write((int)((length >> 32) & 0xFF));
frameHeader.write((int)((length >> 24) & 0xFF));
frameHeader.write((int)((length >> 16) & 0xFF));
frameHeader.write((int)((length >> 8) & 0xFF));
frameHeader.write((int)(length & 0xFF));
}
// 发送帧头
@ -420,13 +401,8 @@ public class WebSocketClient implements Runnable {
if (input != null) input.close();
if (output != null) output.close();
if (socket != null && !socket.isClosed()) socket.close();
System.out.println("客户端 " + username + " 资源已清理");
} catch (IOException e) {
System.err.println("清理资源失败: " + e.getMessage());
}
}
public String getUsername() {
return username;
}
}
}

@ -1,11 +1,14 @@
package server;
import common.Message;
import common.MessageType;
import java.io.*;
import java.net.*;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.*;
import java.util.concurrent.*;
import java.util.regex.*;
import com.google.gson.Gson;
/**
@ -29,7 +32,6 @@ public class WebSocketServer {
public void start() {
try {
serverSocket = new ServerSocket(PORT);
serverSocket.setReuseAddress(true);
running = true;
System.out.println("WebSocket服务器启动成功监听端口: " + PORT);
System.out.println("Web客户端访问地址: http://localhost:" + PORT);
@ -38,9 +40,6 @@ public class WebSocketServer {
// 检查web文件是否存在
checkWebFiles();
// 启动心跳检测线程
startHeartbeatCheck();
while (running) {
try {
Socket clientSocket = serverSocket.accept();
@ -57,42 +56,6 @@ public class WebSocketServer {
}
}
private void startHeartbeatCheck() {
Thread heartbeatThread = new Thread(() -> {
while (running) {
try {
Thread.sleep(30000); // 每30秒检查一次
Map<String, Object> pingMessage = new HashMap<>();
pingMessage.put("type", "PING");
pingMessage.put("timestamp", System.currentTimeMillis());
String pingJson = gson.toJson(pingMessage);
synchronized (this) {
List<String> deadClients = new ArrayList<>();
for (Map.Entry<String, WebSocketClient> entry : clients.entrySet()) {
try {
entry.getValue().sendMessage(pingJson);
} catch (Exception e) {
System.err.println("发送心跳包失败: " + entry.getKey() + ", " + e.getMessage());
deadClients.add(entry.getKey());
}
}
// 清理死亡的客户端
for (String username : deadClients) {
removeClient(username);
}
}
} catch (InterruptedException e) {
break;
}
}
});
heartbeatThread.setDaemon(true);
heartbeatThread.start();
}
private void handleClient(Socket socket) {
try {
BufferedReader reader = new BufferedReader(
@ -283,11 +246,9 @@ public class WebSocketServer {
}
public synchronized void removeClient(String username) {
WebSocketClient client = clients.remove(username);
if (client != null) {
System.out.println("用户 " + username + " 已离线,当前在线: " + clients.size());
broadcastUserList();
}
clients.remove(username);
System.out.println("用户 " + username + " 已离线,当前在线: " + clients.size());
broadcastUserList();
}
public void sendPrivateMessage(String sender, String receiver, String content) {
@ -331,10 +292,10 @@ public class WebSocketServer {
System.out.println("找到接收者客户端,准备发送");
String jsonMessage = gson.toJson(messageData);
int messageSize = jsonMessage.length();
System.out.println("消息大小: " + messageSize + " 字符 (" + formatSize(messageSize) + ")");
System.out.println("消息大小: " + messageSize + " 字符");
// 提高消息大小限制到5MB
if (messageSize > 5 * 1024 * 1024) { // 5MB
// 如果消息太大超过100KB建议压缩或分片
if (messageSize > 100000) {
System.out.println("警告:消息过大,可能导致传输问题");
// 发送错误消息给发送者
@ -347,27 +308,8 @@ public class WebSocketServer {
return;
}
try {
receiverClient.sendMessage(jsonMessage);
System.out.println("消息已发送到接收者");
// 发送成功确认给发送者
if (senderClient != null) {
Map<String, Object> ack = new HashMap<>();
ack.put("type", "SEND_SUCCESS");
ack.put("receiver", receiver);
ack.put("timestamp", System.currentTimeMillis());
senderClient.sendMessage(gson.toJson(ack));
}
} catch (Exception e) {
System.err.println("发送消息失败: " + e.getMessage());
if (senderClient != null) {
Map<String, Object> error = new HashMap<>();
error.put("type", "ERROR");
error.put("content", "发送失败: " + e.getMessage());
senderClient.sendMessage(gson.toJson(error));
}
}
receiverClient.sendMessage(jsonMessage);
System.out.println("消息已发送到接收者");
} else {
System.out.println("接收者不在线: " + receiver);
if (senderClient != null) {
@ -423,34 +365,12 @@ public class WebSocketServer {
System.out.println();
}
public void stop() {
running = false;
try {
if (serverSocket != null && !serverSocket.isClosed()) {
serverSocket.close();
}
} catch (IOException e) {
System.err.println("关闭服务器失败: " + e.getMessage());
}
threadPool.shutdown();
try {
if (!threadPool.awaitTermination(5, TimeUnit.SECONDS)) {
threadPool.shutdownNow();
}
} catch (InterruptedException e) {
threadPool.shutdownNow();
}
System.out.println("服务器已停止");
}
public static void main(String[] args) {
WebSocketServer server = new WebSocketServer();
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
System.out.println("\n正在关闭服务器...");
server.stop();
}));
server.start();
}
}
}

Loading…
Cancel
Save