3种一般方法
在使用 Python 和 C++ 的 socket 通信时,如果要处理不定长的数据包,可以使用以下方法之一:
-
在发送数据包之前,先发送一个固定长度的头部信息,用来指示接下来要接收的数据包的长度。然后再根据这个长度来接收数据。
-
使用分隔符来分割不同的数据包。例如,在每个数据包的末尾添加一个特殊字符,然后在接收端根据这个特殊字符来判断一个数据包是否接收完整。
-
使用循环接收的方法,每次接收一定长度的数据,直到接收到完整的数据包为止。
方法实现
固定长度的头部信息
python 端处理逻辑
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
import socket
import struct
def send_msg(sock, msg):
# 在发送数据之前,先发送一个固定长度的头部信息,用来指示接下来要接收的数据包的长度
msg = struct.pack('>I', len(msg)) + msg
sock.sendall(msg)
def recv_msg(sock):
# 接收固定长度的头部信息
raw_msglen = recvall(sock, 4)
if not raw_msglen:
return None
msglen = struct.unpack('>I', raw_msglen)[0]
# 根据头部信息中指示的长度来接收数据包
return recvall(sock, msglen)
def recvall(sock, n):
data = b''
while len(data) < n:
packet = sock.recv(n - len(data))
if not packet:
return None
data += packet
return data
# 示例:
s = socket.socket()
s.connect(('localhost', 12345))
send_msg(s, b'Hello, world!')
data = recv_msg(s)
print(data)
s.close()
|
c++ 端处理逻辑
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
|
#include <iostream>
#include <cstring>
#include <arpa/inet.h>
#include <sys/socket.h>
void send_msg(int sock, const char *msg) {
uint32_t len = strlen(msg);
uint32_t nlen = htonl(len);
// 在发送数据之前,先发送一个固定长度的头部信息,用来指示接下来要接收的数据包的长度
send(sock, &nlen, sizeof(uint32_t), 0);
send(sock, msg, len, 0);
}
char* recv_msg(int sock) {
uint32_t nlen;
// 接收固定长度的头部信息
recv(sock, &nlen, sizeof(uint32_t), 0);
uint32_t len = ntohl(nlen);
// 根据头部信息中指示的长度来接收数据包
char *msg = new char[len+1];
recv(sock, msg, len, 0);
msg[len] = '\0';
return msg;
}
int main() {
int s = socket(AF_INET , SOCK_STREAM , 0);
struct sockaddr_in server;
server.sin_addr.s_addr = inet_addr("127.0.0.1");
server.sin_family = AF_INET;
server.sin_port = htons(12345);
connect(s , (struct sockaddr *)&server , sizeof(server));
send_msg(s , "Hello World!");
char *data = recv_msg(s);
std::cout << data << std::endl;
delete[] data;
close(s);
return 0;
}
|
c++端也可实现 senall
方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
int sendall(int s, const void *buf, int *len){
int total = 0; // how many bytes send
int bytesleft = *len; // how many left
int n;
while(total < *len) {
n = send(s, (uint8_t *)buf+total, bytesleft, 0);
if (n == -1) { break; }
total += n;
bytesleft -= n;
}
*len = total; // return number actually sent here
return n==-1?-1:0; // return -1 on failure, 0 on success
}
int main(int argc, char **argv)
{
char sendBuffer[128];
/* 省略其他代码 */
int msg_len = sizeof(sendBuffer);
if (sendall(socketDescriptor, sendBuffer, &msg_len) == -1) {
perror("message sendall");
printf("only sent %d bytes because of the error!\n", msg_len);
close(socketDescriptor);
break;
}
}
|
其中s
是 socketDescriptor
使用分隔符(未实现)
循环接收(未实现)