zoukankan      html  css  js  c++  java
  • 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()
     
  • 相关阅读:
    var在PHP和JS中的使用
    修改PHP上传文件大小限制的方法
    Linux中tail指令详解
    drupal7 profile2模块获取个人信息
    drupal7 STMP邮件模块配置
    drupal读取mysql的longblob字段
    drupal7 自定义登录&找回密码页面,注意事项
    转 VS Code 快捷键大全,没有更全
    权力关进笼子里
    drupal的权限设置
  • 原文地址:https://www.cnblogs.com/ywrj/p/10257535.html
Copyright © 2011-2022 走看看