1. Review of the previous lesson
1. TCP ( a two-way connection is established) three-way handshake to establish a connection, and four waves to disconnect
Three-way handshake:
c----syn=1 seq=x--->s
s----ack=1+x syn=1 seq=y--->c
c----ack=1+y------->s
Four waves:
s------fin=1---------->c
c------>ack=1--------->s
c------>fin=1--------->s
s------>ack=1--------->c
127.0.0.1: local loopback address
Regardless of sending and receiving ( send , receive ), it is directly interacting with its own operating system, and the operating system then transfers the hardware to transmit the information to the other party's operating system.
Also based on the above reasons, there is no one-to-one correspondence between sending and receiving.
2、socket
Socket is an abstraction layer between the application layer and the transport layer, which specifically encapsulates the protocol below the transport layer into an interface for the application layer to use. The application only needs to call the socket interface or write the program according to the socket standard, and the written program naturally follows the tcp/ip protocol.
Second, the sticky package problem
TCP , also known as streaming protocol, has two characteristics:
a , like a steady stream of water
b . Optimize the transmission mechanism, use the NAGLE algorithm to save data with a short time interval and a small amount of data into a wave
The above two characteristics lead to the sticky package problem
The idea of solving the problem of sticky packets is to know how much to send, and then how much to receive
Note: If you use time.sleep to solve, solve this end, there may be sticky packets on the other end
3. Solve the problem of sticky package (basic board)
a , struct module
1 ) Convert the integer number to the bytes type
2 ) The converted bytes are of fixed length
import struct
res=struct.pack('i',20332) # ‘i’ --integer
print (res, len (res))
res2=struct.unpack('i',res)
print(res2[0])
b . Server
from socket import *
import subprocess
import struct
server = socket (AF_INET, SOCK_STREAM)
server.bind(('127.0.0.1',8080))
server.listen(5)
while True:
conn,client_addr=server.accept() #( connection object, client's ip and port )
print(client_addr)
while True:
try:
cmd=conn.recv(1024)
obj=subprocess.Popen(cmd.decode('utf-8'),
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
)
stdout=obj.stdout.read()
stderr=obj.stderr.read()
# 1、制作固定长度的报头
total_size=len(stdout) + len(stderr)
header=struct.pack('i',total_size)
# 2、发送报头
conn.send(header)
#3、发送真实的数据
conn.send(stdout)
conn.send(stderr)
except ConnectionResetError:
break
conn.close()
server.close()
c、 客服端
from socket import *
import struct
client=socket(AF_INET,SOCK_STREAM)
client.connect(('127.0.0.1',8080))
# print(client)
while True:
cmd=input('>>>: ').strip()
if not cmd:continue
client.send(cmd.encode('utf-8'))
#1、先收固定长度的报头
header=client.recv(4)
#2、解析报头
total_size=struct.unpack('i',header)[0]
print(total_size) #1025
#3、根据报头内的信息,收取真实的数据
recv_size=0
res=b''
while recv_size < total_size:
recv_data=client.recv(1024)
res+=recv_data
recv_size+=len(recv_data)
print(res.decode('gbk'))
client.close()
四、解决粘包问题(终极版)
a、 struct模块
import struct
import json
header_dic = {
'total_size': 3122222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222121,
'md5': '123svsaef123sdfasdf',
'filename': 'a.txt'
}
header_json=json.dumps(header_dic)
# print(header_json,type(header_json))
header_bytes=header_json.encode('utf-8')
header_size=len(header_bytes)
print(header_size)
obj=struct.pack('i',header_size)
print(obj,len(obj))
b、 服务端
from socket import *
import subprocess
import struct
import json
server=socket(AF_INET,SOCK_STREAM)
server.bind(('127.0.0.1',8080))
server.listen(5)
while True:
conn,client_addr=server.accept() #(连接对象,客户端的ip和端口)
print(client_addr)
while True:
try:
cmd=conn.recv(1024)
obj=subprocess.Popen(cmd.decode('utf-8'),
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
)
stdout=obj.stdout.read()
stderr=obj.stderr.read()
# 1、制作报头
header_dic={
'total_size':len(stdout) + len(stderr),
'md5':'123svsaef123sdfasdf',
'filename':'a.txt'
}
header_json = json.dumps(header_dic)
header_bytes = header_json.encode('utf-8')
# 2、先发送报头的长度
header_size=len(header_bytes)
conn.send(struct.pack('i',header_size))
# 3、发送报头
conn.send(header_bytes)
# 4、发送真实的数据
conn.send(stdout)
conn.send(stderr)
except ConnectionResetError:
break
conn.close()
server.close()
c、 客户端
from socket import *
import struct
import json
client=socket(AF_INET,SOCK_STREAM)
client.connect(('127.0.0.1',8080))
# print(client)
while True:
cmd=input('>>>: ').strip()
if not cmd:continue
client.send(cmd.encode('utf-8'))
#1、先收报头的长度
header_size=struct.unpack('i',client.recv(4))[0]
#2、接收报头
header_bytes=client.recv(header_size)
#3、解析报头
header_json=header_bytes.decode('utf-8')
header_dic=json.loads(header_json)
print(header_dic)
total_size=header_dic[ 'total_size']
# print(total_size) #1025
#4、根据报头内的信息,收取真实的数据
recv_size=0
res=b''
while recv_size < total_size:
recv_data=client.recv(1024)
res+=recv_data
recv_size+=len(recv_data)
print(res.decode('gbk'))
client.close()
五、远程执行命令的程序
a、 客户端
from socket import *
client=socket(AF_INET,SOCK_STREAM)
client.connect(('127.0.0.1',8080))
# print(client)
while True:
cmd=input('>>>: ').strip()
if not cmd:continue
client.send(cmd.encode('utf-8'))
# print('has send')
res=client.recv(14744)
# print('has recv')
print(len(res))
print(res.decode('gbk'))
client.close()
b、 服务端
from socket import *
import subprocess
server=socket(AF_INET,SOCK_STREAM)
server.bind(('127.0.0.1',8080))
server.listen(5)
while True:
conn,client_addr=server.accept() #(连接对象,客户端的ip和端口)
print(client_addr)
while True:
try:
cmd=conn.recv(1024)
obj=subprocess.Popen(cmd.decode('utf-8'),
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
)
stdout=obj.stdout.read()
stderr=obj.stderr.read()
# 先发送数据的长度
total_size=len(stdout) + len(stderr)
conn.send(total_size)
# 发送真实的数据
conn.send(stdout)
conn.send(stderr)
except ConnectionResetError:
break
conn.close()
server.close()
#交互式命令或是cd。。一般要在一台机器上,不推荐远程调控。如若强行要求,不要直接执行,而是要模拟执行,并将模拟结果发回。