• python笔记8 socket(TCP) subprocess模块 粘包现象 struct模块 基于UDP的套接字协议


    socket

    基于tcp协议socket

    服务端

    import socket
    
    phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  # 买电话
    # socket.SOCK_STREAM 流式协议 就是TCP协议
    phone.bind(('127.0.0.1', 8080))  # 买电话卡
    
    phone.listen(5)  # 开机。
    # 5 不是链接数,链接可以产生N个,同一时刻只能监听5个请求。
    
    conn, addr = phone.accept() # 等待接电话  # 阻塞状态
    # print(222)
    print(conn, addr)  # conn 代表的是socket通信的对象,一个管道
    
    client_data = conn.recv(1024)  # 交流过程
    print(client_data)
    conn.send(client_data.upper())
    
    conn.close()
    phone.close()

    客户端

    import socket
    
    phone = socket.socket()  # 买电话
    
    phone.connect(('127.0.0.1', 8080))  # 拨号
    
    msg = input('>>>').strip()
    phone.send(msg.encode('utf-8'))
    server_data = phone.recv(1024)  # 限制的是最大接收字节数。
    print(server_data)
    phone.close()

    服务端与客户端循环 聊

    import socket
    import subprocess
    # socket.SOCK_STREAM 流式协议 就是TCP协议
    phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  # 买电话
    phone.bind(('127.0.0.1', 8080))  # 绑定电话卡,写自己的IP  (俩括号)
    phone.listen(5)   #开机   5不是限制连接数,而是同一时刻只接受5个请求,可以不写,不写为默认,默认可以开启N个
    #运行后停在这里,下边不执行
    while 1:
        conn,addr = phone.accept()  #等待接电话 phone.accept()  conn和addr分别接收phone..accept()生成的两个参数
        print(addr)  #打印连接进来的客户端
        while 1:
            try:
                client_data = conn.recv(1024)   #接受的字节数
                c = client_data.decode('gbk')
                obj = subprocess.Popen(c,
                                       shell=True,
                                       stdout=subprocess.PIPE,
                                       stderr=subprocess.PIPE)
                RET = obj.stdout.read()
                RET1 = obj.stderr.read()
                print(RET.decode('gbk'))
                conn.send(RET+RET1) #返回的信息
            except Exception:
                break
        conn.close()
    phone.close()

    客户端

    import socket
    phone = socket.socket()
    phone.connect(('127.0.0.1', 8080))  # 拨号,写服务端的IP  (俩括号)
    while 1:
        fasong = input('>>>')
        if fasong.upper() == 'Q': break
        elif  not fasong :continue            #如果发送为空,则跳过本次循环 not False3 = True
        phone.send(fasong.encode('gbk'))       #刚给服务端发信息
        server_data = phone.recv(1024)    #接收服务端的信息,1024限制的是最大接受的字节数
        print(server_data.decode('gbk'))
    phone.close()

    subprocess模块

    subprocess模块用于接收shell界面执行的命令并返回结果

    import subprocess 
    obj = subprocess.Popen('ip a',          #输入命令
                            shell=True,           #shell为Tree
                           stdout=subprocess.PIPE,              #stdout接收正确
                           stderr=subprocess.PIPE)               #stderr接收错误返回
    RET = obj.stdout.read()     
    print(RET.decode('utf-8'))        

     粘包现象

    tcp协议

    1. 流式协议.数据全部都像水一样连在一起,一次性发送多字节(全部在客户端操作系统的缓存区),客户端每次只取1024字节,剩余字节在缓存区等待下次取

    client_data = conn.recv(1024)    
    server_data = phone.recv(1024)    

    2.针对于(客户端/服务端)发送的连续的小的数据,对方会一次性接收.

    客户端

    import socket
    phone = socket.socket()
    phone.connect(('127.0.0.1', 8080))  # 拨号,写服务端的IP  (俩括号)
    phone.send(b'hello')              #先发送hello
    phone.send(b'word')               #紧接着在发送word
    while 1:
        server_data = phone.recv(1024)    #接收服务端的信息,1024限制的是最大接受的字节数
        print(server_data.decode('gbk'))
    phone.close()

    服务端

    import socket
    import subprocess
    # socket.SOCK_STREAM 流式协议 就是TCP协议
    phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  # 买电话
    phone.bind(('127.0.0.1', 8080))  # 绑定电话卡,写自己的IP  (俩括号)
    phone.listen(5)   #开机   5不是限制连接数,而是同一时刻只接受5个请求,可以不写,不写为默认,默认可以开启N个
    #运行后停在这里,下边不执行
    conn,addr = phone.accept()  #等待接电话 phone.accept()  conn和addr分别接收phone..accept()生成的两个参数
    print(addr)  #打印连接进来的客户端
    while 1 :
        client_data = conn.recv(1024)   #接受的字节数
        print(client_data)
        conn.send(client_data.upper()) #返回的信息
    conn.close()
    phone.close()
    
    
    ('127.0.0.1', 53961)       #服务端接收客户端的信息连在了一起
    b'helloword'

     

    客户端

    import socket
    import time
    phone = socket.socket()
    phone.connect(('127.0.0.1', 8080))  # 拨号,写服务端的IP  (俩括号)
    phone.send(b'hello')
    time.sleep(0.1)                #等待0.1秒在发送word
    phone.send(b'word')
    while 1:
        server_data = phone.recv(1024)    #接收服务端的信息,1024限制的是最大接受的字节数
        print(server_data.decode('gbk'))
    phone.close()

    服务端

    import socket
    import subprocess
    # socket.SOCK_STREAM 流式协议 就是TCP协议
    phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  # 买电话
    phone.bind(('127.0.0.1', 8080))  # 绑定电话卡,写自己的IP  (俩括号)
    phone.listen(5)   #开机   5不是限制连接数,而是同一时刻只接受5个请求,可以不写,不写为默认,默认可以开启N个
    #运行后停在这里,下边不执行
    conn,addr = phone.accept()  #等待接电话 phone.accept()  conn和addr分别接收phone..accept()生成的两个参数
    print(addr)  #打印连接进来的客户端
    while 1 :
        client_data = conn.recv(1024)   #接受的字节数
        print(client_data)
        conn.send(client_data.upper()) #返回的信息
    conn.close()
    phone.close()
     
    ('127.0.0.1', 53985)               #接受的字符分开了
    b'hello'
    b'word'

    解决粘包问题

    发送固定头部,固定头部包含(数据的总大小) + 数据

    struct模块  将一个数据,int 转化为固定的bytes

    import struct
    ret = struct.pack('i',151923212)    #将151923212 转换为固定的bytes类型
    print(ret,type(ret) ,len(ret),sep='
    ') #sep='
    ',将分隔符换为
    
    
    ret1 = struct.unpack('i',ret)
    print(ret1)
    
    b'x0c*x0e	'
    <class 'bytes'>
    4                         #转为固定的4字节
    (151923212,)

    解决粘包问题代码

    low版 

    一旦数据传入过大则struct模块报错, struct模块不能转译 较长的字符串

    服务端:

    将数据大小通过struct模块转为固定大小发给客户端

    import socket
    import subprocess
    import struct
    # socket.SOCK_STREAM 流式协议 就是TCP协议
    phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  # 买电话
    phone.bind(('127.0.0.1', 8080))  # 绑定电话卡,写自己的IP  (俩括号)
    phone.listen(5)   #开机   5不是限制连接数,而是同一时刻只接受5个请求,可以不写,不写为默认,默认可以开启N个
    #运行后停在这里,下边不执行
    conn,addr = phone.accept()  #等待接电话 phone.accept()  conn和addr分别接收phone..accept()生成的两个参数
    print(addr)  #打印连接进来的客户端
    while 1 :                            #以下为粘包解决方法
        try:
            client_data = conn.recv(1024)  # 接受的字节数
            obj = subprocess.Popen(client_data.decode('utf-8'),   #将接收的字节在本地shell执行 并返回结果
                                   shell=True,
                                   stdout=subprocess.PIPE,
                                   stderr=subprocess.PIPE,)
            ret = obj.stdout.read()           #正确结果
            ret1 = obj.stderr.read()          #错误结果
            ss = len(ret1 + ret)               #算返回结果的总长度
            ret2 = struct.pack('i',ss)         #通过struct将算返回结果的总长度变为固定长度的bytes类型
            conn.send(ret2)    #发送报头
            conn.send(ret)      #发送正确结果
            conn.send(ret1)    #发送错误结果
        except Exception:
            break
    conn.close()
    phone.close()

    客户端:

    客户端根据服务端发来的内容大小取内容

    import socket
    import time
    import struct
    
    phone = socket.socket()
    phone.connect(('127.0.0.1', 8080))  # 拨号,写服务端的IP  (俩括号)
    while 1:
        msg = input('>>>').strip()          #输入发往服务端的内容,如果是q退出,如果是空从新输入
        if msg.upper() == 'Q':
            break
        elif not msg:         #not + 空就是 True 执行continue 重新输入
            continue 
        phone.send(msg.encode('utf-8'))         #往服务端发送内容
        head = phone.recv(4)               #接收报头 报头大小为固定4字节
        head_size = struct.unpack('i', head)[0]          #直接将报头反解为服务端发送内容的长度,返回是元组,取第一个值
        datas = 0      #定义一个datas大小为0
        res = b''       #定义一个空的bytes类型的变量
        while datas < head_size:     #如果datas小于发送的内容的总长度为真
            data = phone.recv(1024)   #取1024字节
            res = res + data                #将取出的内容追加到res里
            datas += len(data)            #datas加上取出内容字节的大小
        print(res.decode('gbk'))         #读出res里的内容
    
    
    phone.close()
    uper版

    服务端:

    将服务端发送数据大小写到字典,

    将字典转为json,

    再将json转为字符串,

    取字符串长度给struct模块转为固定大小

    将固定大小,bytes类型的字典以及所有数据传给客户端

    import socket
    import subprocess
    import struct
    import json
    # socket.SOCK_STREAM 流式协议 就是TCP协议
    phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  # 买电话
    phone.bind(('127.0.0.1', 8080))  # 绑定电话卡,写自己的IP  (俩括号)
    phone.listen(5)   #开机   5不是限制连接数,而是同一时刻只接受5个请求,可以不写,不写为默认,默认可以开启N个
    #运行后停在这里,下边不执行
    conn,addr = phone.accept()  #等待接电话 phone.accept()  conn和addr分别接收phone..accept()生成的两个参数
    print(addr)  #打印连接进来的客户端
    while 1 :
        try:
            client_data = conn.recv(1024)  # 接受的字节数
            obj = subprocess.Popen(client_data.decode('utf-8'),
                                   shell=True,
                                   stdout=subprocess.PIPE,
                                   stderr=subprocess.PIPE,)
            ret = obj.stdout.read()
            ret1 = obj.stderr.read()
            ss = len(ret1 + ret)
            head_dict = {                         #定义一个字典,total_size的值为发送数据的大小,字典里可定义多个键值传递多种信息
                'total_size':ss
            }
            head_json = json.dumps(head_dict)       #将字典转为json格式
            head_bytes = head_json.encode('utf-8')  #再将json格式转为bytes格式
            ret2 = struct.pack('i',len(head_bytes))   #将转为bytes格式的长度通过struct转为固定字节
    
            conn.send(ret2)             #发送固定字节
            conn.send(head_bytes)     #发送bytes类型的字典
            conn.send(ret)                #发送内容
            conn.send(ret1)               
        except Exception:
            break
    conn.close()
    phone.close()

    客户端:

    将服务端发送的头部大小获取字典大小

    通过字典大小获取内容大小

    通过内容大小获取内容

    import socket
    import json
    import struct
    
    phone = socket.socket()
    phone.connect(('127.0.0.1', 8080))  # 拨号,写服务端的IP  (俩括号)
    while 1:
        msg = input('>>>').strip()
        if msg.upper() == 'Q':
            break
        elif not msg:
            continue
        phone.send(msg.encode('utf-8'))
        he = struct.unpack('i', phone.recv(4))[0]   #将头部的大小(phone.recv(4))通过struct模块解析出字典bytes类型的大小
        head_dic_bytes = phone.recv(he)             #通过解析出字典bytes类型的大小获取bytes类型字典的数据
        head_json = head_dic_bytes.decode('utf-8')  #将bytes数据反解为json类型
        head_doc = json.loads(head_json)            #反解json获得字典
        datas = 0
        res = b''
        while datas < head_doc['total_size']:       #将字典total_size键对应的内容大小的值取出,获得内容
            data = phone.recv(1024)
            res = res + data
            datas += len(data)
        print(res.decode('gbk'))
    
    
    phone.close()

    基于UDP的套接字协议

    服务端

    import socket
    udp_sk = socket.socket(type=socket.SOCK_DGRAM)   # (type=socket.SOCK_DGRAM)基于UDP的套接字TCP为socket.AF_INET, socket.SOCK_STREAM
    
    udp_sk.bind(('127.0.0.1', 10000))     #绑定服务器套接字
    
    while 1:
        msg, addr = udp_sk.recvfrom(1024) #tcp里的accept()里的recv() 是阻塞的 这里的recvfrom(1024)是非阻塞的
        print(msg.decode('utf-8'))        #打印内容
        udp_sk.sendto(b'hi',addr)         #返回给客户端的内容

    客户端

    import socket
    ip = ('127.0.0.1',10000)                            #创建个IP
    udp_sk=socket.socket(type=socket.SOCK_DGRAM)        #开启udp的socket
    while 1:
        sd = input('>>>').encode('utf-8')
        udp_sk.sendto(sd,ip)                             #给服务端发送内容
        back_msg,addr=udp_sk.recvfrom(1024)              #获取服务端回复的内容
        print(back_msg.decode('utf-8'),addr)             #打印服务端回复的内容
    udp_sk.close()
     
  • 相关阅读:
    D. Constructing the Array
    B. Navigation System
    B. Dreamoon Likes Sequences
    A. Linova and Kingdom
    G. Special Permutation
    B. Xenia and Colorful Gems
    Firetrucks Are Red
    java getInstance()的使用
    java 静态代理和动态代理
    java 类加载机制和反射机制
  • 原文地址:https://www.cnblogs.com/ywrj/p/10257535.html
Copyright © 2020-2023  润新知