【发布时间】:2019-09-18 08:32:14
【问题描述】:
我创建了一个简单的 C++ 服务器,它试图通过套接字将 vector<uint8_t> 的字节发送到 Python 客户端。我已经让所有服务器和客户端连接正常,但是数据在 python 中输出不正确。我首先发送一个整数来描述预期的字节数,然后发送字节。但是,当我运行我的 python 脚本并在套接字上调用 recv 时,我有时会得到不正确的预期字节数值。
我已经调试了 C++ 和 Python 代码,但它显示出一些奇怪的行为。首先,我意识到当我调试 Python 代码时它工作正常。事实证明,在我的 Python 脚本中,如果我在读取整数标头的前 4 个字节和读取其余字节之间调用 sleep(1) ,它将起作用。但是,当我在没有睡眠的情况下进行多个 recv 调用时,就会出现问题。我还检查了字节字节序的内容是否正确。我什至在服务器和客户端之间添加了一个握手程序,以确保它们能够很好地协同工作。
对于 C++: 设置套接字:
int Server::setup_socket(int port){
int server_fd, new_socket;
struct sockaddr_in address;
int opt = 1;
int addrlen = sizeof(address);
// Creating socket file descriptor
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0){
perror("socket failed");
exit(EXIT_FAILURE);
}
// Forcefully attaching socket to the port
if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))){
perror("setsockopt");
exit(EXIT_FAILURE);
}
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(port);
// Forcefully attaching socket to the port
if (bind(server_fd, (struct sockaddr *)&address, sizeof(address))<0){
perror("bind failed");
exit(EXIT_FAILURE);
}
if (listen(server_fd, 3) < 0){
perror("listen");
exit(EXIT_FAILURE);
}
printf("Successfully connected to port %d\n", port);
if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen))<0){
perror("accept");
exit(EXIT_FAILURE);
}
return new_socket;
}
发送数据和握手方法:
void Server::send_image(cv::Mat &image) {
std::vector<uint8_t> buf;
std::vector<int> param(2);
param[0] = cv::IMWRITE_JPEG_QUALITY;
param[1] = 80; //default(95) 0-100
cv::imencode(".jpg", image, buf, param);
int length = buf.size();
printf("Sending image of size: %d\n", length);
write(data_socket, &length, sizeof(length));
write(data_socket, buf.data(), length);
}
void Server::confirm_sent(){
uint8_t confirmation[1];
write(conf_socket, confirmation, 1);
}
void Server::confirm_received(){
uint8_t confirmation[1];
read(conf_socket, confirmation, 1);
}
Python 代码:
data_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # For sending data
conf_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # For hand shaking
# Connect the socket to the port where the server is listening
data_address = ('192.168.1.146', 2323)
conf_address = ('192.168.1.146', 2324)
print('connecting to %s port %s' % data_address)
data_sock.connect(data_address)
time.sleep(1)
print('connecting to %s port %s' % conf_address)
conf_sock.connect(conf_address)
while True:
conf_sock.recv(1) # Confirm sent
size1 = int.from_bytes(data_sock.recv(4), byteorder="big")
size2 = socket.ntohl(size1) # Fixes endian problems
# time.sleep(1) # Inserting this fixes things, but I don't want the delay
data = np.frombuffer(data_sock.recv(size2), dtype=np.uint8)
print(f"{size1}, {size2}, {data.shape}")
conf_sock.send(bytes(1))
C++ 输出和预期大小:
Max speed spi is 8000000
OV5642 detected.
Successfully connected to port 2323
Successfully connected to port 2324
Sending image of size: 134966
Sending image of size: 135072
Sending image of size: 134628
Sending image of size: 134846
Sending image of size: 134704
Sending image of size: 134885
Sending image of size: 133942
Python 收到的尺寸:
connecting to 192.168.1.146 port 2323
connecting to 192.168.1.146 port 2324
906953216, 134966, (95568,)
1224436735, 4285266760, (45190,)
2585803520, 3874970, (137968,)
939478527, 4283301687, (137524,)
103119361, 24782086, (136294,)
1526714366, 4275044186, (127464,)
469746175, 4290903835, (136333,)
【问题讨论】:
-
旁注:如果您遇到字节序问题,请不要解码为大字节序,而是解码为小字节序。所以放弃
socket.ntohl()调用,并在前一行将'big'替换为'little'。 -
(并且 TCP/IP 的网络字节顺序始终是大端序,如果您有排序问题,那么 C++ 端不会以正确的顺序发送数据,例如它正在以小端方式发送数据 -字节序)