TCP通信: scoket模块 黏包问题 连接循环 通信循环

scoket模块

简单版本原理解析:

服务端的设置:

客户端的设置:

注意:

  127.0.0.1为本机回还地址(只能自己识别自己,其他人无法访问!)

  send 和 recv要相对应,不能出现两边同时接收或发送的情况!

  recv 接收的数据是来自内存的,至于是谁发送到内存的无需考虑。

TCP特点:

    会将数据量小的并且时间间隔短的数据一次性打包发送给对方。

解决黏包问题:

服务端:

  1.先制作一个发送给客户端的字典

  2.制作字典的报头

  3.发送字典的报头

  4.发送字典

  5.再发真实数据

客户端:

  1.先接受字典的报头
  2.解析拿到字典的数据长度
  3.接受字典
  4.从字典中获取真实数据的长度
  5.接受真实数据

struct 模块:

  用于固定发送数据的长度。

  res = struct.pack('i',len(一个值))

  stuct.unpack('i',res)[0]

 1 客户端设置:
 2 import socket
 3 import struct
 4 import json
 5 client = socket.socket()
 6 client.connect(('127.0.0.1',8080))
 7 while True:
 8     msg = input('请输入指令:').encode('utf-8')
 9     client.send(msg)
10     if len(msg) == 0:continue
11     header = client.recv(4)
12     dict_size = struct.unpack('i',header)[0]
13     dict = client.recv(dict_size)
14     dict_json = json.loads(dict.decode('utf-8'))
15     print(dict_json)
16     recv_size = 0
17     real_data = b''
18     while recv_size < dict_json.get('file_size'):
19         data = client.recv(1024)
20         real_data += data
21         recv_size += len(data)
22     print(real_data.decode('gbk'))
23 服务端设置:
24 import socket
25 import subprocess
26 import json
27 import struct
28 server = socket.socket()
29 server.bind(('127.0.0.1',8080))
30 server.listen(5)
31 
32 while True:
33     conn, addr = server.accept()
34     while True:
35         try:
36             cmd = conn.recv(1024)
37             if len(cmd) == 0:break
38             cmd = cmd.decode('utf-8')
39             obj = subprocess.Popen(
40                 cmd,shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
41             res = obj.stdout.read()+obj.stderr.read()
42             d = {'name':'yyj', 'file_size':len(res)}
43             json_d = json.dumps(d)
44             header = struct.pack('i',len(json_d))
45             conn.send(header)
46             conn.send(json_d.encode('utf-8'))
47             conn.send(res)
48         except ConnectionResetError as e:
49             print(e)
50             break
51     conn.close()
View Code

连接循环和通信循环的设计:

 1 #服务端:
 2 import socket
 3 
 4 """
 5 服务端
 6     固定的ip和port
 7     24小时不间断提供服务
 8 """
 9 server = socket.socket()  # 生成一个对象
10 server.bind(('127.0.0.1',8080))  # 绑定ip和port
11 server.listen(5)  # 半连接池
12 
13 while True:
14     conn, addr = server.accept()  # 等到别人来  conn就类似于是双向通道
15     print(addr)  # ('127.0.0.1', 51323) 客户端的地址
16     while True:
17         try:
18             data = conn.recv(1024)
19             print(data)  # b''  针对mac与linux 客户端异常退出之后 服务端不会报错 只会一直收b''
20             if len(data) == 0:break
21             conn.send(data.upper())
22         except ConnectionResetError as e:
23             print(e)
24             break
25     conn.close()
26 
27 客户端:
28 import socket
29 
30 
31 client = socket.socket()
32 client.connect(('127.0.0.1',8080))
33 
34 while True:
35     msg = input('>>>:').encode('utf-8')
36     if len(msg) == 0:continue
37     client.send(msg)
38     data = client.recv(1024)
39     print(data)
View Code

用于处理服务端重新启动时端口没有及时释放问题:

  from socket import SOL_SOCKET,SO_REUSEADDR

  sk.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) #就是它,在bind前加

原文地址:https://www.cnblogs.com/yangjiaoshou/p/11317774.html