博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
高大上版解决粘包问题
阅读量:5162 次
发布时间:2019-06-13

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

recv工作原理

验证服务端缓冲区数据没有取完,又执行了recv执行,recv会继续取值。

server : 按照两个两个这样走

import socketphone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)phone.bind(('127.0.0.1',8080))phone.listen(5)conn,client_addr = phone.accept()from_client_data1 = conn.recv(2)print(from_client_data1)from_client_data2 = conn.recv(2)print(from_client_data2)from_client_data3 = conn.recv(1)print(from_client_data3)conn.close()phone.close()'''b'he'b'll'b'o''''

client

import socketphone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)phone.connect(('127.0.0.1',8080))phone.send('hello'.encode('utf-8'))phone.close()
验证服务端缓冲区取完了,又执行了 recv 操作,此时客户端 20 秒不关闭的前提下,recv 处于阻塞状态

serve

import socketphone =socket.socket(socket.AF_INET,socket.SOCK_STREAM)phone.bind(('127.0.0.1',8080))phone.listen(5)conn, client_addr = phone.accept()from_client_data = conn.recv(1024)print(from_client_data)print(111)conn.recv(1024) # 此时程序阻塞20秒左右,因为缓冲区的数据取完了,并且20秒内,客户端没有关闭。print(222)conn.close()phone.close()'''b'hello'111222'''

client

import socketimport timephone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)phone.connect(('127.0.0.1',8080))phone.send('hello'.encode('utf-8'))time.sleep(20)
验证服务端缓冲区取完了,又执行了recv,此时客户端处于关闭状态,则 recv会取到空字符串

server

import socketphone =socket.socket(socket.AF_INET,socket.SOCK_STREAM)phone.bind(('127.0.0.1',8080))phone.listen(5)conn, client_addr = phone.accept()from_client_data1 = conn.recv(1024)print(from_client_data1)from_client_data2 = conn.recv(1024)print(from_client_data2)from_client_data3 = conn.recv(1024)print(from_client_data3)conn.close()phone.close()'''b'hello'b''b'''''

client

import socketimport timephone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)phone.connect(('127.0.0.1',8080))phone.send('hello'.encode('utf-8'))phone.close()

高大上版解决粘包问题

1. 高大上版: 自定制报头dic = {'filename': XX, 'md5': 654654676576776, 'total_size': 26743}2. 高大上版:可以解决文件过大的问题.

server

import socketimport subprocessimport structimport jsonphone = socket.socket()phone.bind(('127.0.0.1',8848))phone.listen(2)# listen: 2 允许有两个客户端加到半链接池,超过两个则会报错while 1:    conn,addr = phone.accept()  # 等待客户端链接我,阻塞状态中    # print(f'链接来了: {conn,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'),                                   shell=True,                                   stdout=subprocess.PIPE,                                   stderr=subprocess.PIPE,                                   )            result = obj.stdout.read() + obj.stderr.read()            total_size = len(result)            # 1. 自定义报头            head_dic = {                'file_name': 'test1',                'md5': 6567657678678,                'total_size': total_size,            }            # 2. json形式的报头            head_dic_json = json.dumps(head_dic)            # 3. bytes形式报头            head_dic_json_bytes = head_dic_json.encode('utf-8')            # 4. 获取bytes形式的报头的总字节数            len_head_dic_json_bytes = len(head_dic_json_bytes)            # 5. 将不固定的int总字节数变成固定长度的4个字节            four_head_bytes = struct.pack('i',len_head_dic_json_bytes)            # 6. 发送固定的4个字节            conn.send(four_head_bytes)            # 7. 发送报头数据            conn.send(head_dic_json_bytes)            # 8. 发送总数据            conn.send(result)        except ConnectionResetError:            print('客户端链接中断了')            break    conn.close()phone.close()

client

import socketimport structimport jsonphone = socket.socket()phone.connect(('127.0.0.1',8848))while 1:    to_server_data = input('>>>输入q或者 Q 退出').strip().encode('utf-8')    if not to_server_data:        # 服务端如果接受到了空的内容,服务端就会一直阻塞中,所以        # 无论哪一方发送内容时,都不能为空发送        print('发送内容不能为空')        continue    phone.send(to_server_data)    if to_server_data.upper() == b"Q":        break    # 1.接收固定长度的 4 个字节    head_bytes = phone.recv(4)    # 2.获得 bytes 类型字典的总字节数    len_head_dic_json_bytes = struct.unpack('i',head_bytes)[0]    # 3.接收 bytes 形式的 dic数据    head_dic_json_bytes = phone.recv(len_head_dic_json_bytes)    # 4.转化为json 类型 dic    head_dic_json = head_dic_json_bytes.decode('utf-8')    # 5.转化为字典形式的报头    head_dic = json.loads(head_dic_json)    '''    head = {    'file_name': 'test1',    'md5':2345778832434,    'total_size':total_size    }    '''    total_data = b''    while len(total_data) < head_dic['total_size']:        total_data += phone.recv(1024)    print(total_data.decode('utf-8'))phone.close()

基于udp协议的socket 通信

server

# 1. 基于udp协议的socket无须建立管道,先开启服务端或者客户端都行.# 2. 基于udp协议的socket接收一个消息,与发送一个消息都是无连接的.# 3. 只要拿到我的ip地址和端口就都可以给我发消息,我按照顺序接收消息.
import socketserver = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)# 基于网络的UDP协议的socketserver.bind(('127.0.0.1',9000))while 1:    from_client_data = server.recvfrom(1024)  # 阻塞,等待客户来消息    print(f'\033[1;35;0m来自客户端{from_client_data[1]}: {from_client_data[0].decode("utf-8")} \033[0m')    to_client_data = input('>>>').strip()    server.sendto(to_client_data.encode('utf-8'),from_client_data[1])

client

import socketclient = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)# 基于网络的UDP协议的socketwhile 1:    to_server_data = input('>>>:').strip()    client.sendto(to_server_data.encode('utf-8'),('127.0.0.1',9000))    # data,addr = client.recvfrom(1024)    # print(f'来自服务端{addr}消息:{data.decode("utf-8")}')

转载于:https://www.cnblogs.com/hualibokeyuan/p/11366702.html

你可能感兴趣的文章
C++ 面向对象 类成员函数this指针
查看>>
NSPredicate的使用,超级强大
查看>>
自动分割mp3等音频视频文件的脚本
查看>>
判断字符串是否为空的注意事项
查看>>
布兰诗歌
查看>>
js编码
查看>>
Pycharm Error loading package list:Status: 403错误解决方法
查看>>
steps/train_sat.sh
查看>>
转:Linux设备树(Device Tree)机制
查看>>
iOS 组件化
查看>>
(转)Tomcat 8 安装和配置、优化
查看>>
(转)Linxu磁盘体系知识介绍及磁盘介绍
查看>>
tkinter布局
查看>>
命令ord
查看>>
Sharepoint 2013搜索服务配置总结(实战)
查看>>
博客盈利请先考虑这七点
查看>>
使用 XMLBeans 进行编程
查看>>
写接口请求类型为get或post的时,参数定义的几种方式,如何用注解(原创)--雷锋...
查看>>
【OpenJ_Bailian - 2287】Tian Ji -- The Horse Racing (贪心)
查看>>
Java网络编程--socket服务器端与客户端讲解
查看>>