保持 TCP 连接处于活动状态 [英] Keeping TCP connection alive

查看:50
本文介绍了保持 TCP 连接处于活动状态的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

This is probably a stupid question, but hear me out.

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

On my remote server, I am running a program with the following code:

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();
}

正如预期的那样,程序在连接到客户端套接字并从客户端接收所有数据后退出(到目前为止,客户端始终是我的本地机器).

As expected, the program exits once it becomes connected to a client socket and receives all the data from the client (so far the client is always my local machine).

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

However, I would like to keep the program running insofar as the server is available (i.e. not restarting, hibernating, shut down, etc.). After receiving all the data from the client, I would like to keep the TcpListener active and wait for possibly more data. If the client disconnects, the TcpListener should still stay alive and wait for future pending connections.

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

Any suggestions on how I can do so?

更新:

这是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);
    }
}

推荐答案

您必须更改代码以在循环中接受新客户.如果您希望您的客户端连接,您可能希望使用一些异步版本的 Receive 和 Accept 并生成一些任务来处理客户端也循环 - 这实际上不是最佳方式,但它应该可以工作.

You have to change your code to accept new clients in a loop. You probably may want to use some asynchronous versions of Receive and Accept and spawn some tasks to handle clients also in a loop if you want your clients connected - this is not really the most optimal way, but it should work.

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

Network programming is a tricky one. Here are some tips.

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

You have no guarantee that a single Send call in the client will result in single Receive on the server. Your message can be split into fragments or if you quickly send a couple of messages they can all be joined together and received with a single Receive call.

该问题的一个解决方案是在消息前面加上一个标题作为前缀,例如4 字节整数.这个整数是你的消息头,只包含你的消息有多长的信息(以字节为单位).

One solution to that problem is to prefix the message with a header first e.g. with 4 byte integer. This integer is your message header and just contains the information about how long is your message (in bytes).

您想要做的是接收,直到您获得这个 4 字节的整数标头,然后接收消息的其余部分 - 您现在知道消息的长度,因此您可以接收到完整的消息.对每条新消息重复此过程.

What you want to do is receive until you get this 4 byte integer header and then receive the rest of the message - you now know how long the message is so you receive until you get whole message. Repeat this process for every new message.

这称为碎片整理整理.您可以通过多种方式实现这一点:分隔符、以固定大小标头为前缀的消息、这两者之间的一些混合.

This is called defragmentation or deframing. There are various ways you can implement that: delimiters, messages prefixed with fixed-size headers, some mix between those two.

在tcp中存在半开半闭连接的问题.简而言之,它只是意味着您无法确定连接是否仍然活动 - 如果您不交换任何消息,则对等/客户端已连接.当对等/客户端断开连接时,您的 Receive 调用应返回 0 - 这意味着连接已关闭,但 TCP 的工作方式并非总是如此,您必须考虑避免各种相关问题.

In tcp there are problems with half-open and half-closed connections. In short it just means that you cannot be sure whether the connection is still alive - peer/client is connected if you don't exchange any messages. When peer/client disconnects then your Receive call should return 0 - that means the connection is closed, but the way TCP works that's not always the case and you have to account for that to avoid all kinds of related problems.

您可以实现的最简单的 Keep-Alive 机制只是一些超时逻辑,例如2 分钟内未收到任何消息意味着对等/客户端已断开连接.或者添加额外的心跳消息,每 X 秒发送一次,如果在某个时间范围内没有发送它,则对等/客户端超时.

The simplest Keep-Alive mechanism you can implement is just some timeout logic e.g. not receiving any message within 2 minutes means peer/client is disconnected. Or add additional heartbeat message sent every X seconds and timeout the peer/client if it didn't send it within some time range.

如果您没有实现任何自定义协议,并且不想自己解决一些聪明人已经解决的所有 TCP 问题,那么请搜索一个库.

If you are not implementing any custom protocol and don't want to solve all the TCP issues by yourself that are already solved by some smart guys then search for a library.

这篇关于保持 TCP 连接处于活动状态的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