socket分包粘包
socket在发送数据的时候,如果数据返回过大,会分批次发送,所以设计循环发送(while True),有个问题什么时候才算发送结束?
解决办法:可以事先发送数据大小,然后按照数据大小判断结束时间
但是多次发送的过程有可能导致粘包的产生,即连续两次send时间过短,导致客户端收到粘包数据,为此你需要在每一次发送过程都跟客户端做一次握手,服务器发送给客户端,客户端会跟服务器说一声收到,然后服务器接着发送,客户端接着收到,这样一来一回、常来常往就不会出现问题。
下面程序未测试,目测os.popen需要进行更换。
服务端实现
import socket ,os,time
server = socket.socket()
server.bind(('localhost',9999) )
server.listen()
while True:
conn, addr = server.accept()
print("new conn:",addr)
while True:
print("等待新指令")
data = conn.recv(1024)
if not data:
print("客户端已断开")
break
print("执行指令:",data)
## 有可能高版本得使用subprocess实现, 未测试,只是讲原理!
cmd_res = os.popen(data.decode()).read() #接受字符串,执行结果也是字符串
print("before send",len(cmd_res))
if len(cmd_res) ==0:
cmd_res = "cmd has no output..."
conn.send( str(len(cmd_res.encode())).encode("utf-8") ) #先发大小给客户端
time.sleep(0.5) ## 这不是一个好办法,需要改进,可以通过conn.recv()改进
conn.send(cmd_res.encode("utf-8"))
print("send done")
os.path.isfile()
os.stat("sock")
server.close()
import hashlib
m = hashlib.md5()
改进版本:
import socket ,os,time
server = socket.socket()
#服务器端0.0.0.0的话可以访问多个服务端的ip
#如果只有一个网卡,那么0.0.0.0和指定ip一样
#server.bind(('localhost',9999) )
server.bind(('0.0.0.0',9999) )
server.listen()
while True:
conn, addr = server.accept()
print("new conn:",addr)
while True:
print("等待新指令")
data = conn.recv(1024)
if not data:
print("客户端已断开")
break
print("执行指令:",data)
## 有可能高版本得使用subprocess实现, 未测试,只是讲原理!
cmd_res = os.popen(data.decode()).read() #接受字符串,执行结果也是字符串
print("before send",len(cmd_res))
if len(cmd_res) ==0:
cmd_res = "cmd has no output..."
conn.send( str(len(cmd_res.encode())).encode("utf-8") ) #先发大小给客户端
##time.sleep(0.5) ## 这不是一个好办法,需要改进,可以通过conn.recv()改进
client_ack=conn.recv(1024) ##收到客户端的响应!!很重要,不然两次send会存在粘包现象!
print(f'from clinet ack {client_ack}')
conn.send(cmd_res.encode("utf-8"))
print("send done")
os.path.isfile()
os.stat("sock")
server.close()
import hashlib
m = hashlib.md5()
client客户端实现
import socket
client = socket.socket()
#client.connect(('192.168.16.200',9999))
client.connect(('localhost',9999))
while True:
cmd = input(">>:").strip()
if len(cmd) == 0: continue
client.send(cmd.encode("utf-8"))
cmd_res_size = client.recv(1024) ##接受命令结果的长度
print("命令结果大小:",cmd_res_size)
received_size = 0
received_data = b''
while received_size < int(cmd_res_size.decode()) :
data = client.recv(1024)
received_size += len(data) #每次收到的有可能小于1024,所以必须用len判断
#print(data.decode())
received_data += data
else:
print("cmd res receive done...",received_size)
print(received_data.decode())
client.close()
服务器端额外需要接受一条回复。
客户端程序改进:
import socket
client = socket.socket()
#client.connect(('192.168.16.200',9999))
client.connect(('localhost',9999))
while True:
cmd = input(">>:").strip()
if len(cmd) == 0: continue
client.send(cmd.encode("utf-8"))
cmd_res_size = client.recv(1024) ##接受命令结果的长度
print("命令结果大小:",cmd_res_size)
client.send("准备好接收了,服务器可以发送了".encode("utf-8"))
received_size = 0
received_data = b''
while received_size < int(cmd_res_size.decode()) :
data = client.recv(1024)
received_size += len(data) #每次收到的有可能小于1024,所以必须用len判断
#print(data.decode())
received_data += data
else:
print("cmd res receive done...",received_size)
print(received_data.decode())
client.close()
socketServer使用
socketServer的最主要作用就是实现一个并发处理(socketserver.TCPServer改为socketserver.ThreadingTCPServer就可以变为并发程序!! 很简单! TCPServer依然是1对1程序,多个client链接服务器需要等待,而ThreadingTCPServer实现了真正的并发socket),参考下面的socketServer使用,然后再改造你的socket ssh和FTP https://jueqingsizhe66.github.io/post/simplehttpserver-python3-version/
socketServer的感觉的有点类似于线程池
socketServer相对于socket,正如线程池相对于thread.
class MyTCPHandler(socketserver.BaseRequestHandler):
def handle(self):
while True:
try:
self.data = self.request.recv(1024).strip()
print("{} wrote:".format(self.client_address[0]))
print(self.data)
self.request.send(self.data.upper())
except ConnectionResetError as e:
print("err",e)
break
if __name__ == "__main__":
HOST, PORT = "localhost", 9999
# Create the server, binding to localhost on port 9999
server = socketserver.ThreadingTCPServer((HOST, PORT), MyTCPHandler)
## TCPHandler有点类似于工作线程,Server分派一个一个的Handler和客户端进行交互,
## 进而实现并发socket过程!
server.serve_forever()
## 注意ThreadingTCPServer
ThreadingTCPServer的默认实现: 多并发实现指的是多个线程执行 而还有多进程,指的是ForkTCPServer(linux有用)
def process_request(self, request, client_address):
"""Start a new thread to process the request."""
if self.block_on_close:
vars(self).setdefault('_threads', _Threads())
t = threading.Thread(target = self.process_request_thread,
args = (request, client_address))
t.daemon = self.daemon_threads
self._threads.append(t)
t.start()
https://jueqingsizhe66.github.io/post/socket%E6%9D%A5%E6%BA%90/
Related