简体   繁体   English

C 套接字服务器和 Python 套接字客户端“资源暂时不可用”

[英]C socket server and Python socket client "Resource temporarily unavailable"

I am creating a C server and Python client for UNIX domain datagram sockets (UDS) IPC on Ubuntu 18.04. 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.我的场景是: Python 作为使用 fork-execv 创建的子进程运行,其中 C 是父进程。 The Python client blocks on socket.recvfrom until data is sent by the C server. Python 客户端在 socket.recvfrom 上阻塞,直到 C 服务器发送数据。 When the C server sends data to the Python client then C will block on recvfrom until Python sends data to C with sendto. 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.我已经将 UDS 用于 C 客户端和 C 服务器没有问题,但是 C-Python 设置导致了一些问题。 For this Python version I worked from an example at https://lloydrochester.com/post/c/unix-domain-socket-datagram .对于这个 Python 版本,我从https://lloydrochester.com/post/c/unix-domain-socket-datagram的示例中工作。

I create a server socket in C and bind to it;我在 C 中创建一个服务器套接字并绑定到它; it returns file descriptor 5:它返回文件描述符 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.我没有在 C 端创建或显式连接到客户端套接字。

On the Python side I bind to the client socket.在 Python 端,我绑定到客户端套接字。 Here is my Python code, following the example cited, but altered somewhat to fit my use case:这是我的 Python 代码,按照引用的示例,但有所改动以适合我的用例:

#!/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. 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) ,并且 C 无法继续。

If I set it to nonblocking with csock.setblocking(False) I get this error message:如果我使用 csock.setblocking(False) 将其设置为非阻塞,我会收到以下错误消息:

(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?所以我的问题是为什么 Python 会阻止这两个进程,为什么我会在非阻塞模式下收到该错误消息?

Thanks for any help.谢谢你的帮助。

Explanation解释

why does Python block both processes?为什么 Python 会阻止这两个进程?

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.当您的客户端使用recvfrom等待服务器的响应时,您的服务器什么也没做,因此服务器也会在其recvfrom处阻塞。

why do I get that error message in nonblocking mode?为什么我在非阻塞模式下会收到该错误消息?

Your server/client might not be as robust as the one you quoted (ie from lloydrochester.com ).您的服务器/客户端可能不像您引用的那样强大(即来自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.其中一些只是关于 C 郎,如变量声明Function 返回等。还有一些是关于网络编程的,如Buffer SizingSocket Internals等,不一一列举并一一分析。 Better read through K&R and BSD socket to fix them thoroughly.最好通读K&RBSD 套接字以彻底修复它们。

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 .此外,您可能希望将server_alice.c第 48 行中的回复消息更改为Code_99


Environment环境

Ubuntu 18.04
gcc 7.5.0
Python 3.6.9

server_alice.c 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 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:服务器 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:客户 Output:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM