recv原理
1.验证服务端缓冲区数据没有取完,又执行了recv执行,recv会继续取值。
# 服务器: import socket phone =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() # 客户端: import socket import time phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM) phone.connect(('127.0.0.1',8080)) phone.send('hello'.encode('utf-8')) time.sleep(20) phone.close()
2.验证服务端缓冲区取完了,又执行了recv执行,此时客户端20秒内不关闭的前提下,recv处于阻塞状态
# 服务端: import socket phone =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() # 客户端: import socket import time phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM) phone.connect(('127.0.0.1',8080)) phone.send('hello'.encode('utf-8')) time.sleep(20) phone.close()
3. 服务端缓冲区的数据取完之后,又执行了recv执行,此时客户端处于关闭状态,则recv会取到空字符串。
# 服务端: import socket phone =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() # 客户端: import socket import time phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM) phone.connect(('127.0.0.1',8080)) phone.send('hello'.encode('utf-8')) phone.close()
用户登录功能实现:
用户登录作业用tcp协议下的socket完成: 1,服务端: 等待客户端来发送数据:用户名,密码。 本地文件汇总查看用户名密码是否合法。 合法:登录成功。 否则:用户名或者密码错误。 2,客户端: 用户输入: 用户名,密码。 发送到服务端进行校验。 服务端: import socket server = socket.socket() server.bind(('127.0.0.1',9045)) server.listen(5) try: while 1: conn,addr = server.accept() flag = 0 while not flag: user_pwd = conn.recv(1024).decode('utf-8') with open ('userinfo',encoding='utf-8')as f: for i in f: if i.strip() == user_pwd: conn.send('success'.encode('utf-8')) flag =1 break else: conn.send('failed'.encode('utf-8')) conn.close() finally: server.close() 客户端: import socket client = socket.socket() client.connect(('127.0.0.1',9045)) while 1: user = input('用户名>>>').strip() pwd = input('密码>>>').strip() user_pwd = user + '|' + pwd client.send(user_pwd.encode('utf-8')) result = client.recv(1024) if result == b'success': print('登录成功') break else: print('用户名或密码错误') client.close()
上传功能实现:
服务端: import socket import json import struct import os server = socket.socket() server.bind(('127.0.0.1',9345)) server.listen() file_base_path = 'D:上传下载' conn,addr = server.accept() head_dic_json_bytes_struct = conn.recv(4) #接收4个字节 head_dic_json_bytes_len = struct.unpack('i',head_dic_json_bytes_struct)[0] # 转换成int长度 head_dic_json_bytes = conn.recv(head_dic_json_bytes_len) # 接收报头字典的字节 head_dic_json = head_dic_json_bytes.decode('utf-8') # 转换成json字符串 head_dic = json.loads(head_dic_json) # 转换成报头字典 file_path = os.path.join(file_base_path,head_dic['file_name']) with open(file_path,mode='wb')as f: total_data_size = 0 while total_data_size < head_dic['file_size']: every_data = conn.recv(1024) f.write(every_data) total_data_size += len(every_data) conn.close() server.close() 客户端: import socket import json import struct import os client = socket.socket() client.connect(('127.0.0.1',9345)) #1.自定制报头 head_dic = { 'file_name':'今日总结.mp4', 'file_path':r'F:workspace_pythons19day30文件上传今日总结.mp4', 'file_size':None } head_dic['file_size'] = os.path.getsize(head_dic['file_path']) head_dic_json =json.dumps(head_dic) #转换成json字符串 head_dic_json_bytes = head_dic_json.encode('utf-8') #将字符串转换成字节 head_dic_json_bytes_struct = struct.pack('i',len(head_dic_json_bytes)) #转换成4个字节 client.send(head_dic_json_bytes_struct) client.send(head_dic_json_bytes) with open(head_dic['file_name'],mode='rb')as f1: total_data_size = 0 while total_data_size < head_dic['file_size']: every_data = f1.read(1024) client.send(every_data) total_data_size += len(every_data) client.close()
基于UDP协议的socket
TCP协议有回执,丢包跟网络相关(网络断开或者遭遇抓包)
UDP协议无阻塞,没有粘包现象
服务端: import socket server = socket.socket(type=socket.SOCK_DGRAM) # udp协议 server.bind(('127.0.0.1',8848)) try: while 1: client_data, client_address = server.recvfrom(1024) print('来自%s消息: %s'%(client_address,client_data.decode('utf-8'))) to_client_data = input('回复:').strip().encode('utf-8') server.sendto(to_client_data,client_address) finally: server.close() 客户端: import socket client = socket.socket(type=socket.SOCK_DGRAM) # udp协议 while 1: to_server_data = input('给服务端发送:').strip().encode('utf-8') client.sendto(to_server_data,('127.0.0.1',8848)) server_data, server_address = client.recvfrom(1024) print(' 33[1;35;0m来自%s的信息: %s 33[0m' %(server_address,server_data.decode('utf-8')))
socketserver
服务端: import socketserver class MyServer(socketserver.BaseRequestHandler): # MyServer类名不固定,但是必须要继承socketserver.BaseRequestHandler def handle(self): # handle方法名固定写法 # self.request conn while 1: from_client_data = self.request.recv(1024) print(from_client_data.decode('utf-8')) to_client_data = input('>>>').strip().encode('utf-8') self.request.send(to_client_data) if __name__ == '__main__': ip_port = ('127.0.0.1', 8888) socketserver.TCPServer.allow_reuse_address = True server = socketserver.ThreadingTCPServer(ip_port,MyServer) # 固定写法((ip地址,端口),MyServer) # 源码显示:上一行代码: 创建socket对象,绑定ip地址和端口,监听 server.serve_forever() 客户端: import socket client = socket.socket() client.connect(('127.0.0.1',8888)) while 1: to_server_data = input('>>>').strip().encode('utf-8') client.send(to_server_data) from_server_data = client.recv(1024).decode('utf-8') print(from_server_data)