具有大型客户端的TCP服务器将无法及时响应
本文关键字:响应 服务器 大型 客户端 TCP | 更新日期: 2023-09-27 18:16:13
我有服务器应用程序处理请求所有收到的命令从客户端,当我的客户端连接超过1000个后,当我的客户端连接超过1000个时,这个服务工作缓慢,并且在20秒内无法及时响应。20秒后,我的客户超时错误,我不想增加超时超过20秒…另外,如果我在单独的端口运行这个应用程序,每件事都可以在更多的客户端,我必须在一个应用程序中运行,我的错误在哪里?
static class Program {
static void Main(string[] args) {
TcpListener baseListernerNewVer = new TcpListener(new System.Net.IPEndPoint(IPAddress.Any, 1425));
baseListernerNewVer.Start();
BeginAccept(baseListernerNewVer);
while (true) {
System.Threading.Thread.Sleep(1);
}
}
}
//Wait For New Clinet
private static void BeginAccept(TcpListener baseListernerNewVer) {
baseListernerNewVer.BeginAcceptTcpClient((ar) => {
while (true) {
try {
BeginAccept(baseListernerNewVer);
break;
}
catch(Exception e) {
System.Threading.Thread.Sleep(100);
}
}
//All Client Will Manage Here
Manage(baseListernerNewVer.EndAcceptTcpClient(ar));
}, baseListernerNewVer);
}
public void Manage(TcpClient tcpClient) {
GC.Collect();
var onlineClientInfo = new OnlineClientInfo(tcpClient);
try {
lock (onlineClientsInfos) {
onlineClientsInfos.Add(onlineClientInfo);
}
System.Threading.ThreadPool.QueueUserWorkItem(new WaitCallback((object state) => {
System.Threading.Thread.Sleep(1000);
while (tcpClient.Connected && onlineClientInfo.IsConnect && service1.Running) {
try {
if (FeedMeMessage(onlineClientInfo)) {
System.Threading.Thread.Sleep(1000);
}
else {
System.Threading.Thread.Sleep(1000);
}
}
catch (Exception e) {
}
}
}));
//Wait from command form clients
CallGetNextCommand(onlineClientInfo);
}
catch (Exception e) {
}
finally {
}
}
private void DisconnectFromClient(OnlineClientInfo onlineClientInfo) {
lock (onlineClientsInfos) {
onlineClientsInfos.Remove(onlineClientInfo);
try {
onlineClientInfo.TcpClient.Close();
}
catch {
}
}
}
private void ReadNextSocketBuffer(OnlineClientInfo onlineClientInfo, DateTime baseDateAndTime, byte[] buffer, int offset, int length, Action fullBufferFilled) {
TcpClient tcpClient = onlineClientInfo.TcpClient;
try {
tcpClient.Client.BeginReceive(buffer, offset, length, SocketFlags.Partial, (ar) => {
int len = 0;
try {
len = tcpClient.Client.EndReceive(ar);
if (len == 0) {
if (DateTime.Now > baseDateAndTime.AddMinutes(1)) {
DisconnectFromClient(onlineClientInfo);
return;
}
System.Threading.Thread.Sleep(1);
}
}
catch {
DisconnectFromClient(onlineClientInfo);
}
if (offset + len == buffer.Length) {
fullBufferFilled();
}
else {
int newOffset = offset + len;
ReadNextSocketBuffer(onlineClientInfo, baseDateAndTime, buffer, newOffset, buffer.Length - newOffset, fullBufferFilled);
}
}, null);
}
catch {
DisconnectFromClient(onlineClientInfo);
}
}
private void ReadSocketLength(OnlineClientInfo onlineClientInfo, int length, Action<byte[]> readedToLength) {
byte[] buffer = new byte[length];
ReadNextSocketBuffer(onlineClientInfo, DateTime.Now, buffer, 0, length, () => {
try {
readedToLength(buffer);
}
catch { }
});
}
private void ReadCommandLength(OnlineClientInfo onlineClientInfo, Action<int> length) {
ReadSocketLength(onlineClientInfo, 4, (commandLength) => {
try {
length(Common.ToInt(commandLength));
}
catch { }
});
}
private void ReadCommand(OnlineClientInfo onlineClientInfo, int commandLength, Action<byte[]> commandResult) {
ReadSocketLength(onlineClientInfo, commandLength, (command) => {
try {
commandResult(command);
}
catch { }
});
}
private void GetNextCommand(OnlineClientInfo onlineClientInfo, Action finishedExecute) {
ReadCommandLength(onlineClientInfo, (commandLength) => {
ReadCommand(onlineClientInfo, 1, (commandHeader) => {
if (commandLength == 2 && (ServerCommandType)commandHeader[0] == ServerCommandType.AckVer1) {
ReadCommand(onlineClientInfo, 1, (newCommandHeader) => {
try {
byte ackCode = newCommandHeader[0];
onlineClientInfo.AckReceived(ackCode);
}
catch { }
finishedExecute();
});
}
else {
ReadCommand(onlineClientInfo, commandLength, (command) => {
try {
if (ExecuteCommand(command, onlineClientInfo)) {
onlineClientInfo.SendAck(commandHeader[0]);
}
}
catch {
}
finishedExecute();
});
}
});
});
}
private void CallGetNextCommand(OnlineClientInfo onlineClientInfo) {
TcpClient tcpClient = onlineClientInfo.TcpClient;
Action finishedExecute = null;
finishedExecute = () => {
if (tcpClient.Connected && onlineClientInfo.IsConnect) {
try {
GetNextCommand(onlineClientInfo, finishedExecute);
}
catch {
}
}
else {
DisconnectFromClient(onlineClientInfo);
}
};
finishedExecute();
}
这段代码非常令人困惑。错误之多,我无法一一列举。大多数错误源于您以复杂和错误的方式使用异步IO的事实。这是可以理解的,因为网络上大多数关于TCP的教程都很糟糕。要么使用await,要么尝试使用同步IO并首先使其工作。会很难。
话虽如此,以下是我最注意到的:
while (true) {
try {
BeginAccept(baseListernerNewVer);
break;
}
catch(Exception e) {
System.Threading.Thread.Sleep(100);
}
}
开始在无限循环中接受操作。这意味着您的CPU处于100%的启动接受状态。事实上,每接受一个套接字,你就开始另一个这样的循环…
有一个accept循环:
while (true) {
var socket = Accept();
new Thread(() => HandleClient(socket)).Start(); //Or, go async with this
}
非常简单。
Async IO在这里没有给你买任何东西。指定一个线程来接受连接是完全可以的。
使用错误的API。监听器不是高度可伸缩的。您应该使用套接字并使用SELECT方法来选择有数据等待的(http://msdn.microsoft.com/en-us/library/system.net.sockets.socket.select(v=vs.110).aspx)