使TCP连接保持活动状态

时间:2019-04-11 07:27:22

标签: c# .net tcpclient tcplistener

这可能是一个愚蠢的问题,但是请听我说。

在我的远程服务器上,我正在运行一个包含以下代码的程序:

private const int BufferSize = 1024;
private static readonly byte[] BytesBeingReceived = new byte[BufferSize];

static void Main(string[] args)
{
    TcpListener tcpListener = new TcpListener(localaddr: IPAddress.Any, port: 8080);
    tcpListener.Start();

    clientSocket = tcpListener.AcceptSocket();
    clientSocket.Receive(BytesBeingReceived); // Receives header first

    ReceiveAndUnzip(GetZippedFolderSizeInBytes()); 
    // GetZippedFolderSizeInBytes() reads the header, which contains information about the folder size

    Console.WriteLine("Press any key to exit the program.");
    Console.ReadLine();
}

按预期,一旦程序连接到客户端套接字并退出并从客户端接收所有数据(到目前为止,客户端始终是我的本地计算机),程序便会退出。

但是,我想在服务器可用的范围内保持程序运行(即不重新启动,休眠,关闭等)。从客户端收到所有数据后,我想保持TcpListener处于活动状态并等待可能的更多数据。如果客户端断开连接,则TcpListener应该仍然保持活动状态并等待将来的未决连接。

关于如何做到这一点的任何建议?

更新:

这是GetZippedFolderSizeInBytes()的实现:

private static int GetFileSizeInBytes()
{
    return Convert.ToInt32(Encoding.ASCII.GetString(BytesBeingReceived)
                                         .Replace("\0", Empty)
                                         .Split(new[] { Environment.NewLine, ":" }, StringSplitOptions.RemoveEmptyEntries)[1]);
}

这是ReceiveAndUnzip(int numBytesExpectedToReceive)方法的实现:

private static void ReceiveAndUnzip(int numBytesExpectedToReceive)
{
    int numBytesLeftToReceive = numBytesExpectedToReceive;

    using (MemoryStream zippedFolderStream = new MemoryStream(new byte[numBytesExpectedToReceive]))
    {
        while (numBytesLeftToReceive > 0)
        {
            Array.Clear(BytesBeingReceived, 0, BufferSize);
            int numBytesReceived = clientSocket.Receive(BytesBeingReceived, SocketFlags.Partial);
            zippedFolderStream.Write(
                BytesBeingReceived, 
                0, 
                numBytesLeftToReceive < BufferSize ? numBytesLeftToReceive : BufferSize);
            numBytesLeftToReceive -= numBytesReceived;
        }

        zippedFolderStream.Unzip(afterReadingEachDocument: DoMoreStuff);
    }
}

1 个答案:

答案 0 :(得分:2)

您必须更改代码以循环接受新客户端。如果您希望与客户端连接,则可能要使用Receive和Accept的一些异步版本,并在循环中生成一些任务来处理客户端-这虽然不是最佳方法,但是应该可以。

网络编程是一个棘手的问题。这里有一些提示。


1。邮件碎片整理

您不能保证客户端中的单个发送调用将导致服务器上的单个接收。您的消息可以分为片段,或者如果您快速发送几条消息,它们也可以全部合并在一起,并通过一个接收呼叫来接收。

该问题的一种解决方案是在邮件的开头加上标题,例如具有4个字节的整数。这个整数是您的邮件标题,仅包含有关您的邮件有多长时间(以字节为单位)的信息。

您要执行的操作是接收,直到获得此4字节整数标头,然后接收其余消息为止-现在,您知道消息有多长,因此您可以接收到直到收到完整消息为止。对每条新消息重复此过程。

这称为碎片整理碎片整理。有多种实现方法:定界符,以固定大小的标头为前缀的消息,以及两者之间的某些混合。

2。保持活动/心跳机制

在tcp中,半打开和半关闭连接存在问题。简而言之,这仅意味着您无法确定连接是否仍有效-如果您不交换任何消息,则对等/客户端已连接。当对等/客户端断开连接时,您的接收呼叫应返回0-这意味着连接已关闭,但TCP的工作方式并非总是如此,因此您必须考虑以避免各种相关问题。

您可以实现的最简单的Keep-Alive机制只是一些超时逻辑,例如2分钟内未收到任何消息表示对等/客户端已断开连接。或添加每隔X秒发送的其他心跳消息,如果对端/客户端在一定时间内未发送,则会使对等/客户端超时。

3。使用一些经过良好测试的库

如果您未实现任何自定义协议,并且不想自己解决某些聪明人已经解决的所有TCP问题,则搜索库。