tcp和udp发送接收的细节

2020年10月19日 / 32次阅读 / Last Modified 2020年10月20日
socket

python tcp和udp编程时,有一些发送和接收数据方面的细节,需要好好研究一下。

UDP(package)

udp的sendto接口,最大一次大概发就是65000左右个字节,在大就会有raise,说数据太大了。

而udp的recvfrom接口,要给一个缓冲区大小,这个缓冲区大小不能太小,如果小于对方发送的数据,直接数据丢失。udp的recvfrom,只有一次机会,下一次在recvfrom,就直接阻塞了。

udp报文很大的时候,IP层会对齐进行分片处理,接收侧合并所有分片后,在同时udp层处理。失败就失败了,udp传输没有确认机制。

如果udp发送端在接收端两次recvfrom之间,连续sendto了好几次数据,假设缓冲区足够大,recvfrom每一次还是只能够获得一个udp的数据报文,要连续好几次才能收完数据。udp通信以报文为单位,每一次收一个报文。

UDP报文头
UDP报文头

网络上又说UDP头的校验是可选的,不是很确定?

TCP(stream)

tcp的send接口,就可以一下子发送超大的数据,我测试过一次发10万个字节,不会raise。

tcp 的recv接口,不管你设置多大的缓冲区都没关系,只要数据还没有收完,下一次recv接着收。

python系统默认给tcp接收最大缓冲区是65536字节,发送一个10万字节的消息,接收端会先收65536字节,下一次recv时在接着收。

如果发送端在接收端两次recv之间,连续send了好几次数据,接收端在recv的时候,如果缓冲区足够大,可以直接一锅端。

应用如果建立在tcp上,发送方和接收方要做一些约定,tcp只保证了数据的可靠传输,对数据的解释,需要应用层来完成。

一个可能出问题的场景:tcp发送方通过调用多次send函数来发送数据,由于网络传输的不确定性,接收方仅仅通过一次recv,可能收不全数据,接收方需要有一个判断机制,来判断消息数据接收完毕。或者有一个应用层的简单协议,比如先传长度信息,或者等待超时后做checksum(要规定checksum的位置)。多次调用send函数,而不是一次sendall函数,也是个系统设计问题,具体请参考python官方对这两个函数的说明。

tcp报文头
tcp报文头

TCP校验和字段:占16比特。对整个TCP报文段,即TCP头部和TCP数据进行校验和计算,并由目标端进行验证。

窗口大小字段:占16比特。此字段用来进行流量控制。单位为字节数,这个值是本机期望一次接收的字节数。

-----补充-----

终于发现的权威的关于TCP的资料,就是python官方的howto:https://docs.python.org/3/howto/sockets.html#socket-howto

-- EOF --

本文链接:https://www.pynote.net/archives/2592

留言区

《tcp和udp发送接收的细节》有5条留言

电子邮件地址不会被公开。 必填项已用*标注

  • 麦新杰

    TCP通信可以设计成短连接,也可以是长连接。 [回复]

  • 麦新杰

    UDP可以发长度为0的package,接收方收到的也是长度为0的msg;TCP发送长度为0的msg,等于什么都没发,send函数会返回0,tcp链接依旧,接收方还阻塞在recv函数不会返回。 [回复]

  • 麦新杰

    But if you plan to reuse your socket for further transfers, you need to realize that there is no EOT on a socket. I repeat: if a socket send or recv returns after handling 0 bytes, the connection has been broken. If the connection has not been broken, you may wait on a recv forever, because the socket will not tell you that there’s nothing more to read (for now). [回复]

    • 麦新杰

      Now if you think about that a bit, you’ll come to realize a fundamental truth of sockets: messages must either be fixed length (yuck), or be delimited (shrug), or indicate how long they are (much better), or end by shutting down the connection. The choice is entirely yours, (but some ways are righter than others). [回复]

  • 麦新杰

    UDP收发都是package,TCP收发都是stream! [回复]


前一篇:
后一篇:

More


©Copyright 麦新杰 Since 2019 Python笔记

go to top