使用PF_UNIX/AF_UNIX套接字实现父子进程通信时遇传输端点未连接错误
解决AF_UNIX套接字通信的"transmission endpoint not connected"错误
我一眼就揪出了问题的核心,咱们一步步拆解清楚:
错误根源:用错了套接字描述符
你在父进程里调用send(father_desc, ...),但father_desc是监听套接字(通过socket()+bind()+listen()创建的),它的唯一作用就是调用accept()等待并接受新连接。真正用来和子进程收发数据的,是accept()返回的那个已连接套接字——也就是你的son1_desc!
这就好比你开了个门店(监听套接字),有人上门(子进程发起connect),你得把客人带到会客室(已连接套接字)才能聊天,总不能直接在门店门口喊话对吧?
其他需要修正的潜在问题
除了这个核心错误,代码里还有几个小问题会导致通信异常:
- 父进程的
wait(NULL)时机不对:第一个wait会直接等待第一个子进程结束,但此时父进程还没启动socket服务,第一个子进程的connect大概率会失败(哪怕sleep了1秒,也可能赶不上父进程的bind/listen流程)。应该把父进程的socket初始化逻辑放在fork子进程之前。 recv的长度参数错误:你用了strlen(message)+1,但message初始是空字符串,strlen(message)是0,这意味着你最多只接收1字节数据,根本拿不到完整消息。应该用缓冲区的总大小(比如sizeof(message)-1,留一个字节给终止符)。- 第二个子进程没有任何逻辑,会直接退出,不过这暂时不影响第一个子进程的通信。
修正后的完整代码
我把所有问题都修复了,关键修改处用注释标出来了:
#include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/wait.h> #include <unistd.h> #include <netinet/in.h> #include <netdb.h> #include <sys/un.h> #include <string.h> // 别忘了包含string.h,strlen需要它 #define PATH "/tmp/Server" int main() { pid_t proc1, proc2; // 先初始化父进程的socket服务,再fork子进程,避免子进程connect时服务还没启动 int father_desc = socket(PF_UNIX, SOCK_STREAM, 0); if (father_desc == -1) { perror("Errore nel socket padre"); exit(EXIT_FAILURE); } struct sockaddr_un father_add = {AF_UNIX, PATH}; unlink(PATH); // 先删除旧的套接字文件,避免bind失败 if (-1 == bind(father_desc, (struct sockaddr*)&father_add, sizeof(struct sockaddr_un))) { perror("Errore nel bind"); close(father_desc); exit(EXIT_FAILURE); } if (-1 == listen(father_desc, 2)) { perror("Errore nel listen"); close(father_desc); exit(EXIT_FAILURE); } // 现在再fork子进程 proc1 = fork(); if(proc1 == -1) { perror("Errore nella prima fork"); close(father_desc); exit(EXIT_FAILURE); } if(proc1 != 0) { // PADRE DOPO IL PRIMO FIGLIO proc2 = fork(); if(proc2 == -1) { perror("Errore nella seconda fork"); close(father_desc); wait(NULL); exit(EXIT_FAILURE); } if(proc2 != 0) { // PADRE DOPO I DUE FIGLI struct sockaddr_un son1_add; int len = sizeof(son1_add); int son1_desc = accept(father_desc, (struct sockaddr*)&son1_add, &len); if(-1 == son1_desc) { perror("Errore nell'accept"); close(father_desc); wait(NULL); wait(NULL); exit(EXIT_FAILURE); } char message[256] = "Ciao"; // 关键修改:用son1_desc(已连接套接字)发送数据,而不是father_desc if(-1 == send(son1_desc, message, strlen(message) + 1, 0)) { perror("Errore nel send"); close(father_desc); close(son1_desc); wait(NULL); wait(NULL); exit(EXIT_FAILURE); } close(father_desc); close(son1_desc); wait(NULL); // 等待第一个子进程 wait(NULL); // 等待第二个子进程 unlink(PATH); // 通信结束后删除套接字文件 } else { // SECONDO FIGLIO - 可以在这里添加第二个子进程的通信逻辑 sleep(2); printf("Secondo figlio terminato\n"); exit(EXIT_SUCCESS); } } else { // PRIMO FIGLIO struct sockaddr_un son1_add = {AF_UNIX, PATH}; int son1_desc = socket(PF_UNIX, SOCK_STREAM, 0); if(-1 == son1_desc) { perror("Errore nel socket figlio"); exit(EXIT_FAILURE); } // 加个重试逻辑,避免父进程还没准备好 int retries = 5; while (retries-- > 0) { if (-1 == connect(son1_desc, (struct sockaddr*) &son1_add, sizeof(struct sockaddr_un))) { perror("Tentativo connect fallito, riprovo..."); sleep(1); } else { break; } } if (retries < 0) { perror("Errore nel connect dopo più tentativi"); close(son1_desc); exit(EXIT_FAILURE); } char message[256] = ""; // 关键修改:用sizeof(message)-1作为接收长度,确保能拿到完整消息 if(-1 == recv(son1_desc, message, sizeof(message)-1, 0)) { perror("Errore nel rcv"); close(son1_desc); exit(EXIT_FAILURE); } printf("Messaggio ricevuto dal padre: %s\n", message); close(son1_desc); exit(EXIT_SUCCESS); } return 0; }
验证修改后的效果
编译运行后,第一个子进程会成功接收到父进程发送的"Ciao",不会再出现"transmission endpoint not connected"错误。
内容的提问来源于stack exchange,提问作者Tom Riddle
相关产品推荐
相关产品推荐

