Home > Mobile >  C socket server and Python socket client "Resource temporarily unavailable"
C socket server and Python socket client "Resource temporarily unavailable"

Time:11-24

I am creating a C server and Python client for UNIX domain datagram sockets (UDS) IPC on Ubuntu 18.04. My scenario is: Python runs as a child process created with fork-execv where C is the parent process. The Python client blocks on socket.recvfrom until data is sent by the C server. When the C server sends data to the Python client then C will block on recvfrom until Python sends data to C with sendto.

I have used UDS for a C client and a C server with no problems, but the C-Python setup is causing some problems. For this Python version I worked from an example at https://lloydrochester.com/post/c/unix-domain-socket-datagram.

I create a server socket in C and bind to it; it returns file descriptor 5:

int64_t * create_socket_server(struct sockaddr_un svaddr, int64_t retvals[])
{
    int sfd, j;
    ssize_t numBytes;
    socklen_t len;
    char buf[BUF_SIZE];

    retvals[0] = 0;
    retvals[1] = 0;

    sfd = socket(AF_UNIX, SOCK_DGRAM, 0); /* Create server socket 

    if (sfd == -1)
         return retvals;

    if (remove(SV_SOCK_PATH) == -1 && errno != ENOENT)
           return retvals;

    memset(&svaddr, 0, sizeof(struct sockaddr_un));
    svaddr.sun_family = AF_UNIX;
    strncpy(svaddr.sun_path, SV_SOCK_PATH, sizeof(svaddr.sun_path) - 1);

    if (bind(sfd, (struct sockaddr *) &svaddr, sizeof(struct sockaddr_un)) == -1)
           return retvals;

    retvals[0] = sfd;
    retvals[1] = (int64_t)&svaddr;

     return retvals;
}

I do not create or explicitly connect to the client socket on the C side.

On the Python side I bind to the client socket. Here is my Python code, following the example cited, but altered somewhat to fit my use case:

#!/usr/bin/python3
import socket
import os, os.path

csock_file = "/tmp/py_sock"
ssock_file = "/tmp/ud_ucase"

if os.path.exists(csock_file):
  os.remove(csock_file)

csock = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
csock.bind(csock_file) # Bind to the server socket

return_msg = "Got it"

while True:

    (bytes, address) = csock.recvfrom(720)
    msg = bytes.decode('utf-8')

    print("Python received")

    if msg != "Code_99":
        print('address:',address,'received:',msg)
        csock.sendto(str.encode(return_msg), ssock_file)

    if msg == "Code_99":
        print("closing")
        #Close the socket

I want recvfrom to be blocking in both Python and C because Python should block until C sends, but when I leave it at blocking (the default) then Python blocks both processes when it calls (bytes, address) = csock.recvfrom(720), and C cannot continue.

If I set it to nonblocking with csock.setblocking(False) I get this error message:

(bytes, address) = csock.recvfrom(720)
BlockingIOError: [Errno 11] Resource temporarily unavailable

So my question is why does Python block both processes, and why do I get that error message in nonblocking mode?

Thanks for any help.

CodePudding user response:

Explanation

why does Python block both processes ?

When your client is waiting for your server's response with recvfrom, you server just did nothing, thus server blocks at its recvfrom as well.

why do I get that error message in nonblocking mode ?

Your server/client might not be as robust as the one you quoted (i.e. from lloydrochester.com). Serveral parts broke and result in breaking the whole thing. Some of them are just about C Lang, such as Variable Declarations, Function Returning, etc. Others are about network programming, such as Buffer Sizing, Socket Internals, etc. It's not realistic to list them all and analyse one by one. Better read through K&R and BSD socket to fix them thoroughly.

However, here is an relatively simple implementation for you case, based on your codes, shown below. In addition, you might want to change the reply message to Code_99 in the 48th line of server_alice.c.


Environment

Ubuntu 18.04
gcc 7.5.0
Python 3.6.9

server_alice.c

#include <sys/un.h>
#include <sys/socket.h>
#include <ctype.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>

#define BUF_SIZE 720
#define SV_SOCK_PATH "ssock"
int create_socket_server(int *sfd_ptr, struct sockaddr_un *svaddr_ptr);

int main(int argc, char *argv[]) {

    struct sockaddr_un svaddr, claddr;
    int sfd, j;
    ssize_t numBytes;
    socklen_t len;
    char buf[BUF_SIZE];

    int64_t retvals[2];

    if (create_socket_server(&sfd, &svaddr) == 0)
        printf("create_socket_server...DONE\n");
    else exit(0);

    for (;;) {
        len = sizeof(struct sockaddr);
        printf("waiting clients...\n");
        numBytes = recvfrom(sfd, buf, BUF_SIZE, 0, (struct sockaddr *) &claddr, &len);

        if (numBytes == -1) {
            fprintf(stderr, "error recvfrom");
            return 4;
        }
        claddr.sun_path[len - sizeof(sa_family_t) - 1] = 0;
        buf[numBytes] = '\0';
        fprintf(stdout, "server received %ld bytes from %s, they are: \x1b[32m%s\x1b[0m\n", (long) numBytes,
                claddr.sun_path, buf);

        for (j = 0; j < numBytes; j  ) {
            buf[j] = toupper((unsigned char) buf[j]);
        }

        // char *reply_msg="Code_99";        #   different reply message
        char *reply_msg = "Hello Bob~ This is a message: blablablabla";

        j = sendto(sfd, reply_msg, strlen(reply_msg), 0, (struct sockaddr *) &claddr, len);
        if (j != strlen(reply_msg)) {
            fprintf(stderr, "error sendto %s", strerror(errno));
        }
    }
    exit(EXIT_SUCCESS);
}

/* Your create_socket_server, with a few changes */
int create_socket_server(int *sfd_ptr, struct sockaddr_un *svaddr_ptr) {
    struct sockaddr_un svaddr;
    int sfd = socket(AF_UNIX, SOCK_DGRAM, 0); // Create server socket

    if (sfd == -1)
        return -1;

    if (remove(SV_SOCK_PATH) == -1 && errno != ENOENT)
        return -1;

    memset(&svaddr, 0, sizeof(struct sockaddr_un));
    svaddr.sun_family = AF_UNIX;
    strncpy(svaddr.sun_path, SV_SOCK_PATH, sizeof(svaddr.sun_path) - 1);
    if (bind(sfd, (struct sockaddr *) &svaddr, sizeof(struct sockaddr_un)) == -1)
        return -1;

    memcpy(sfd_ptr, &sfd, sizeof(int));
    memcpy(svaddr_ptr, &svaddr, sizeof(struct sockaddr_un));


    return 0;
}

client_bob.py

#!/usr/bin/python3
import socket
import os, os.path

csock_file = "./csock"
ssock_file = "./ssock"

if os.path.exists(csock_file):
    os.remove(csock_file)

csock = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
csock.bind(csock_file)  # Bind to the server socket

return_msg = "Got it"
csock.sendto(str.encode("Hello Alice! I'm coming!"), ssock_file)
# while True:     #       ! CATION !       If 'while(true)', there will be infinite message sending back and forth!
(bytes, address) = csock.recvfrom(720)
msg = bytes.decode('utf-8')

if msg != "Code_99":
    print('address:    ', address, 'received:   ', msg)
    csock.sendto(str.encode(return_msg), ssock_file)

if msg == "Code_99":
    print("closing")
    csock.close()

Server Output:

$ gcc server_alice.c && ./a.out
create_socket_server...DONE
waiting clients...
server received 24 bytes from ./csock, they are: Hello Alice! I'm coming!
waiting clients...
server received 6 bytes from ./csock, they are: Got it
waiting clients...

Client Output:

$ python3 client_bob.py 
address:     ssock received:    Hello Bob~ This is a message: blablablabla
  • Related