客户端/服务器套接字通信(AF_UNIX)

我正在尝试编写一个客户端程序和一个服务器程序,当客户端连接到服务器时,服务器会将文件中的随机字符串发送回它。 这是我到目前为止(从文件中省略):

server.c

#include  #include  #include  #include  #include  #include  #include  int listfd; int connfd; int main(int argc, char *argv[]){ /* * Create Sockets */ listfd = socket(AF_UNIX, SOCK_STREAM, 0); if(listfd == -1) exit(-1); struct sockaddr saddr = {AF_UNIX, "server"}; socklen_t saddrlen = sizeof(struct sockaddr) + 6; bind(listfd, &saddr, saddrlen); listen(listfd, 10); fflush(stdout); printf("Running...\n"); /* * Listen for connections * and send random phrase on accept */ while(1){ connfd = accept(listfd, NULL, NULL); int r = rand() % num_of_lines; //Pick random phrase/hint pair write(connfd, phrases[r], strlen(phrases[r])); close(connfd); sleep(1); } exit(0); } 

client.c

 #include  #include  #include  #include  #include  #include  #include  int main(int argc, char *argv[]) { int sock; int conn; struct sockaddr saddr = {AF_UNIX, "server"}; socklen_t saddrlen = sizeof(struct sockaddr) + 6; sock = socket(AF_UNIX, SOCK_STREAM, 0); conn = connect(sock, &saddr, saddrlen); char BUFF[1024]; read(sock, BUFF, 1024); printf("%s", BUFF); return 0; } 

当我尝试在客户端打印时出现问题。 我运行服务器,但是当我运行客户端时,它只打印垃圾字符,我不完全确定是什么导致了这一点。

非常感谢任何帮助,谢谢!

编辑:

我想出了我的问题。 因为服务器套接字绑定到“服务器”,这也是可执行文件的名称,这导致了很多问题。

重命名sockaddr.sa_data字段修复了我的问题。

你有很多问题。 这是错的:

 struct sockaddr saddr = {AF_UNIX, "server"}; socklen_t saddrlen = sizeof(struct sockaddr) + 6; 

你告诉内核“这是一个代表套接字地址的字节包。它的sizeof(struct sockaddr) + 6个字节长”,但你只传递sizeof(struct sockaddr)字节。 结果:内核读取您的地址超出范围,最多导致系统调用失败并导致EFAULT ,最坏情况导致内核读入垃圾数据。

设置AF_UNIX套接字地址的正确方法是使用用于AF_UNIX套接字的套接字地址类型,即struct sockaddr_un (请参阅unix(7) ):

 struct sockaddr_un saddr = {AF_UNIX, "/socket/path"}; bind(listfd, (struct sockaddr *)&saddr, sizeof(saddr)); 

同样,调用connect(2)的客户端代码也应该以相同的方式设置地址。

接下来,您需要检查错误。 几乎所有系统调用都可能失败,因此您需要在每次调用后检查失败并正确处理它(通常关闭套接字和/或使用适当的错误消息终止进程)。

如您所述,您还需要为套接字选择合适的路径名。 命名的AF_UNIX套接字存在于文件系统中,因此不能与任何其他文件共享相同的名称,包括服务器和客户端程序。

您对read(2)调用需要使用返回值来确定读取的字节数。 它不会终止其输出 – 如果它读取4个字节,那么这4个字节将在您的缓冲区中,之后的所有其他内容将是不确定的。 由于printf期望其输入为空终止,因此您需要自己显式地对其进行null终止,或者传递长度,例如:

 int n = read(sock, BUFF, sizeof(BUFF)); if (n < 0) { /* Handle error */ } printf("%.*s", n, BUFF); 
 read(sock, BUFF, 1024); 

没有NULL终止缓冲区。 你需要明确地做。 它返回读取的字节数,并将许多字节复制到缓冲区。

  readlen = read(sock, BUFF, 1024); BUFF[readlen] = '\0'; 

检查connect的返回值并read任何错误。 检查服务器发送的内容