这可能是一个愚蠢的问题,但请听我说。
在我的远程服务器上,我运行的程序包含以下代码:
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);
}
}
您必须更改代码以接受循环中的新客户端。你可能想要使用一些异步版本的Receive和Accept,并产生一些任务来处理客户端,如果你想要你的客户端连接 - 这不是真正的最佳方式,但它应该工作。
网络编程是一个棘手的问题。这里有一些提示。
您无法保证客户端中的单个发送呼叫将导致服务器上的单个接收。您的消息可以拆分成片段,或者如果您快速发送一些消息,则可以将它们连接在一起并通过单个接收呼叫接收。
该问题的一个解决方案是首先在消息前加上标题,例如: 4字节整数。此整数是您的邮件头,只包含有关邮件有多长的信息(以字节为单位)。
你想要做的就是接收,直到你得到这个4字节的整数标题,然后接收剩下的信息 - 你现在知道消息是多长时间,所以你收到消息直到你收到整个消息。对每个新邮件重复此过程。
这称为碎片整理或解帧。有多种方法可以实现:分隔符,前缀为固定大小标题的消息,以及这两者之间的一些混合。
在tcp中,半开和半闭连接存在问题。简而言之,它只是意味着您无法确定连接是否仍然存在 - 如果您不交换任何消息,则连接对等/客户端。当对等/客户端断开连接时,您的接收呼叫应该返回0 - 这意味着连接已关闭,但TCP的工作方式并非总是如此,您必须考虑到这一点以避免各种相关问题。
您可以实现的最简单的Keep-Alive机制只是一些超时逻辑,例如2分钟内未收到任何消息表示对等/客户端已断开连接。或者每隔X秒添加一次心跳消息,如果在某个时间范围内没有发送,则超时对等/客户端。
如果您没有实现任何自定义协议,并且不想自己解决所有已经由一些聪明人解决的TCP问题,那么搜索一个库。