我很确定Inet套接字在accept()调用之后正确地填写了地址和端口,所以我在测试程序中做错了什么,或者我期待错误的结果?
我正在运行CentOS 6.2和gcc 4.4.6.
示例代码:
server.c
#include <sys/types.h> #include <sys/socket.h> #include <sys/un.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #define NAME "socket" int main(int argc,char **argv) { int sock,msgsock,rval; struct sockaddr_un server,client; char buf[1024]; sock = socket(AF_UNIX,SOCK_STREAM,0); if (sock < 0) { perror("opening stream socket"); exit(1); } server.sun_family = AF_UNIX; strcpy(server.sun_path,NAME); if (bind(sock,(struct sockaddr *) &server,sizeof(struct sockaddr_un))) { perror("binding stream socket"); exit(1); } printf("Socket has name %s\n",server.sun_path); listen(sock,5); for (;;) { socklen_t len = sizeof(client); msgsock = accept(sock,(struct sockaddr *)&client,&len); if (msgsock == -1) perror("accept"); else do { printf("strlen(sun_path) = %zu\n",strlen(client.sun_path)); bzero(buf,sizeof(buf)); if ((rval = read(msgsock,buf,1024)) < 0) perror("reading stream message"); else if (rval == 0) printf("Ending connection\n"); else printf("-->%s\n",buf); } while (rval > 0); close(msgsock); } close(sock); unlink(NAME); return 0; }
client.c
#include <sys/types.h> #include <sys/socket.h> #include <sys/un.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #define DATA "Half a league,half a league . . ." int main(int argc,char **argv) { int sock; struct sockaddr_un server; if (argc < 2) { printf("usage:%s <pathname>",argv[0]); exit(1); } sock = socket(AF_UNIX,argv[1]); if (connect(sock,sizeof(struct sockaddr_un)) < 0) { close(sock); perror("connecting stream socket"); exit(1); } if (write(sock,DATA,sizeof(DATA)) < 0) perror("writing on stream socket"); close(sock); return 0; }
只是重申一下这个问题:
为什么在服务器上的accept()调用之后没有填写sun_path?
解决方法
至少在Linux 3.16.0,NetBSD 6.1.4和Darwin 13.1.0内核中,accept(2)填充的值似乎与协议无关.在实践中,这意味着接受(2),struct sockaddr *的第二个参数仅被填充到所有协议之间共享的内容.因此,在成功接受(2)后你手中的东西远不是一个完整的结构sockaddr_un.
可能没有人认为在接受(2)的第一次实现完成时它会非常重要,现在我们仍然坚持这一点.幸运的是,有一种解决方法,如果有人丢失了用于socket的路径名并调用bind(2),现在又想找到它.
使用struct sockaddr_storage和getsockname(2),可以访问成员sun_path.因此,为了确保获得所有有用的细节,请在成功调用accept(2)之后调用getsockname(2)(这将在您的server.c中的第40行之后放置):
struct sockaddr_storage ss; socklen_t sslen = sizeof(struct sockaddr_storage); if (getsockname(msgsock,(struct sockaddr *)&ss,&sslen) == 0) { struct sockaddr_un *un = (struct sockaddr_un *)&ss; printf("socket name is: %s\n",un->sun_path); }
或者只是使用这个:
#include <sys/types.h> #include <sys/socket.h> #include <sys/un.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #define NAME "socket" int main(int argc,strlen(client.sun_path)); struct sockaddr_storage ss; socklen_t sslen = sizeof(struct sockaddr_storage); if (getsockname(msgsock,&sslen) == 0) { struct sockaddr_un *un = (struct sockaddr_un *)&ss; printf("socket name is: %s\n",un->sun_path); } bzero(buf,buf); } while (rval > 0); close(msgsock); } close(sock); unlink(NAME); return 0; }
这已经过测试,即.它编译并产生预期的结果,用于运行内核3.16.0的GNU / Linux系统,运行6.1.4内核的NetBSD系统,以及运行13.1.0内核的OS / X Mavericks系统.在所有这些接受(2)的行为是一致的:sun_path在填充的结构中找不到. getsockname(2)的行为在不同的操作环境之间也是一致的,使所有协议特定的细节都可用.
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。