2010-04-04 77 views
2

我有一个线程是通过套接字这样接收数据:.NET套接字缓冲区溢出没有错误

while (sock.Connected) 
{ 
    // Receive Data (Block if no data) 
    recvn = sock.Receive(recvb, 0, rlen, SocketFlags.None, out serr); 

    if (recvn <= 0 || sock == null || !sock.Connected) 
    { 
     OnError("Error In Receive, recvn <= 0 || sock == null || !sock.Connected"); 
     return; 
    } 
    else if (serr != SocketError.Success) 
    { 
     OnError("Error In Receive, serr = " + serr); 
     return; 
    } 

    // Copy Data Into Tokenizer 
    tknz.Read(recvb, recvn); 

    // Parse Data 
    while (tknz.MoveToNext()) 
    { 
     try 
     { 
      ParseMessageAndRaiseEvents(tknz.Buffer(), tknz.Length); 
     } 
     catch (System.Exception ex) 
     { 
      string BadMessage = ByteArrayToStringClean(tknz.Buffer(), tknz.Length); 
      string msg = string.Format("Exception in MDWrapper Parsing Message, 
          Ex = {0}, Msg = {1}", ex.Message, BadMessage); 
      OnError(msg); 
     } 
    } 
} 

我总是看到在我的分析功能偶然的错误指示该消息是无效的。起初,我认为我的tokenizer类被破坏了。但是,在将所有传入字节记录到标记器后,事实证明recvb中的原始字节不是有效的消息。我不认为这样的数据流是可以通过tcp数据流破坏的。

我想它必须是某种类型的缓冲区溢出,所以我设置

sock.ReceiveBufferSize = 1024 * 1024 * 8; 

,从不解析错误,曾经发生在测试(它发生的频率足以复制,如果我不改变ReceiveBufferSize )。

但我的问题是:为什么我没有看到一个异常或错误状态,或者如果在更改此缓冲区大小之前套接字的内部缓冲区溢出了?

回答

2

我还建议确认数据的发送者正在检查成功写入的字节数,而不是假定所有字节都已成功写入。

这是使用Socket.Send时常见的错误,也可以解释为什么当您调整缓冲区大小时,问题会消失。

发件人有责任重试,直到所有字节都成功写入。

+0

感谢您的回复。这是一个很好的观点,它可能在发件人一方。这将解释为什么套接字不报告任何错误。如果字节正确传递,但发件人有一些问题,而不是全部发送给我,因为缓冲区已满,那可能就是这样。我想我应该用wireshark捕获服务器发送的数据包来确认。 – 2010-04-05 02:19:25

+0

我想你的权利,设法让服务器的人今天和他的日志文件记录输出:“发送():短送98,应该是106.” 所以看起来他没有发送所有东西,因为我的接收缓冲区已满。谢谢你的帮助! – 2010-04-05 19:01:37

4

我假设你的标记器需要文本(Utf8?),但是(套接字)流使用字节数据。多字节字符在传输中可能会分裂。一个小缓冲区增加了发生这种情况的可能性。

如果您使用的ASCII码是安全的,否则解决方案将使用TextReader作为中间件。

+0

感谢您的回复。我没有想过这个。幸运的是,这是使用ASCII。我收到的数据的数据包结构具有ascii字符31(单位分隔符)作为消息之间的分隔符。只是从recvb捕获原始数据并写入文件表明这些消息是无效的(至少两个消息在它们之间没有字符31的情况下重叠时,数组中的一个点)。 – 2010-04-04 23:26:43

+0

@迈克尔,好的,但仍然检查你的标记器的逻辑。从你的代码中,标记器负责重新组装消息。也就是说,在尝试查找下一条消息之前,必须记住任何不完整的消息并追加新的数据。 – 2010-04-04 23:31:20

+0

标记器不会重新组装消息。肯定可能会有一个错误。但我不认为这是我在这里看到的问题。我在记录recvn内容到达记号器之前先进行记录。只要将这些字节写入到文件中,并且其中的消息不正确(即两个消息存在重叠,不会被ascii令牌31分隔)。 – 2010-04-04 23:54:24