python基础--socket套接字、粘包问题
本地回环地址:127.0.0.1
简易版服务端:
import socket server = socket.socket() # 就比如买了一个手机 server.bind(("127.0.0.1",8080)) # bind中绑定的是IP地址和端口号,注意是一个元组,就比如,将手机卡,插入了手机 server.listen(5) # 半连接池,最大等待连接数为5个,就比如开机 conn,address = server.accept() # 接听电话等着别人给你打电话 date = conn.recv(1024) # 听别人说话,接收1023个字节数 print(date) conn.send(b"hello") # 给别人回话 conn.close() # 挂断电话 server.close() # 关机
简易版客户端:
import socket client = socket.socket() #拿电话 client.connect(("127.0.0.1",8080)) #绑定的是IP地址和端口号,也是一个元组 拨号 client.send(b"hello") # 对别人发消息 date = client.recv(1024) #接收别人说话,没次接收1024个字节 print(date) client.close() # 挂电话
注意:在写服务端和客户端的时候send和recv需要一一对应,不能再两边都出现,recv是跟内存要数据,至于数据的来源无需考虑
粘包:
服务端:
import socket server = socket.socket() # 就比如买了一个手机 server.bind(("127.0.0.1",8088)) # bind中绑定的是IP地址和端口号,注意是一个元组,就比如,将手机卡,插入了手机 server.listen(5) # 半连接池,最大等待连接数为5个,就比如开机 conn,address = server.accept() # 接听电话等着别人给你打电话 date = conn.recv(1024) # 听别人说话,接收1023个字节数 print(date) date = conn.recv(1024) # 听别人说话,接收1023个字节数 print(date) conn.close() # 挂断电话 server.close() # 关机
客户端:
import socket client = socket.socket() #拿电话 client.connect(("127.0.0.1",8088)) #绑定的是IP地址和端口号,也是一个元组 拨号 client.send(b"hello") # 对别人发消息 client.send(b"hello") # 对别人发消息 client.close() # 挂电话
服务端打印结果:
b'hellohello'
这是因为tcp协议会将时间间隔短的,和文件大小小的会一次打包发送给对方
解决粘包问题:
struct模块:
import struct print("--------------------------1--------------------------") msg = "asdasdasdasdasd" print("原字符串的长度") print(len(msg)) handler = struct.pack("i",len(msg)) print("创建报头的长度") print(len(handler)) res = struct.unpack("i",handler)[0] print("解报头过后的长度") print(res) print("--------------------------2--------------------------") msg1 = "asdasdasdasdasdasdasdasd" print("原字符串的长度") print(len(msg1)) handler1 = struct.pack("i",len(msg1)) print("创建报头的长度") print(len(handler1)) res1 = struct.unpack("i",handler1)[0] print("解报头过后的长度") print(res1) """ --------------------------1-------------------------- 原字符串的长度 15 创建报头的长度 4 解报头过后的长度 15 --------------------------2-------------------------- 原字符串的长度 24 创建报头的长度 4 解报头过后的长度 24 """
我们可以将报头发过去,然后解报头,就可以知道原来数据的大小,如果这个字节大小比我们接受的大,我们就可以一直让它接收,直到接收完成为止,
服务端:
import json import os import socket import struct server_path = r'/Users/mac/Documents/client-server/server_movie' server = socket.socket() ip_port = ('127.0.0.1', 8080) server.bind(ip_port) server.listen(5) conn, addr = server.accept() while 1: head_len = conn.recv(4) head_len = struct.unpack('i', head_len)[0] json_head = conn.recv(head_len).decode('utf-8') head = json.loads(json_head) file_size = head['file_size'] with open(os.path.join(server_path, head['file_name']), 'wb') as f: while file_size: if file_size >= 1024: content = conn.recv(1024) f.write(content) file_size -= 1024 else: content = conn.recv(file_size) f.write(content) break
客户端:
import os import socket import json import struct client = socket.socket() ip_port = ('127.0.0.1', 8080) client.connect(ip_port) head = { 'file_path': r'/Users/mac/Documents/client-server/client_movie', 'file_name': None, 'file_size': None } movie_list = os.listdir(head['file_path']) while 1: for i, m in enumerate(movie_list, 1): print('%s --> %s' % (i, m)) choice = input('please input movie number:>>').strip() if choice.isdigit(): choice = int(choice) if choice in range(1, len(movie_list) + 1): movie_name = movie_list[choice - 1] head['file_name'] = movie_name head['file_size'] = os.path.getsize(os.path.join(head['file_path'], head['file_name'])) json_head = json.dumps(head).encode('utf-8') bytes_head = len(json_head) pack_head = struct.pack('i', bytes_head) client.send(pack_head) client.send(json_head) file_size = head['file_size'] with open(os.path.join(head['file_path'], head['file_name']), 'rb') as f: while file_size: if file_size >= 1024: content = f.read(1024) client.send(content) file_size -= 1024 else: content = f.read(file_size) client.send(content) print("finish") break else: print('index out of range') else: print('input number...')