UNIX域流式套接字的用法与TCP套接字基本一致,区别就在于使用的协议和地址不同。
UNIX域流式套接字服务器器端流程以及示例代码如下。
(1)创建UNIX域流式套接字。
(2)将套接字文件描述符与本地信息结构体绑定。
(3)设置监听模式。
(4)接收客户端的连接请求。
(5)发送、接收数据。
1 #include <stdio.h>
2 #include <arpa/inet.h>
3 #include <sys/types.h>
4 #include <sys/socket.h>
5 #include <stdlib.h>
6 #include <unistd.h>
7 #include <string.h>
8 #include <strings.h>
9 #include <sys/un.h>
10
11 #define N 128
12 #define errlog(errmsg) do{perror(errmsg);\
13 printf("%s--%s--%d\n",\
14 __FILE__, __func__, __LINE__);\
15 exit(1);\
16 }while(0)
17
18 int main(int argc, const char *argv[])
19 {
20 int sockfd, acceptfd;
21 struct sockaddr_un serveraddr, clientaddr;
22 socklen_t addrlen = sizeof(serveraddr);
23 char buf[N] = {};
24
25 //初始化结构体
26 bzero(&serveraddr, addrlen);
27 bzero(&clientaddr, addrlen);
28
29 //第一步:创建套接字
30 if((sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0){
31 errlog("fail to socket");
32 }
33
34 //第二步:填充服务器本地信息结构体
35 serveraddr.sun_family = AF_UNIX;
36 strcpy(serveraddr.sun_path, argv[1]);
37
38 //第三步:将套接字与服务器网络信息结构体绑定
39 if(bind(sockfd, (struct sockaddr *)&serveraddr, addrlen) < 0){
40 errlog("fail to bind");
41 }
42
43 //第四步:将套接字设置为被动监听模式
44 if(listen(sockfd, 5) < 0){
45 errlog("fail to listen");
46 }
47
48 //第五步:阻塞等待客户端的连接请求
49 if((acceptfd = accept(sockfd,\
50 (struct sockaddr *)&clientaddr, &addrlen)) < 0){
51 errlog("fail to accept");
52 }
53
54 ssize_t bytes;
55 while(1){
56 if((bytes = recv(acceptfd, buf, N, 0)) < 0){
57 errlog("fail to recv");
58 }
59 else if(bytes == 0){
60 printf("NO DATA\n");
61 exit(1);
62 }
63 else{
64 if(strncmp(buf, "quit", 4) == 0){
65 printf("client quit\n");
66 break;
67 }
68 else{
69 printf("client: %s\n", buf);
70
71 strcat(buf, " *_*");
72
73 if(send(acceptfd, buf, N, 0) < 0){
74 errlog("fail to send");
75 }
76 }
77 }
78 }
79
80 close(acceptfd);
81 close(sockfd);
82
83 return 0;
84 }
UNIX域流式套接字客户端流程及代码示例如下。
(1)创建UNIX域流式套接字。
(2)指定服务器端地址(套接字文字)。
(3)建立连接。
(4)发送、接收数据。
1 #include <stdio.h>
2 #include <arpa/inet.h>
3 #include <sys/types.h>
4 #include <sys/socket.h>
5 #include <stdlib.h>
6 #include <unistd.h>
7 #include <string.h>
8 #include <sys/un.h>
9
10 #define N 128
11 #define errlog(errmsg) do{perror(errmsg);\
12 printf("%s--%s--%d\n",\
13 __FILE__, __func__, __LINE__);\
14 exit(1);\
15 }while(0)
16
17 int main(int argc, const char *argv[])
18 {
19 int sockfd;
20 struct sockaddr_un serveraddr;
21 socklen_t addrlen = sizeof(serveraddr);
22 char buf[N] = {};
23
24 //第一步:创建套接字
25 if((sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0){
26 errlog("fail to socket");
27 }
28
29 //第二步:填充服务器本地信息结构体
30 serveraddr.sun_family = AF_UNIX;
31 strcpy(serveraddr.sun_path, argv[1]);
32
33 //第三步:发送客户端连接请求
34 if(connect(sockfd, (struct sockaddr *)&serveraddr, addrlen) < 0){
35 errlog("fail to connect");
36 }
37
38 while(1){
39 fgets(buf, N, stdin);
40 buf[strlen(buf) - 1] = '\0';
41
42 if(send(sockfd, buf, N, 0) < 0){
43 errlog("fail to send");
44 }
45
46 if(strncmp(buf, "quit", 4) == 0){
47 printf("client is quited\n");
48 break;
49 }
50 else {
51 if(recv(sockfd, buf, N, 0) < 0){
52 errlog("fail to recv");
53 }
54
55 printf("server: %s\n", buf);
56 }
57 }
58
59 close(sockfd);
60
61 return 0;
62 }
上述客户端代码中,需要注意的是,UNIX域数据报套接字与网络数据报套接字(UDP)不同的是前者的客户端一定要绑定自己的信息结构体。数据报套接字在用于网络通信时,服务器可以为客户端自动分配地址和端口号。而在本地通信时,服务器不会为客户端分配套接字文件(本地信息结构体)。如果客户端不绑定自己的信息结构体,服务器则无法知道客户端是谁。
先运行服务器端,再运行客户端,在客户端终端输入发送的数据即可。客户端的运行结果如下所示,命令行传参为套接字文件的名称。客户端发送数据,服务器将数据修改之后,回复给客户端。输入“quit”,客户端与服务器退出。
linux@Master:~/1000phone/net/unix_dgram$ ./client dgram dgram_client
hello world
server: hello world *_*
quit
client is quited
服务器的运行结果如下所示。
linux@Master:~/1000phone/net/unix_dgram$ ./server dgram
clientaddr.sun_path = dgram_client
client: hello world
clientaddr.sun_path = dgram_client
client quit
在当前目录下自动创建的套接字文件如下所示。
linux@Master:~/1000phone/net/unix_dgram$ ls -l dgram*
srwxrwxr-x 1 linux linux 0 6月 21 15:16 dgram
srwxrwxr-x 1 linux linux 0 6月 21 15:16 dgram_client