网络编程-套接字(socket)
一、Socket(套接字)
★注意点:
① 127.0.0.1本机地址回环:只能识别自己,其他人无法访问
② send与recv对应,不要出现两边是相同的情况,recv是跟内存要数据,无需考虑
③ tcp特点是会将数据量比较小的并且时间间隔比较短的数据,一次性打包发送给对方
1 import socket 2 3 server = socket.socket() # 买手机 不传参数默认用的就是TCP协议 4 server.bind(('127.0.0.1',8080)) # bind((host,port)) 插电话卡 绑定ip和端口 5 server.listen(5) # 开机 半连接池 6 7 conn, addr = server.accept() # 接听电话 等着别人给你打电话 8 data = conn.recv(1024) # 听别人说话 接收1024个字节数据 9 conn.send(b'hello baby~') # 给别人回话 10 11 conn.close() # 挂电话 12 server.close() # 关机
1 import socket 2 3 client = socket.socket() # 拿电话 4 client.connect(('127.0.0.1',8080)) # 拨号 写的是对方的ip和port 5 6 client.send(b'hello world!') # 对别人说话 7 data = client.recv(1024) # 听别人说话 8 print(data) 9 10 client.close() # 挂电话
二、TCP粘包问题
我们基于TCP协议写一个远程命令操控
1 from socket import * 2 import subprocess 3 4 1024 5 6 tcp_socket_server=socket(AF_INET,SOCK_STREAM) 7 tcp_socket_server.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) 8 tcp_socket_server.bind(('127.0.0.1',8888)) 9 tcp_socket_server.listen(5) 10 11 while True: 12 conn,addr=tcp_socket_server.accept() 13 14 while True: 15 cmd=conn.recv(1024) 16 if len(cmd) == 0:break 17 18 res=subprocess.Popen(cmd.decode('utf-8'),shell=True, 19 stdout=subprocess.PIPE, 20 stdin=subprocess.PIPE, 21 stderr=subprocess.PIPE) 22 23 stderr=res.stderr.read() 24 stdout=res.stdout.read() 25 conn.send(stderr) 26 conn.send(stdout)
1 import socket 2 3 s=socket.socket(socket.AF_INET,socket.SOCK_STREAM) 4 res=s.connect_ex(('127.0.0.1',8888)) 5 6 while True: 7 msg=input('>>: ').strip() 8 if len(msg) == 0:continue 9 if msg == 'quit':break 10 11 s.send(msg.encode('utf-8')) 12 act_res=s.recv(1024) 13 14 print(act_res.decode('utf-8'),end='')
同时执行多条命令之后,得到的结果可能只有一部分,在执行其他命令的时候又接收到之前执行的另外一部分结果,这种现象就是粘包。
三、解决粘包问题
问题的根源在于,接收端不知道发送端将要传送的字节流的长度,所以解决粘包的方法就是围绕,如何让发送端在发送数据前,把自己将要发送的字节流总大小让接收端知晓,然后接收端来一个while循环接收完所有数据。
1 import json 2 import socket 3 import struct 4 import subprocess 5 6 server = socket.socket() 7 server.bind(('127.0.0.1',8080)) 8 server.listen(5) 9 10 while True: 11 conn,addr = server.accept() 12 while True: 13 try: 14 msg = conn.recv(1024).decode('utf-8') 15 if not msg : break 16 obj = subprocess.Popen(msg,shell = True,stdout = subprocess.PIPE,stderr = subprocess.PIPE) 17 res = obj.stdout.read() + obj.stderr.read() 18 dict = {'name':'Spenser','file_size':len(res),'info':'to be a better man'} 19 json_dict = json.dumps(dict) 20 #1.制作字典报头 21 header = struct.pack('i',len(json_dict)) 22 #2.传送字典报头 23 conn.send(header) 24 #3.传送字典 25 conn.send(json_dict.encode('utf-8')) 26 #4.传送真实数据 27 conn.send(res) 28 except ConnectionResetError: 29 break 30 conn.close()
1 import socket 2 import struct 3 import json 4 5 client = socket.socket() 6 client.connect(('127.0.0.1',8080)) 7 8 while True: 9 msg = input('>>>:').encode('utf-8') 10 if len(msg) == 0:continue 11 client.send(msg) 12 # 1.先接受字典报头 13 header_dict = client.recv(4) 14 # 2.解析报头 获取字典的长度 15 dict_size = struct.unpack('i',header_dict)[0] # 解包的时候一定要加上索引0 16 # 3.接收字典数据 17 dict_bytes = client.recv(dict_size) 18 dict_json = json.loads(dict_bytes.decode('utf-8')) 19 # 4.从字典中获取信息 20 print(dict_json) 21 recv_size = 0 22 real_data = b'' 23 while recv_size < dict_json.get('file_size'): # real_size = 102400 24 data = client.recv(1024) 25 real_data += data 26 recv_size += len(data) 27 print(real_data.decode('gbk'))