【问题标题】:Do I have to chunk large data while sending it with tcp socket?使用 tcp 套接字发送大数据时是否必须对大数据进行分块?
【发布时间】:2011-11-03 17:25:16
【问题描述】:

我正在通过 tcp 套接字发送一些非大字符串。今天我发送了 2031 个字节,而接收端并没有得到全部(我已经发送了更大的消息 - 在 2040 字节之前到几天前) - 这并不是那么糟糕,程序知道出了问题并再次发送数据(第三次尝试成功)。现在我想知道是否应该将消息分成更小的块并在循环语句中发送它们?我的代码中是否有我遗漏的东西?

Socket sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
sock.SetSocketOption(System.Net.Sockets.SocketOptionLevel.Socket,SocketOptionName.ReceiveTimeout,0);
sock.SetSocketOption(System.Net.Sockets.SocketOptionLevel.Socket,SocketOptionName.SendTimeout,0);           
LingerOption lingerOption = new LingerOption (true, 1); 
sock.SetSocketOption(System.Net.Sockets.SocketOptionLevel.Socket,SocketOptionName.Linger, lingerOption );
sock.Blocking =  true;

try
{
    sock.Connect(_dostHostEp);
}
catch(SocketException e)                     
{                                       
    sock.Close();
    throw new Exception("Connection error (" + _dostHostEp.Address + ":" + _dostHostEp.Port + ")" + e.Message);             
}

try    
{
    sock.Send(Encoding.UTF8.GetBytes(message));                             
}
catch(SocketException e)
{                   
    sock.Close();               
    throw new Exception("Error while sending message to (" + _dostHostEp.Address + ":" + _dostHostEp.Port + ")" + e.Message);               
}

【问题讨论】:

标签: c# sockets


【解决方案1】:

为什么你坚持要把 2031 个字节放在一个块中?相反,您必须在接收方读取数据直到数据存在。这意味着例如您读取了一个 1800 字节的块,另一个 231 字节的块,然后是 0 字节,这意味着数据结束。

【讨论】:

  • -1 No. 0 不代表结束,表示“断开”。 Read 在有更多数据可用之前不会返回。
  • 我并不是坚持要在一个块中获取 2031 个字节。接收由其他人完成。我的问题是socket.Send方法中传递的字节数组是否有限制?
  • 阅读我的链接答案。你永远不能保证接收者收到你发送的所有东西。 TCP 不能那样工作。换句话说:发送多少数据并不重要(只要不溢出套接字实现的内部缓冲区)。
  • 所以总的来说我的方式还不错:1. 发送 2. 看看它是否正常(接收方回复正确的消息) 3. 如果以后不再次发送?
  • TCP 将始终传递您发送的内容(或尝试死亡 = 断开连接)= 您永远不需要重新发送任何内容。您需要引入一种方法来告诉接收者消息何时开始或结束(再次阅读链接的答案)。
【解决方案2】:

我一直认为在没有明确定义的结束字符的情况下发送数据是不好的做法。我个人建议执行以下操作:

作为发件人,在消息前添加 STX-Character (0x02) 并附加 ETX-Character (0x03)。

接收方应将 STX 识别为新消息的开始,然后读取(阻塞?)直到收到 ETX。如果在合理时间内没有收到 ETX,则说明读取整条消息时出现问题。

您不需要使用 STX 和 ETX,也可以使用 \r\n 或任何不属于您的消息本身的内容。

如果您不使用明确定义的消息结尾,读者将永远不知道何时停止阅读,您将搞砸您的沟通。

我认为有问题的一个示例案例:

发件人一个接一个地发送两条消息。如果没有 EndOfMessage 字符,接收者将尝试将其作为一条消息读取。使用 EOM,接收方可以拆分两条消息并同时处理它们。

【讨论】:

  • 为什么不投票以重复关闭,而不是在链接的问题中重复我的答案?
  • 因为我什至在你对副本发表评论之前就开始写这篇回复了。
猜你喜欢
  • 2012-10-13
  • 2020-12-03
  • 1970-01-01
  • 2018-08-05
  • 2015-01-23
  • 1970-01-01
  • 1970-01-01
  • 2020-09-01
  • 2013-07-04
相关资源
最近更新 更多