具有大型客户端的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();
}

具有大型客户端的TCP服务器将无法及时响应

这段代码非常令人困惑。错误之多,我无法一一列举。大多数错误源于您以复杂和错误的方式使用异步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)