zoukankan      html  css  js  c++  java
  • 网络编程二

    一,基于tcp的黏包现象

    server

    import socket
    sk=socket.socket()
    sk.bind(('127.0.0.1',8090))
    sk.listen()
    conn,addr=sk.accept()
    while 1:
        cmd=input('>>>')
        conn.send(cmd.encode('utf-8'))
        ret=conn.recv(1024).decode('utf-8')
        print(ret)
    conn.close()
    sk.close()

    client

    import socket,subprocess
    sk=socket.socket()
    sk.connect(('127.0.0.1',8090))
    while 1:
        ret=sk.recv(1024).decode('gbk')
        re=subprocess.Popen(ret,shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
        a='stdout:'+(re.stdout.read()).decode('gbk')
        b='stderr:'+(re.stderr.read()).decode('gbk')
        print(a)
        print(b)
        sk.send(a.encode('utf-8'))
        sk.send(b.encode('utf=8'))
    sk.close()

    server结果:

    C:UsershcAppDataLocalProgramsPythonPython36python3.exe C:/s9/day31/server1.py
    >>>dir
    stdout: 驱动器 C 中的卷没有标签。
     卷的序列号是 301A-FE4B
    
     C:s9day31 的目录
    
    2018/01/26  13:53    <DIR>          .
    2018/01/26  13:53    <DIR>          ..
    2018/01/26  13:52               418 client1.py
    2018/01/26  13:53               249 server1.py
                   2 个文件            667 字节
                   2 个目录 30,544,834,560 可用字节
    
    >>>ls
    stderr:
    >>>

    client结果

    C:UsershcAppDataLocalProgramsPythonPython36python3.exe C:/s9/day31/client1.py
    stdout: 驱动器 C 中的卷没有标签。
     卷的序列号是 301A-FE4B
    
     C:s9day31 的目录
    
    2018/01/26  13:53    <DIR>          .
    2018/01/26  13:53    <DIR>          ..
    2018/01/26  13:52               418 client1.py
    2018/01/26  13:53               249 server1.py
                   2 个文件            667 字节
                   2 个目录 30,544,834,560 可用字节
    
    stderr:
    stdout:
    stderr:'ls' 不是内部或外部命令,也不是可运行的程序
    或批处理文件。

    同时执行多条命令,或者显示的的内容过多,得到的结果很可能只有一部分,在执行其他的命令

    的时候,又接收到之前执行的例外的内容,这就叫黏包

    基于udp的

    import socket
    sk=socket.socket(type=socket.SOCK_DGRAM)
    sk.bind(('127.0.0.1',8090))
    msg,addr=sk.recvfrom(1024)
    while 1:
        cmd=input('>>>')
        sk.sendto(cmd.encode('utf-8'),addr)
        ret,addr=sk.recvfrom(1024)
        print(ret.decode('utf-8'))
    conn.close()
    sk.close()
    import socket,subprocess
    sk=socket.socket(type=socket.SOCK_DGRAM)
    aa=('127.0.0.1',8090)
    sk.sendto('hello'.encode('utf-8'),aa)
    while 1:
        ret,addr=sk.recvfrom(1024)
        re=subprocess.Popen(ret.decode('gbk'),shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
        a='stdout:'+(re.stdout.read()).decode('gbk')
        b='stderr:'+(re.stderr.read()).decode('gbk')
        print(a)
        print(b)
        sk.sendto(a.encode('utf-8'),aa)
        sk.sendto(b.encode('utf=8'),aa)
    sk.close()
    C:UsershcAppDataLocalProgramsPythonPython36python3.exe C:/s9/day31/server1.py
    >>>dir
    stdout: 驱动器 C 中的卷没有标签。
     卷的序列号是 301A-FE4B
    
     C:s9day31 的目录
    
    2018/01/26  14:13    <DIR>          .
    2018/01/26  14:13    <DIR>          ..
    2018/01/26  14:10               489 client1.py
    2018/01/26  14:13               275 server1.py
                   2 个文件            764 字节
                   2 个目录 30,521,020,416 可用字节
    
    >>>ls
    stderr:
    >>>ls
    stdout:
    >>>dir
    stderr:'ls' 不是内部或外部命令,也不是可运行的程序
    或批处理文件。
    
    >>>
    C:UsershcAppDataLocalProgramsPythonPython36python3.exe C:/s9/day31/client1.py
    stdout: 驱动器 C 中的卷没有标签。
     卷的序列号是 301A-FE4B
    
     C:s9day31 的目录
    
    2018/01/26  14:13    <DIR>          .
    2018/01/26  14:13    <DIR>          ..
    2018/01/26  14:10               489 client1.py
    2018/01/26  14:13               275 server1.py
                   2 个文件            764 字节
                   2 个目录 30,521,020,416 可用字节
    
    stderr:
    stdout:
    stderr:'ls' 不是内部或外部命令,也不是可运行的程序
    或批处理文件。
    
    stdout:
    stderr:'ls' 不是内部或外部命令,也不是可运行的程序
    或批处理文件。
    
    stdout: 驱动器 C 中的卷没有标签。
     卷的序列号是 301A-FE4B
    
     C:s9day31 的目录
    
    2018/01/26  14:13    <DIR>          .
    2018/01/26  14:13    <DIR>          ..
    2018/01/26  14:10               489 client1.py
    2018/01/26  14:13               275 server1.py
                   2 个文件            764 字节
                   2 个目录 30,520,823,808 可用字节
    
    stderr:

    tcp协议的拆包机制

    当发送端缓冲区的长度大于网卡的MTU时,tcp会将这次发送的数据拆成几个数据包发送出去

    MTU是Maximum Transmission Unit,的缩写,意思是网络上传送的最大数据包,MTU单位是字节,

     大部分网络设备的MTU都是1500。如果本机的MTU比网关的MTU大,大的数据包就会被拆开来传送,这样会产生很多数据包碎片,增加丢包率,降低网络速度。

    面向流的通信特点和Nagle算法

    复制代码
    TCP(transport control protocol,传输控制协议)是面向连接的,面向流的,提供高可靠性服务。
    收发两端(客户端和服务器端)都要有一一成对的socket,因此,发送端为了将多个发往接收端的包,更有效的发到对方,使用了优化方法(Nagle算法),将多次间隔较小且数据量小的数据,合并成一个大的数据块,然后进行封包。
    这样,接收端,就难于分辨出来了,必须提供科学的拆包机制。 即面向流的通信是无消息保护边界的。 
    对于空消息:tcp是基于数据流的,于是收发的消息不能为空,这就需要在客户端和服务端都添加空消息的处理机制,防止程序卡住,而udp是基于数据报的,即便是你输入的是空内容(直接回车),也可以被发送,udp协议会帮你封装上消息头发送过去。 
    可靠黏包的tcp协议:tcp的协议数据不会丢,没有收完包,下次接收,会继续上次继续接收,己端总是在收到ack时才会清除缓冲区内容。数据是可靠的,但是会粘包。

    UDP不会发生黏包

    复制代码
    UDP(user datagram protocol,用户数据报协议)是无连接的,面向消息的,提供高效率服务。 
    不会使用块的合并优化算法,, 由于UDP支持的是一对多的模式,所以接收端的skbuff(套接字缓冲区)采用了链式结构来记录每一个到达的UDP包,在每个UDP包中就有了消息头(消息来源地址,端口等信息),这样,对于接收端来说,就容易进行区分处理了。 即面向消息的通信是有消息保护边界的。 
    对于空消息:tcp是基于数据流的,于是收发的消息不能为空,这就需要在客户端和服务端都添加空消息的处理机制,防止程序卡住,而udp是基于数据报的,即便是你输入的是空内容(直接回车),也可以被发送,udp协议会帮你封装上消息头发送过去。 
    不可靠不黏包的udp协议:udp的recvfrom是阻塞的,一个recvfrom(x)必须对唯一一个sendinto(y),收完了x个字节的数据就算完成,若是y;x数据就丢失,这意味着udp根本不会粘包,但是会丢数据,不可靠。
    
    复制代码
    用UDP协议发送时,用sendto函数最大能发送数据的长度为:65535- IP头(20) – UDP头(8)=65507字节。用sendto函数发送数据时,如果发送数据长度大于该值,则函数会返回错误。(丢弃这个包,不进行发送) 
    用TCP协议发送时,由于TCP是数据流协议,因此不存在包大小的限制(暂不考虑缓冲区的大小),这是指在用send函数时,数据长度参数不受限制。而实际上,所指定的这段数据并不一定会一次性发送出去,如果这段数据比较长,会被分段发送,如果比较短,可能会等待和下一次数据一起发送。

    1,,发送方的缓存机制

    发送端需要等缓冲区满才发送出去,造成粘包(发送数据时间间隔很短,数据了很小,会合到一起,产生粘包)

    2,接收方的缓存机制

    接收方不及时接收缓冲区的包,造成多个包接收(客户端发送了一段数据,服务端只收了一小部分,服务端下次再收的时候还是从缓冲区拿上次遗留的数据,产生粘包) 

    总结

    黏包现象只发生在tcp协议中:

    1.从表面上看,黏包问题主要是因为发送方和接收方的缓存机制、tcp协议面向流通信的特点。

    2.实际上,主要还是因为接收方不知道消息之间的界限,不知道一次性提取多少字节的数据所造成的

  • 相关阅读:
    Seial port API and tool
    Simple HTTPD
    VC与Cygwin的结合
    zlib
    嵌入式开发系统编程文件格式解析
    ZB4O
    Wireshark基本介绍和学习TCP三次握手
    freeware
    Console2 A Better Windows Command Prompt
    iniparser
  • 原文地址:https://www.cnblogs.com/xuguangzong/p/8359544.html
Copyright © 2011-2022 走看看