zoukankan      html  css  js  c++  java
  • socket进阶

    1、关于send和sendall的区别

    sendall:
    Send a data string to the socket.  For the optional flags
    argument, see the Unix manual. This calls send() repeatedly
    until all data is sent. If an error occurs, it's impossible
    to tell how much data has been sent.
    send:
    Send a data string to the socket.  For the optional flags
    argument, see the Unix manual. Return the number of bytes
    sent; this may be less than len(data) if the network is busy.
    有上面两段话可知,send发送数据(数据需为bytes)可能会小于要发送的数据长度,返回的是已经发送的字节数,sendall就是循环调用send直到数据全部发送完成,所以下面两段代码是等价的
    client = socket.socket()       #创建一个套接字实例
    client.connect(addr)           #将套接字连接到远程地址
    
    client.sendall(b'hello,world')     #发送数据,只能是bytes形式,等同于下面这段
    
    # buffer = b'hello,world'
    # while buffer:
    #     b = client.send(buffer)
    #     buffer = buffer[b:]

    2、粘包问题

    先看段代码

     1 import socket
     2 import time
     3 addr = ("localhost",1024)
     4 
     5 server = socket.socket()  #创建一个socket实例
     6 
     7 server.bind(addr)  #绑定套接字绑定到本地地址,格式为(地址,端口)
     8 server.listen(5)    #监听端口
     9 
    10 conn,addr = server.accept() #等待请求
    11 print(conn,addr)#conn就是客户端连接过来而在服务器端为其生成的一个实例,addr客户端地址,格式为(地址,端口)
    12 
    13 
    14 
    15 data1 = conn.recv(1024)  #接收数据
    16 data2 = conn.recv(1024)
    17 print("data1:{},data2:{}".format(data1,data2))
    18 
    19 server.close()  #关闭连接
     1 import socket
     2 
     3 addr = ("localhost",1024)
     4 
     5 client = socket.socket()       #创建一个套接字实例
     6 client.connect(addr)           #将套接字连接到远程地址
     7 
     8 client.send(b'hello')     #发送数据,只能是bytes形式
     9 client.send(b'world')
    10 
    11 client.close()                         #关闭连接

    这里客户端连续发送两次,服务器端接收两次,我们想要的结果是,依次收到hello和world,但是结果是这样子的:

    <socket.socket fd=420, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 1024), raddr=('127.0.0.1', 51569)> ('127.0.0.1', 51569)
    data1:b'helloworld',data2:b''

    连在一起发送过来了

    所谓粘包问题主要还是C/S两端数据传输时  因为接收方不知道消息之间的界限,不知道一次性提取多少字节的数据所造成的
    根本原因:
    粘包是由TCP协议本身造成的,TCP为提高传输效率,发送方往往要收集到足够多的数据后才发送一个TCP段。若连续几次需要send的数据都很少,通常TCP会根据优化算法把这些数据合成一个TCP段后一次发送出去,这样接收方就收到了粘包数据。udp并不会出现该问题
    解决方法:
    1、自定义字典类型 的数据报头{文件名:a,文件的size:1090}计算出该报头的长度(len(字节))
    2、使用struct.pack('i',报头长度(一个数字))把一个数字压缩成固定的size 4个字节,发送给对端。

    3、对端 struct.unpack(‘i’,recv(4))接收固定大小4个字节;这就是接收到了 报头的长度。

    4.recv(报头长度)这就是发送过来的报头信息了
    对上面例子进行优化:
    #client
    
    import socket
    import struct
    addr = ("localhost",1024)
    
    client = socket.socket()       #创建一个套接字实例
    client.connect(addr)           #将套接字连接到远程地址
    
    msg = b'hello'
    msg1 = b'world'
    msg_size = len(msg)
    
    
    a = struct.pack('i',msg_size)
    client.send(a)             #发送数据长度
    client.send(b'hello')     #这里我们只要处理这个粘包就可以了
    client.send(msg1)
    
    client.close()                         #关闭连接
    
    
    #server
    import socket
    import time
    addr = ("localhost",1024)
    
    server = socket.socket()  #创建一个socket实例
    
    server.bind(addr)  #绑定套接字绑定到本地地址,格式为(地址,端口)
    server.listen(5)    #监听端口
    
    conn,addr = server.accept() #等待请求
    print(conn,addr)#conn就是客户端连接过来而在服务器端为其生成的一个实例,addr客户端地址,格式为(地址,端口)
    
    
    size = conn.recv(4)   #接收报头,4bytes
    print(size[0])
    data1 = conn.recv(size[0])  #size[0]就是要接收的数据长度
    data2 = conn.recv(1024)
    print("data1:{},data2:{}".format(data1,data2))
    
    server.close()  #关闭连接
    
    
    

      

     


  • 相关阅读:
    EasyUI左边树菜单和datagrid分页
    Linux上安装Redis教程
    TreeMap和TreeSet的区别与联系
    将Map<String, List<Map<String,Object>>>进行排序
    Linux系统安装JDK和Tomcat
    点击添加按钮,使用ajax动态添加一行和移除一行,并且序号重新排序和数据不重复操作判断
    23种设计模式汇总整理
    SSH架构BaseDao实现
    双击Table表格td变成text修改内容
    用户找回密码功能JS验证邮箱通过点击下一步隐藏邮箱输入框并修改下一步按钮的ID
  • 原文地址:https://www.cnblogs.com/zj-luxj/p/7113051.html
Copyright © 2011-2022 走看看