我正在為 Ubuntu 18.04 上的 UNIX 域資料報套接字 (UDS) IPC 創建 C 服務器和 Python 客戶端。我的場景是:Python 作為使用 fork-execv 創建的子行程運行,其中 C 是父行程。Python 客戶端在 socket.recvfrom 上阻塞,直到 C 服務器發送資料。當 C 服務器向 Python 客戶端發送資料時,C 將阻塞 recvfrom,直到 Python 使用 sendto 將資料發送到 C。
我已經將 UDS 用于 C 客戶端和 C 服務器,沒有任何問題,但是 C-Python 設定導致了一些問題。對于這個 Python 版本,我從https://lloydrochester.com/post/c/unix-domain-socket-datagram 上的一個例子開始作業。
我在 C 中創建了一個服務器套接字并系結到它;它回傳檔案描述符 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;
}
我沒有在 C 端創建或顯式連接到客戶端套接字。
在 Python 端,我系結到客戶端套接字。這是我的 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
我希望 recvfrom 在 Python 和 C 中都被阻塞,因為 Python 應該阻塞直到 C 發送,但是當我讓它處于阻塞狀態(默認)然后 Python 在呼叫 (bytes, address) = csock.recvfrom(720) 時阻塞兩個行程,C 不能繼續。
如果我使用 csock.setblocking(False) 將其設定為非阻塞,我會收到以下錯誤訊息:
(bytes, address) = csock.recvfrom(720)
BlockingIOError: [Errno 11] Resource temporarily unavailable
所以我的問題是為什么 Python 會阻塞兩個行程,為什么我會在非阻塞模式下收到該錯誤訊息?
謝謝你的幫助。
uj5u.com熱心網友回復:
解釋
為什么 Python 會阻止這兩個行程?
當您的客戶端正在等待您的服務器的回應時recvfrom,您的服務器什么也沒做,因此服務器recvfrom也會阻塞它。
為什么我會在非阻塞模式下收到該錯誤訊息?
您的服務器/客戶端可能不如您參考的(即來自lloydrochester.com)那么強大。幾個零件壞了,導致整個東西都壞了。有的只是關于C語言的,如變數宣告、函式回傳等,有的則是關于網路編程的,如Buffer Sizing、Socket Internals等,一一列舉,一一分析是不現實的。最好通讀K&R和BSD 套接字以徹底修復它們。
但是,根據您的代碼,這里有一個相對簡單的實作,如下所示。此外,您可能希望將server_alice.cCode_99的第 48 行中的回復訊息更改為。
環境
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;
}
客戶端_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()
服務器輸出:
$ 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...
客戶端輸出:
$ python3 client_bob.py
address: ssock received: Hello Bob~ This is a message: blablablabla
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/364037.html
上一篇:宣告矩陣c的不同方式
