UNIX域流式套接字的用法与 TCP
编程基本一致,区别就在于使用的协议和地址不同。
服务端
UNIX域流式套接字实现本地通信服务器端流程如下:
实现示例:(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, acceptfd; struct sockaddr_un serveraddr, clientaddr; socklen_t addrlen = sizeof(serveraddr); char buf[N] = {}; // 初始化结构体 bzero(&serveraddr, addrlen); bzero(&clientaddr, addrlen); // Step1. 创建套接字 if ((sockfd = socket(AF_UNIX, SOCK_STREAM, 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"); } // Step4. 将套接字设置为被动监听模式 if (listen(sockfd, 5) < 0) { errlog("fail to listen"); } // Step5. 阻塞等待客户端的连接请求 if ((acceptfd = accept(sockfd, (struct sockaddr *)&clientaddr, &addrlen)) < 0) { errlog("fail to accept"); } ssize_t bytes; while (1) { if ((bytes = recv(acceptfd, buf, N, 0)) < 0) { errlog("fail to recv"); } else if (bytes == 0) { printf("NO DATA\n"); exit(1); } else { if (strncmp(buf, "quit", 4) == 0) { printf("client quit\n"); break; } else { printf("client: %s\n", buf); strcat(buf, " *_*"); if (send(acceptfd, buf, N, 0) < 0) { errlog("fail to send"); } } } } close(acceptfd); close(sockfd); return 0; }点击复制复制失败已复制
客户端
UNIX域流式套接字实现本地通信客户端流程如下所示:
实现示例:( 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_STREAM, 0)) < 0) { errlog("fail to socket"); } // Step2. 填充服务器本地信息结构体 serveraddr.sun_family = AF_UNIX; strcpy(serveraddr.sun_path, argv[1]); // Step3. 发送客户端请求 if (connect(sockfd, (struct sockaddr *)&serveraddr, addrlen) < 0) { errlog("fail to connect"); } while (1) { fgets(buf, N, stdin); buf[strlen(buf) - 1] = '\0'; if (send(sockfd, buf, N, 0) < 0) { errlog("fail to send"); } if (strncmp(buf, "quit", 4) == 0) { printf("client is quired\n"); break; } else { if (recv(sockfd, buf, N, 0) < 0) { errlog("fail to recv"); } printf("server: %s\n", buf); } } close(sockfd); return 0; }点击复制复制失败已复制
运行交互
先运行服务端,再运行客户端,客户端终端输入发送的数据即可。
提示
UNIX域套接字实现本地通信有点类似于管道,即通过 文件
实现通信。
运行服务端:
$ gcc server.c -o server && ./server ./stream点击复制复制失败已复制
运行客户端:
$ gcc client.c -o client && ./client ./stream点击复制复制失败已复制
之后客户端分别输入 hello
、 world
和 quite
,效果如下:
提示
./stream
为当前目录下的文件 stream
,不需要提前创建,程序运行自动创建。 server
服务退出,本示例不会主动清除 stream
文件,须手动清除,否则下次运行会提示错误: fail to bind: Address already in use --server.c--main--40--
。如果有 stream
文件,但是 server
未运行,直接运行 client
会提示: fail to bind: Address already in use --server.c--main--40--
。如果没有 stream
文件,直接运行 client
会提示: fail to connect: No such file or directory --client.c--main--35--