· socket不仅支持TCP协议,还支持udp协议。
· socket通信只做两件事:发送数据(send)和接收数据(receive)
· 实现通信要有IP+端口
· 先要有服务端(接收端),再有客户端(发送端)
示例代码1:
服务端:
import socket server = socket.socket() server.bind(('localhost',9338)) #绑定要监听的端口,这里只能传入一个参数(包含IP和端口),因此传入一个元组。 server.listen(9338) #监听(端口) con,addr = server.accept() #等待数据传输过来,接收两个值,con就是客户端连接过来而在服务端为其生成的一个连接实例,addr是客户端IP和端口。 data = con.recv(1024) #接收1024字节数据 print('recv:',data) con.send(data.upper()) #将接收的数据大写处理后发送出去 server.close() # 输出: recv: b'hello world!'
客户端:
import socket client = socket.socket() #声明socket类型,同时生成socket连接对象。 client.connect(('localhost',9338)) client.send(b'hello world') #python3中只能传输byte类型数据 data = client.recv(1024) print('recv:',data) client.close() #输出: recv: b'HELLO WORLD!'
代码饭粒2(实现多重连接+多次通信):
server端:
#!/usr/bin/env python # -*- coding: utf-8 -*- import socket server = socket.socket() server.bind(('localhost',9338)) server.listen(3) while True: con, addr = server.accept() while True: data = con.recv(1024) if not data: #接收数据为空时判为客户端断开 print('Client has lost...') break print('recv:',data.decode()) con.send(data.upper()) #将接收的数据大写处理后发送出去 server.close()
client端:
#!/usr/bin/env python # -*- coding: utf-8 -*- import socket client = socket.socket() client.connect(('localhost',9338)) while True: msg = input("Please input message:") if len(msg) == 0:continue # 如果信息为空就不往下执行 client.send(msg.encode('utf-8')) data = client.recv(1024) if not data: #接收数据为空时判为服务端断开 print('Server has lost...') break print('recv:',data.decode()) client.close()
代码饭粒3(执行server端Linux的命令并返回给client端):
server端:
#!/usr/bin/env python # -*- coding: utf-8 -*- import socket,os server = socket.socket() #声明socket类型,同时生成socket连接对象。 server.bind(('localhost',9338)) #绑定要监听的端口,这里只能传入一个参数(包含IP和端口),因此传入一个元组。 server.listen(3) #监听(最大连接数) while True: con, addr = server.accept() # 等待数据传输过来,接收两个值,con就是客户端连接过来而在服务端为其生成的一个连接实例,addr是客>户端IP和端口。 while True: data = con.recv(1024) #接收1024字节数据 if not data: print('Client has lost...') break print('recv:',data.decode()) #接收中文要解码 res = os.popen(data.decode()).read() con.send(res.encode('utf-8')) # 将接收的命令执行后发送 #con.send(data.upper()) #将接收的数据大写处理后发送出去 # con.send('hi,你好哇!'.encode('utf-8')) #发送中文要先转码 server.close()
client端:
#!/usr/bin/env python # -*- coding: utf-8 -*- import socket client = socket.socket() client.connect(('localhost',9338)) while True: msg = input("Please input message:") if len(msg) == 0:continue # 如果信息为空就不往下执行 client.send(msg.encode('utf-8')) data = client.recv(1024) if not data: print('Server has lost...') break print('recv:',data.decode()) client.close()
代码范例4:socket传输大数据
server
#!/usr/bin/env python # -*- coding: utf-8 -*- import socket,os server = socket.socket() server.bind(("localhost",9339)) server.listen(3) while True: con, addr = server.accept() # 等待数据传输过来,接收两个值,con就是客户端连接过来而在服务端为其生成的一个连接实例,addr是客>户端IP和端口。 print('client IP: ',addr) while True: data = con.recv(1024) #接收1024字节数据 if not data: print('Client has lost...') break print('recv:',data.decode()) #接收中文要解码 res = os.popen(data.decode()).read() # 将接收的命令执行后发送 if len(res) == 0: res = 'cmd has no output...' con.send(str(len(res.encode())).encode('utf-8')) # 发送命令输出的大小 con.recv(1024) con.send(res.encode('utf-8')) server.close()
client:
#!/usr/bin/env python # -*- coding: utf-8 -*- import socket client = socket.socket() client.connect(('localhost',9339)) while True: msg = input("Please input message:") if len(msg) == 0:continue # 如果信息为空就不往下执行 client.send(msg.encode('utf-8')) data_size = client.recv(1024) # 接收命令输出的大小 print('cmd output size: ',data_size.decode()) client.send(b'I am readly to recive...') recv_size = 0 # 接收的大小 get_data = b'' # 接收的数据 while len(get_data) < int(data_size.decode()): data = client.recv(1024) if not data: print('Server has lost...') break recv_size += len(data) # 每次收到的长度可能小于1024,所以要用len判断 get_data += data # print('recv:', data.decode()) else: print("cmd output recive done...",recv_size) print(get_data.decode()) client.close()
代码饭粒5:实现文件传输文件(FTP),并验证文件合法性(md5)
server:
#!/usr/bin/env python # -*- coding: utf-8 -*- import socket,os,hashlib server = socket.socket() server.bind(("0.0.0.0",9339)) server.listen(3) while True: con, addr = server.accept() print('client IP: ',addr) while True: data = con.recv(1024) if not data: print('Client has lost...') break cmd,filename = data.decode().split() if os.path.isfile(filename): f = open(filename,'rb') m = hashlib.md5() file_size = os.stat(filename).st_size con.send(str(file_size).encode()) # send file size con.recv(1024) # wait for ack for line in f: m.update(line) con.send(line) file_md5 = m.hexdigest() con.send(file_md5.encode()) # send md5 print("file md5:",m.hexdigest()) server.close()
client:
#!/usr/bin/env python # -*- coding: utf-8 -*- import socket,hashlib client = socket.socket() client.connect(('localhost',9339)) while True: cmd = input("Please input message:").strip() if len(cmd) == 0:continue if cmd.startswith("get"): client.send(cmd.encode()) file_size = int(client.recv(1024).decode().strip()) print("File size: ",file_size) client.send(b"ready to recv file.") received_size = 0 filename = cmd.split()[1] f = open(filename + '.new','wb') m = hashlib.md5() while received_size < file_size: if file_size - received_size > 1024: # 解决粘包问题 size = 1024 else: size = file_size - received data = client.recv(size) m.update(data) received_size += len(data) f.write(data) else: print("file receive done",received_size,file_size) f.close() recv_file_md5 = m.hexdigest() print('received file md5: ',recv_file_md5) client.send(b'I am ready to recv file md5...') source_file_md5 = client.recv(1024).decode().strip() print('source file md5: ',source_file_md5) if recv_file_md5 != source_file_md5: print("Critical: The md5 value of the received file is different from the source file!") else: print("The md5 value of the received file is the same as the source file.") client.close()
附:解决粘包问题方法
1、time.sleep(0.5),经多次测试,让服务器程序sleep 至少0.5就会造成缓冲区超时;
2、服务器端每发送一个数据给客户端,就立刻等待客户端进行回应,即调用 conn.recv(1024);
3、判断接收数据大小,recv()时直接在括号内指定接收的数据大小。