一、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'))
