0

我有一个用 C# 编写的多线程 TCP 服务器。客户端被服务器接受,并且在连接时不会离开服务器。在大约 1300 个活动连接之后,我的软件给出了 System.OutOfMemmoryException 错误。这个问题是否与 32 位系统架构和内存有关?我有 32 位 Windows 7 Professional 和 4 GB 的 RAM。当我的服务器上存在大约 1300 个活动连接时,我的内存使用量约为 2.1GB,CPU 使用率为 30%。

谢谢你。

4

3 回答 3

5

System.OutOfMemmoryException在您的进程中创建约 1300 个线程时抛出(在 32 位操作系统上)。问题是您正在为每个连接创建全新的线程。那是不好的做法。

相反,您应该只使用一个线程来管理发送数据,使用同一个线程(或者可能是第二个)来发送数据,并且只使用一个线程来接受连接。

接受所有客户端的线程池的代码示例:

TcpListener tcpListener = new TcpListener(IPAddress.Any, 90);

public void BeginAccept()
{
    try { tcpListener.BeginAcceptTcpClient(AcceptClient, null); }
    catch { /* Swallowing is bad */ }
}

private void AcceptClient(IAsyncResult ar)
{
    TcpClient tcpClient;

    try { tcpClient = tcpListener.EndAcceptTcpClient(ar); }
    catch { /* Swallowing is bad */ }
    finally { BeginAccept(); }

    // TODO: Add your brand new tcpClient to some sort of collection, may be.
}

一个线程接受所有客户端的代码示例:

TcpListener tcpListener = new TcpListener(IPAddress.Any, 90);
bool isListening;

public void BeginAccept()
{
    while (isListening)
    {
        TcpClient tcpClient;

        try { tcpClient = tcpListener.AcceptTcpClient(); }
        catch { /* Swallowing is bad */ }

        // TODO: Add your brand new tcpClient to some sort of collection, may be.
    }
}
于 2012-04-12T12:08:01.177 回答
0

你应该看看实现异步服务器套接字
我仍然建议在不同的线程中发送响应以避免队列/TCP 重新发送。
您可以使用任务或将接收到的具有相关连接的消息添加到并发队列中,由工作人员处理它们。

于 2012-04-12T12:20:27.123 回答
0

您的计算机/操作系统不是限制因素。它可以为每个进程分配近 4GB(如果您总共使用超过 4GB,它将开始交换/写入磁盘:这比普通内存慢得多,但它仍然可以工作)。但是,C# 编译器限制了你。C# 默认编译为 32 位,这意味着每个进程只能使用大约 2GB 的内存。这就是为什么您的服务器一旦达到 2GB 就会崩溃。您可以为 64 位操作系统编译它,这将允许您使用几乎无限的内存,但您没有 64 位操作系统,因此它不会在您的机器上运行。

最好为每个客户端连接创建一个新进程,而不是一个线程。您的主进程将侦听并接受连接,并且当建立新连接时,它应该生成一个专门用于处理与该客户端的连接的新进程。因为每个连接都有自己的进程,所以您不会再达到 2GB 的限制,并且还有更多优点:一旦连接关闭,回收内存就容易得多,并且一个连接中的任何错误都不太可能导致整个程序崩溃。当然,多进程架构的编程比多线程架构的编程要困难一些,因为没有共享内存,但这是更好的方法。

于 2012-04-12T12:21:26.003 回答