博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
python笔记8 socket(TCP) subprocess模块 粘包现象 struct模块 基于UDP的套接字协议
阅读量:4345 次
发布时间:2019-06-07

本文共 9757 字,大约阅读时间需要 32 分钟。

socket

基于tcp协议socket

服务端

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

 

服务端

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

服务端

import socketimport 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 structret = struct.pack('i',151923212)    #将151923212 转换为固定的bytes类型print(ret,type(ret) ,len(ret),sep='\n') #sep='\n',将分隔符换为\nret1 = struct.unpack('i',ret)print(ret1)b'\x0c*\x0e\t'
4 #转为固定的4字节(151923212,)

解决粘包问题代码

low版 

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

服务端:

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

import socketimport subprocessimport 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:        breakconn.close()phone.close()

客户端:

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

import socketimport timeimport structphone = 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 socketimport subprocessimport structimport 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:        breakconn.close()phone.close()

客户端:

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

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

通过内容大小获取内容

import socketimport jsonimport structphone = 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 socketudp_sk = socket.socket(type=socket.SOCK_DGRAM)   # (type=socket.SOCK_DGRAM)基于UDP的套接字TCP为socket.AF_INET, socket.SOCK_STREAMudp_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 socketip = ('127.0.0.1',10000)                            #创建个IPudp_sk=socket.socket(type=socket.SOCK_DGRAM)        #开启udp的socketwhile 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()

 

 

 

 

 

转载于:https://www.cnblogs.com/ywrj/p/10257535.html

你可能感兴趣的文章
论工作的价值
查看>>
Heritrix3.x主配置文件(crawler-beans.cxml)详解
查看>>
最大子矩阵的一种实现方法
查看>>
RTEMS开发环境搭建——基于FreeBSD系统
查看>>
python测试开发django-39.xadmin详情页面布局form_layout
查看>>
云服务器(uCloud)部署java web项目(七) apacheHTTPS转发到tomctHTTPS
查看>>
IOS开发中单例模式使用详解
查看>>
Scriptcase在线试用开发环境
查看>>
疯狂的预编译加类型推导能孵化什么吗?
查看>>
[置顶] Android系统五大布局详解Layout
查看>>
IronRuby - 编写自动化测试脚本
查看>>
禁止CloudStack删除Xenserver原有虚拟机
查看>>
How Many Elements Are in the Power Set?
查看>>
eclipse突然启动不了问题
查看>>
Python_函数
查看>>
下游系统访问思考
查看>>
TreeView绑定数据库数据
查看>>
StringTokenizer
查看>>
移动互联网产品设计的核心要素有哪些?
查看>>
经典SQL语句大全
查看>>