When sending data larger than the SendBufferSize,

2020-06-23 20:29发布

I just asked a question on how to send data larger than the SendBufferSize and the answer was that is would be send in a couple of parts.

My second question is how will this data be received? Will it be complete in the network stream or will it get it divided.

the first question: Can you send a file larger that the SendBufferSize throuh a TcpClient?

5条回答
Luminary・发光体
2楼-- · 2020-06-23 20:34

TCP is not a message only protocol. It is a stream based protocol and takes care of splitting the data for us. Lemme take you to the core section. There are two parts in the case of TCP - Segmentation and Fragmentation.

Segmentation happens at TCP (Transport Layer). This is dependent on two parameters - MSS and Window Size. MSS determines the maximum size of segment that a device can receive. The MSS is communicated during the intial connection establishment via TCP options. Each direction of data flow can use a different MSS and the operating system determines it. However, the Window size is sent in TCP header by the receiver to communicate the maximum of data it can buffer at one time on the receiving side of a connection before waiting an acknowlegement and window update from the receiving host. That is, a host can send a number of segments(factor of MSS) before exhausting the receiver's window size.

Fragmentation happens at IP(Network Layer) in two ways. If there are no devices with MTU limitation on the path of communication between the sender and receiver, fragmentation will happen to meet the MTU of ethernet(1500 bytes) alone. However, incase of presence of an intermediate device with a MTU limitation between the sender and receiver, IP layer(Internet protocol) does datagram fragmentation, so that packets may be formed such that they can pass through a link with a smaller maximum transmission unit (MTU) than the original datagram size. In case of intermediate device with MTU limitations, the sender shall also deploy path MTU discovery to determine the the minimum MTU in the network path towards the receiver and dynamically adjust the MSS to avoid IP fragmentation within network. Path MTU discovery is done by setting the DF (Don't Fragment) option in the IP headers of outgoing packets. Any device in the path of communication between the sender and receiver, whose MTU is smaller than the packet will drop such packets and reply the sender with ICMP "Destination Unreachable (Datagram Too Big)" message containing the device's MTU. This information allows the sender to reduce its assumed path MTU appropriately.

So, this leads to the point of relation between the MSS and MTU. The RFC 791 states that "All hosts must be prepared to accept datagrams of up to 576 octets (whether they arrive whole or in fragments)". So, the minimum MTU for IP networks is 576. In case of TCP, deduction of 20 bytes for the TCP header and 20 bytes for the IP header we will give us 536 bytes as standard MSS for TCP.

Now, lets get into the re-assembly part. Fragmentation can happen based on MTU on the intermediate devices, but the re-assembly shall happen only at the destination device. TCP takes care of segmentation, however on the destination device, TCP shall take care of ordering, but the re-assembly of the segments should be taken care by the application.

So, If you need only whole message based communication and reliability is not a concern, then UDP shall be your choice. However, note that if you can send a large data by splitting, UDP will not be able to ensure the ordering of the packets and also it will not be able to deal with packet drops as it does not have error correction mechanism like re-transmission.

If you would want to have a message based communication just as in UDP but coupled with TCP features like reliable in-order delivery, congestion control and also additional improvements/features on top of it, like multi-streaming, multi-homing, in-built MTU discovery, then SCTP should be your choice. However, if you have legacy NAT systems in your network, then you may need to go for encapsulating SCTP in UDP.

查看更多
别忘想泡老子
3楼-- · 2020-06-23 20:35

You will need something called message framing in your protocol.

Fun fact: you'll need this even if sending a message smaller than SendBufferSize. :)

查看更多
老娘就宠你
4楼-- · 2020-06-23 20:37

.Net handles the splitting of the data for you. You can write and receive packages larger than SendBufferSize without noticing it (if you aren't too concerned about performance).

查看更多
手持菜刀,她持情操
5楼-- · 2020-06-23 20:38

Chances are your data is going to be split on receive so you'll need to rebuild it once you've received all the data.

查看更多
我命由我不由天
6楼-- · 2020-06-23 20:58

In contrast to e.g. UDP, TCP is not a protocol that allows sending of individual "messages", which get delivered to the receiver in the same form. You rather send and receive a stream of bytes.

Under the hood, your data gets split into IP packets, regardless of SendBufferSize, which btw defaults to 8192, a value much higher than what fits into a single IP packet (the maximum size of an IP packet is related to the MTU, but mostly a little less than 1500 bytes). Example:

  1. Socket.Send(2000 bytes)
  2. IP Packet #1(1460 bytes)
  3. IP Packet #2(540 bytes)

Also: The data of multiple Socket.Send()s may get merged (Nagle's algorithm). Example:

  1. Socket.Send(1000 bytes)
  2. Socket.Send(1000 bytes)
  3. IP Packet #1(1460 bytes)
  4. IP Packet #2(540 bytes)

And there's no way for the receiver to distinguish the 2 cases. What's more, for reasons of efficiency, on the receiving end the data might be handed over to you in a different size buffer.

Bottom line: With TCP, you cannot rely to receive packets in the same number and with the same sizes as they are sent. If you need that, add size information, as suggested by Stephen Cleary, or use a protocol like UDP or if you need reliability: SCTP. Which however looks like overkill, unless you are also interested in SCTP's other improvements over TCP.

查看更多
登录 后发表回答