0

I've tried sending a string from a Python socket to a C socket, but for some reason, when receiving the string in C, I had to receive 2 characters extra, which I think is a newline. Since I don't want a newline, and since I think that there's a much better way to do what I'm doing, how can I send a string from a Python socket to a C socket? Do I need to use the Python module ctypes? Thanks

This is the line I'm executing (in Python):

sock.send(bytes("FPUT", "utf-8"))

and in order to receive the entire message, I have to receive 6 characters in C. Here is the receiving code I tried before I noticed the error:

char* msghdr = (char*) malloc(4*sizeof(char));
recv(i, msghdr, 4, 0); //i is the socket
Serket
  • 3,785
  • 3
  • 14
  • 45

1 Answers1

1

C strings are null-terminated, meaning that there is a 0 ('\0') character that marks the end of the string. Without that character, you're using whatever happens to come next in memory as part of the string.

This means that every string buffer needs to be one larger than the actual string length. You're only transmitting the contents of the string, not the representation of a C string.

There are two options for adding the NUL character. You could add it on the Python side, and receive one more character on the C side, or keep the Python code the same and add the '\0' in C:


This code shows only changes to C

#define MSGHDR_SIZE 4

// ...

char* msghdr = malloc((MSGHDR_SIZE + 1) * sizeof(char));
ssize_t recv_result = recv(i, msghdr, MSGHDR_SIZE, 0);
if (recv_result == -1) {
    // Handle error
} else {
    msghdr[recv_result] = '\0';
}

Here, the number of actual received bytes is used as the index at which to add the NUL character, ensuring that the buffer is always a valid string.

I've also used a preprocessor macro MSGHDR_SIZE. This is generally considered to be good practice, avoiding "magic numbers".

Also, I removed the cast on the result of malloc. See Do I cast the result of malloc?.


This code shows adding the character in Python

sock.send(bytes("FPUT", "utf-8") + b'\0')
// Includes NUL character
#define MSGHDR_SIZE 5

// ...

char* msghdr = malloc(MSGHDR_SIZE * sizeof(char));
ssize_t recv_result = recv(i, msghdr, MSGHDR_SIZE, 0);
if (recv_result == -1) {
    // Handle error
} else {
    msghdr[recv_result] = '\0';
}

Also, you should be checking the result of malloc for failure.

Thomas Jager
  • 4,836
  • 2
  • 16
  • 30
  • Thanks! But out of curiosity, could you show me how to implement this on the Python side? – Serket May 13 '20 at 13:49
  • @Serket I've added a second set of code showing that. – Thomas Jager May 13 '20 at 13:58
  • `sock.send(b'FPUT\0')` is more straightforward. – Mark Tolonen May 14 '20 at 07:32
  • @MarkTolonen It's more straightforward, but that might be less flexible. Works fine here, but that could change if the actual code is more complex. Since they already had the conversion to a `bytes` object, I figured it makes sense to keep the string as it is. – Thomas Jager May 14 '20 at 12:32