UNIX域数据报套接字的流程可参考 UDP
套接字编程。
服务器端
服务器端流程如下:
实现示例:( server.c 文件)
#include <stdio.h> #include <arpa/inet.h> #include <sys/types.h> #include <sys/socket.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <strings.h> #include <sys/un.h> #define N 128 #define errlog(errmsg) \ do { \ perror(errmsg); \ printf("--%s--%s--%d--\n", __FILE__, __FUNCTION__, __LINE__); \ return -1; \ } while (0) int main(int argc, const char *argv[]) { int sockfd; struct sockaddr_un serveraddr, clientaddr; socklen_t addrlen = sizeof(serveraddr); char buf[N] = {}; //Step1. 创建套接字 if ((sockfd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) { errlog("fail to socket"); } // Step2. 填充服务器本地信息结构体 serveraddr.sun_family = AF_UNIX; strcpy(serveraddr.sun_path, argv[1]); // Step3. 将套接字与服务器本地信息结构体绑定 if (bind(sockfd, (struct sockaddr *)&serveraddr, addrlen) < 0) { errlog("fail to bind"); } ssize_t bytes; while (1) { if ((bytes = recvfrom(sockfd, buf, N, 0, (struct sockaddr *)&clientaddr, &addrlen)) < 0) { errlog("fail to recvfrom"); } else { printf("clientaddr.sun_path = %s\n", clientaddr.sun_path); if (strncmp(buf, "quit", 4) == 0) { printf("client quit\n"); } else { printf("client: %s\n", buf); strcat(buf, " *_*"); if (sendto(sockfd, buf, N, 0, (struct sockaddr *)&clientaddr, addrlen) < 0) { errlog("fail to sendto"); } } } } close(sockfd); return 0; }点击复制复制失败已复制
客户端
客户端流程如下:
实现示例:( client.c 文件)
#include <stdio.h> #include <arpa/inet.h> #include <sys/types.h> #include <sys/socket.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <sys/un.h> #define N 128 #define errlog(errmsg) \ do { \ perror(errmsg); \ printf("--%s--%s--%d--\n", __FILE__, __FUNCTION__, __LINE__); \ return -1; \ } while (0) int main(int argc, const char *argv[]) { int sockfd; struct sockaddr_un serveraddr; socklen_t addrlen = sizeof(serveraddr); char buf[N] = {}; // Step1. 创建套接字 if ((sockfd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) { errlog("fail to socket"); } // Step2. 填充服务器本地信息结构体 serveraddr.sun_family = AF_UNIX; strcpy(serveraddr.sun_path, argv[1]); // 客户端需要绑定自己的信息,否则服务器无法给客户端发送数据 struct sockaddr_un clientaddr; clientaddr.sun_family = AF_UNIX; strcpy(clientaddr.sun_path, argv[2]); if (bind(sockfd, (struct sockaddr *)&clientaddr, addrlen) < 0) { errlog("fail to bind"); } while (1) { fgets(buf, N, stdin); buf[strlen(buf) - 1] = '\0'; if (sendto(sockfd, buf, N, 0, (struct sockaddr *)&serveraddr, addrlen) < 0) { errlog("fail to sendto"); } if (strncmp(buf, "quit", 4) == 0) { printf("client is quited\n"); break; } else { if (recvfrom(sockfd, buf, N, 0, (struct sockaddr *)&serveraddr, &addrlen) < 0) { errlog("fail to recv"); } printf("server: %s\n", buf); } } close(sockfd); return 0; }点击复制复制失败已复制
上述客户端代码中,需要注意的是,UNIX域数据报套接字与网络数据报套接字( UDP
)不同的是,前者的客户端一定要绑定自己的信息结构体。数据报套接字在用于网络通信时,服务器可以为客户端自动分配地址和端口。而在本地通信时,服务器不会为客户端分配套接字文件(本地信息结构体)。如果客户端不绑定自己的信息结构体,服务器则无法知道客户端是谁。
运行交互
先运行服务端,后运行客户端,在客户端输入发送的数据即可。
运行服务端:
$ gcc server.c -o server && ./server dgram点击复制复制失败已复制
运行客户端:
$ gcc client.c -o client && ./client dgram dgram_client点击复制复制失败已复制
效果如下:
提示
运行会生成两个文件 dgram
和 dgram_client
,与UNIX域流式套接字一样,不删除无法启动,但是有一点不同,可以先运行客户端,后运行服务端。