python 30 基于TCP协议的socket通信

python 30 基于TCP协议的socket通信,第1张

概述目录 1. 单对单循环通信 2. 循环连接通信:可连接多个客户端 3. 执行远程命令 4. 粘包现象 4.1 socket缓冲区 4.2 出现粘包的情况: 4.3 解决粘包现象 bytes 1. 单对单循环通信 ? send() 和recv()不是一一对应的。 # 服务端 server.py import socketphone = socket.socket()phone.bind =

目录

1. 单对单循环通信 2. 循环连接通信:可连接多个客户端 3. 执行远程命令 4. 粘包现象 4.1 socket缓冲区 4.2 出现粘包的情况: 4.3 解决粘包现象 bytes 1. 单对单循环通信

? send() 和recv()不是一一对应的。

# 服务端 server.py  import socketphone = socket.socket()phone.bind = (('127.0.0.1',8888))  # 绑定本地回环地址/端口号phone.Listen()  # 开始监听conn,addr = phone.accept()  # 等待连接print(f"连接{addr}成功!")while 1:    try:        from_clIEnt_data = conn.recv(1024)        if from_clIEnt_data.upper() == b'Q':   # 字节bytes Q            print('客户端已正常退出!')            break        print(f"来自客户端{addr}的消息:{from_clIEnt_data.decode('utf-8')}")                to_server_data = input('>>>').strip().encode('utf-8')        phone.send(to_server_data)    except ConnectionresetError:        print('客户端连接中断!')        breakconn.close()phone.close()
# 客户端 clIEnt.pyimport socketphone = socket.socket()phone.connect(('127.0.0.1',8888))while 1:    to_server_data = input('>>>').strip().encode('utf-8')    if not to_server_data:        print('输入内容不能为空!')        continue    phone.send(to_server_data)    if to_server_data.upper() == b'Q':        break    from_server_data = phone.recv(1024)    print(f"来自服务端的消息:{from_server_data.decode('utf-8')}")    phone.close()
2. 循环连接通信:可连接多个客户端
# 服务端循环接收连接import socketphone = socket.socket()phone.bind(('127.0.0.1',8848))phone.Listen()while 1:    conn,addr = phone.accept()      # 循环可接收客户端    print(f'与客户端{addr}连接成功!')    while 1:        try:            from_clIEnt_data = conn.recv(1024)            if from_clIEnt_data.upper() == b'Q':                print('客户端已退出!')                break            print(f"来自客户端的消息:{from_clIEnt_data.decode('utf-8')}")            to_clIEnt_data = input('>>>').strip().encode('utf-8')            conn.send(to_clIEnt_data)        except ConnectionresetError:            print('客户端连接中断!')            break    conn.close()phone.close()
# 客户端 clIEntimport socketphone = socket.socket()phone.connect(('127.0.0.1',8848))while 1:    to_server_data = input('>>>').strip().encode('utf-8')    if not to_server_data:        print('输入内容不能为空!')        continue    phine.send(to_server_data)    if to_server_data.upper() == b'Q':        break    from_server_data = phone.recv(1024)    print(f"来自服务端的消息:{from_server_data.decode('utf-8')}")phone.close
3. 执行远程命令
# 使用subproess模块 可像 *** 作系统cmd一样执行命令import subprocessobj = subprocess.Popen('dir',shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE,)print(obj.stdout.read().decode('gbk'))  # 正确命令print(obj.stderr.read().decode('gbk'))  # 错误命令# 如果是正确的命令,那么错误命令会输出空字符。# shell: 命令解释器,相当于调用cmd 执行指定的命令。# stdout:正确结果丢到管道中。# stderr:错了丢到另一个管道中。# windows *** 作系统的默认编码是gbk编码。
# 在服务端 增加subprocess模块,import subprocessimport socketphone = socket.socket(socket.AF_INET,socket.soCK_STREAM)phone.bind(('127.0.0.1',8888))phone.Listen()while 1:    conn,addr = phone.accept()    print(f'连接{addr}成功!')    while 1:        try:            from_clIEnt_data = conn.recv(1024)            if from_clIEnt_data.upper() == b'Q':                print('客户端正常退出!')                break            # print(f"来自客户端{addr}的消息:{from_clIEnt_data.decode('utf-8')}")            obj = subprocess.Popen(from_clIEnt_data.decode("utf-8"),)            to_clIEnt_data = obj.stdout.read() + obj.stderr.read()            # subprocess使用当前系统默认编码,得到结果为bytes类型,在windows下需要用gbk解码            conn.send(to_clIEnt_data) # 此时是gbk的bytes的类型        except ConnectionresetError:            print('客户端连接中断!')            break    conn.close()phone.close()
# 客户端 clIEntimport socketphone = socket.socket()phone.connect(('127.0.0.1',8888))while 1:    to_server_data = input('>>>').strip().encode('utf-8')    if not to_server_data:        print('输入内容不能为空!')        continue    phone.send(to_server_data)    if to_server_data.upper() == b'Q':        break    from_server_data = phone.recv(1024)    print(f"{from_server_data.decode('gbk')}")  # 需gbk解码phone.close()
4. 粘包现象 4.1 socket缓冲区

