I have created a simple C++ server that is attempting to send the bytes of a vector<uint8_t> to a Python client over a socket. I have got all the server and client connecting fine, however the data is coming out incorrectly in python. I am first sending an integer describing how many bytes to expect, then sending the bytes. However, when I run my python script and call recv on the socket, I am sometimes getting incorrect values for the amount of bytes to expect.
I have debugged the C++ and the Python code, and it is showing some weird behaviour. Firstly I realised that when I was debugging the Python code it was working fine. It turns out that in my Python script, if I call sleep(1) between when I read the first 4 bytes for the integer header and when I then read the rest of the bytes it works. However, when I do the multiple recv calls without the sleep, then things go wrong. I have also checked that the byte endian stuff is correct. I even added a handshake procedure between the server and client to make sure they were working together nicely.
For the C++: Setting up the socket:
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;
}
Sending data and handshake methods:
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 code:
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++ output and expected sizes:
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 received sizes:
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()call, and replace'big'with'little'on the preceding line.