2

我正在尝试在 C# 中编写一个异步套接字。我阅读了很多 msdn 文章并找到了这两个示例:serverclient

我理解示例代码并使用它来实现我自己的异步套接字。在示例中,服务器检查<EOF>以确定流的结尾并发送响应。我想知道流结束时不检查特殊文字。我的想法是递归地检查(bytesRead > 0)和调用。handler.BeginReceive()请参阅以下内容:

原来的

if (bytesRead > 0) {
    // There  might be more data, so store the data received so far.
    state.sb.Append(Encoding.ASCII.GetString(
        state.buffer,0,bytesRead));

    // Check for end-of-file tag. If it is not there, read 
    // more data.
    content = state.sb.ToString();
    if (content.IndexOf("<EOF>") > -1) {
        // All the data has been read from the 
        // client. Display it on the console.
        Console.WriteLine("Read {0} bytes from socket. \n Data : {1}",
            content.Length, content );
        // Echo the data back to the client.
        Send(handler, content);
    } else {
        // Not all data received. Get more.
        handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
        new AsyncCallback(ReadCallback), state);
    }
}

我的点子

if (received > 0)
{
    state.sb.Append(Encoding.ASCII.GetString(state.buffer, 0, received));
    handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReadCallback), state);
}
else
    Send(handler, state.sb.ToString());

如果我用我的零件替换原始零件,程序将停止运行。我猜客户端在 in 之后执行并EndSend()阻止SendCallback()线程。我怎么能通过这个?是否有必要使用确定流结束的令牌?receiveDone.WaitOne()StartClient()

还有其他好的示例代码吗?我刚找到那两个。

(证据。服务器应该接收在线客户端并将它们从这个缓冲区中放入一个循环缓冲区,他应该使用多线程读取和处理记录。)

编辑

如果我使用以下功能:

if (receive > 0)
    state.sb.Append(Encoding.UTF8.GetString(state.buffer, 0, receive));
if (receive == StateObject.BufferSize)
    state.listener.BeginReceive(state.buffer, 0, StateObject.BufferSize, SocketFlags.None, new AsyncCallback(ReceiveCallback), state);
else
    Send(state.listener, state.sb.ToString());

一切工作正常,我猜。可以吗?还是想念我什么?

如果我将这两个 if 结合起来,它将不再起作用。为什么?

if(receive > 0 || receive == StateObject.BufferSize)->if(receive > 0) // Not working.

4

2 回答 2

4

您的代码版本的问题是您BeginReceive总是在一种情况下启动,即当0收到字节时。事实上,当您收到非零且小于缓冲区大小的数据量(有时恰好是缓冲区大小时)时,大多数情况下会发生传输结束。接收0字节永远不会发生,因为这意味着没有传输而不是传输结束。那是假设发送者通过关闭连接来结束传输。

有多种方法可以指示传输结束:

  • 发件人关闭连接
  • 发送特殊序列(如 EOF)
  • 接收者得到了他所期望的(因为它首先得到了标题)

第一种方法的问题是关闭(和重新打开)连接通常很昂贵。标头的问题是,如果您错过了一个标头(由于某些网络问题),您将丢失 - 您不知道下一个标头何时到来,因为您不知道当前数据包何时结束(丢失标头)。出现问题时最容易的恢复以某种形式提供 EOF。它不一定是字面上的<EOF>字符串,它可以是(很可能)不会出现在您的正常数据流中的任何内容。

话虽如此,没有什么能阻止您将标题与EOF或包含特殊序列标记记录开头的标题组合使用。

于 2013-04-04T10:45:57.253 回答
0

您可以确定网络流已经结束的情况是远程端正常关闭连接。这将使EndRead返回为零。如果您想将数据发送回远程端,这当然不是最佳方法。您基本上必须创建一个返回客户端的新连接,而不是重用初始连接。这当然是您可以做的,但它通常不会很好地工作,例如,如果客户端位于 NAT 路由器后面。

示例代码在检查时执行的操作EOF是执行应用程序级协议。底层网络堆栈不了解它传递给您的应用程序的有效负载,因此无法确定概念流已经结束。这是您的应用程序有责任的事情。检查标签或令牌是一种非常简单的方法。

于 2013-04-03T16:51:38.537 回答