? 每个socket,都会有两个缓冲区,输入/输出缓冲区。过程如上图,send()结束后,会马上进入recv()状态(有阻塞)。

? 作用:1. 展示存储一些数据;2. 如果网络有波动,缓冲区会保护数据的收发稳定、匀速。

? 缺点:是会造成粘包的现象之一。

4.2 出现粘包的情况:

? 1. 如果客户端send() 数据超过recv() 设定的字节数,会先接收最大限制的字节数,当第二次send() 数据时,recv() 会将上次遗留的数据接收,产生粘包现象。

连续短暂send() 多次(数据量较小),数据会统一发送出去,产生粘包。

(Nagle算法)

4.3 解决粘包现象
#思路:    服务端发出send() 数据有10000字节,客户端接收数据时,循环recv()接收,每次(至多)接收1024字节,直至将所有的字节全部接收完毕,将接收的数据拼接在一起,编码打印出。    #遇到的问题:    1. recv() 次数无法确定。    客户端先接收总数据的一个长度,然后再循环recv 控制循环次数,只有接收的数据长度 < 总数据长度,就会一直接收。(先发总数据长度,再发总数据)    2.获取总数据的长度是 int 类型,先要转换成 bytes 类型,再发出,但是总数据的长度转化成的 bytes类型的字节数是不固定的。    int:376 ——> str(376):'376' ——> bytes:b'376'  (长度为3)    int:4558 ——> str(4558):'4558' ——> bytes:b'4558'  (长度为4)     解决:将不固定长度的int类型转换成固定长度的bytes,并且还可以反解回来。(用来制定固定长度的报头)
# 将不固定长度的int类型转换成固定长度的bytesimport structret = struct.pack('i',376) # 将int 376转换成固定4个长度的bytes字节# i 默认长度为 4; q 默认为8print(ret,type(ret),len(ret))ret1 = struct.unpack('i',ret)[0]    # 是元组形式, 反解成int型print(ret1,type(ret1))# 但是通过struct 处理不能处理太大数据ret = struct.pack('l',4323241232132324)print(ret,len(ret))  # 报错
# low版解决粘包现象# 服务端serverimport socketimport subprocessimport structphone = socket.socket()phone.bind(('127.0.0.1',8888))phone.Listen()while 1:    conn,addr = phone.accept()    print(f'与客户端{addr}连接')    while 1:        try:            from_clIEnt_data = conn.recv(1024)            if from_clIEnt_data.upper() == b'Q':                print('客户端已退出!')                break            obj = subprocess.Popen(from_clIEnt_data.decode("utf-8"),)            total_data = obj.stdout.read() + obj.stderr.read()            conn.send(struct.pack('i',len(total_data)))  # 发出 总数据长度的bytes类型            print(len(total_data))            conn.send(total_data)   # 发出总数据 gbk编码的字节        except ConnectionresetError:            print('与客户端连接中断!')            break    conn.close()phone.close()
# 客户端clIEntimport socketimport structphone = socket.socket()phone.connect(('127.0.0.1',8888))while 1:    to_server_data = input('>>>').strip().encode('utf-8')    if not to_server_data:        print('内容不能为空!')        continue    phone.send(to_server_data)    if to_server_data.upper() == b'Q':        break    head_bytes = phone.recv(4)   # 接收总数据长度的bytes    head_int = struct.unpack('i',head_bytes)[0]  # 反解成int    print(head_int)    data = b''      # 定义一个空字节    while len(data) < head_int:        data = data + phone.recv(1024)    print(len(data))    print(f"{data.decode('gbk')}")  # 终端是 gbk 编码的phone.close()
bytes

? 用于网络传输、文件存储时。

能够保持数据原本类型。

总结

以上是内存溢出为你收集整理的python 30 基于TCP协议的socket通信全部内容,希望文章能够帮你解决python 30 基于TCP协议的socket通信所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/1191779.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-03
下一篇 2022-06-03

发表评论

登录后才能评论

评论列表(0条)

保存