学习笔记(1):socket:tcp,udp

首先要清楚的几点是

  1. socket服务本质是一个应用服务,属于应用层。
  2. 数据之间的传输依靠的是底层的硬件,如网卡,位于物理层,传输的是字节。
  3. 应用层要想获得物理层的数据必须通过操作系统,当socket要传输或者接收网络数据,必须由操作系统中间调度,socket只是单纯的搬运缓冲区的数据。
  4. 网络之间的数据传输依靠的是tcp/udp等协议,socket服务只是单纯的搬运工,要将二者区别开看。
  5. tcp的传输是字节流,udp传输的是数据报,两者在数据传输上的区别是udp已经定制好报头,而这些报头也扮演着分隔符的功能,而字节流更像流水,没有界限,所以会socket搬运的时候只是按照规定的长度搬运,不管这串数据之间是否关联,这就造成了粘包,而在udp中,由于有报头作为分隔符就明确的知道报与报的关系,不会造成相互倾占。
  6. send()与recv()没有一一对应的关系,sendto()与recvfrom()由于有报头所以存在一一对应关系,具体的是,如果有3个发送,却有4个接受,那么程序会卡在第4个接受上。

socket.recv() 与socket.recvfrom() 面对发送消息为空时:

前者会被阻塞,后者会正常发送(不过送的内容为空),为何?因为前面已经提到了,udp协议会为每一次发送消息定制报头,虽然发送消息为空,但是加上了报头数据,所以接收方的缓冲区依然会接收到数据,反观前者发送为空,缓冲区就一直为空,相当于没有任何发送,接收程序依然在等待。

客户端异常断开服务和正常socket.close()的区别

正常关闭会使得recv不再阻塞,会一直搬运缓冲区的数据,而缓冲区为空,所以搬运一直的是空(b''),可以用一个if判断解决。

if msg:   #如果为空
    break  #跳出通讯的循环,不再搬运数据

如果是异常断开(即程序异常断开,socket实例没有关闭),则服务端会报错,解决办法:

try:
    '这里写正常时执行的代码'
except Exception as e:
    print(e)
    '这里写处理办法'        #这样服务端程序就不会因为报错而断开连接

为tcp协议定制报头

有时候,发送量远远大于一次接受的量(一般接受不超过8k字节),而缓冲区也小于要发送的数据量,一般对数据做拆分处理。

  • .sendall()这个方法不会将没有存进缓冲区的数据丢失,而是暂存,等待有空间,剩下的再依次进入缓冲区域。
  • 定制报头要用到两个模块:structpickle模块

请转至这里

猜你喜欢

转载自blog.csdn.net/a_lazy_zhu/article/details/80503103