AF_UNIX 地址系列(使用 AF_UNIX 或 AF_UNIX_CCSID 地址系列的套接字)可以是面向连接的(类型 SOCK_STREAM),也可以是无连接的(类型 SOCK_DGRAM)。两种类型都很可靠,原因是没有连接两个进程的外部通信函数。
UNIX 域数据报套接字的运行方式与 UDP 数据报套接字有所不同。借助 UDP 数据报套接字,客户机程序就不必调用 bind() 函数,原因是系统会自动指定未使用的端口号。于是服务器可将数据报发送回该端口号。但是,使用 UNIX 域数据报套接字,系统不会自动指定客户机的路径名。因此,使用 UNIX 域数据报的所有客户机程序必须调用bind() 函数。在客户机的 bind() 上指定的精确路径名就是传递至服务器的路径名。因此,如果客户机指定相对路径名(即,并非以 / 开头的全限定路径名),除非服务器以同一当前目录运行,否则它不能向客户机发送数据报。
应用程序可能对此地址系列使用的示例路径名就是 /tmp/myserver 或 servers/thatserver。借助 servers/thatserver,可使用并非全限定(未指定 /)的路径名。这表示该项在文件系统层次结构中的位置应根据当前工作目录确定。
下图举例说明了 AF_UNIX 地址系列的客户机/服务器关系。有关将环境设置为使用 AF_UNIX 地址系列的详细信息,参见套接字编程的先决条件。
套接字事件流:使用 AF_UNIX 地址系列的服务器应用程序
示例:使用 AF_UNIX 地址系列的服务器应用程序使用以下函数调用序列:
AF_UNIX 或 AF_UNIX_CCSID 是支持 socketpair() 函数的唯一地址系列。socketpair() 函数返回未命名的和已连接的套接字描述符。
UNIX 域套接字的名称空间由路径名组成。当套接字程序调用 bind() 函数时,会在文件系统目录中创建一项。如果路径名已存在,则bind() 失败。因此,UNIX 域套接字程序应总是调用 unlink() 函数以在结束时除去该目录项。
套接字事件流:使用 AF_UNIX 地址系列的客户机应用程序
示例:使用 AF_UNIX 地址系列的客户机应用程序使用以下函数调用序列:
AF_UNIX 或 AF_UNIX_CCSID 是支持 socketpair() 函数的唯一地址系列。socketpair() 函数返回未命名的和已连接的套接字描述符。
程序说明:
程序里包含服务端和客户端两个程序,它们之间使用 AF_UNIX 实现本机数据流通信。使用 AF_UNIX 域实际上是使用本地 socket 文件来通信。
服务器端代码:
引用
#include <sys/types.h> #include <sys/socket.h> #include <stdio.h> #include <sys/un.h> #include <unistd.h> #include <stdlib.h> int main (int argc, char *argv[]) { int server_sockfd, client_sockfd; int server_len, client_len; struct sockaddr_un server_address; /*声明一个UNIX域套接字结构*/ struct sockaddr_un client_address; int i, bytes; char ch_send, ch_recv; unlink ("server_socket"); /*删除原有server_socket对象*/ /*创建 socket, 通信协议为AF_UNIX, SCK_STREAM 数据方式*/ server_sockfd = socket (AF_UNIX, SOCK_STREAM, 0); /*配置服务器信息(通信协议)*/ server_address.sun_family = AF_UNIX; /*配置服务器信息(socket 对象)*/ strcpy (server_address.sun_path, "server_socket"); /*配置服务器信息(服务器地址长度)*/ server_len = sizeof (server_address); /*绑定 socket 对象*/ bind (server_sockfd, (struct sockaddr *)&server_address, server_len); /*监听网络,队列数为5*/ listen (server_sockfd, 5); printf ("Server is waiting for client connect...\n"); client_len = sizeof (client_address); /*接受客户端请求; 第2个参数用来存储客户端地址; 第3个参数用来存储客户端地址的大小*/ /*建立(返回)一个到客户端的文件描述符,用以对客户端的读写操作*/ client_sockfd = accept (server_sockfd, (struct sockaddr *)&server_address, (socklen_t *)&client_len); if (client_sockfd == -1) { perror ("accept"); exit (EXIT_FAILURE); } printf ("The server is waiting for client data...\n"); for (i = 0, ch_send = '1'; i < 5; i++, ch_send++) { if ((bytes = read (client_sockfd, &ch_recv, 1)) == -1) { perror ("read"); exit (EXIT_FAILURE); } printf ("The character receiver from client is %c\n", ch_recv); sleep (1); if ((bytes = write (client_sockfd, &ch_send, 1)) == -1) { perror ("read"); exit (EXIT_FAILURE); } } close (client_sockfd); unlink ("server socket"); }
#include <sys/types.h> #include <sys/socket.h> #include <stdio.h> #include <sys/un.h> #include <unistd.h> #include <stdlib.h> int main (int argc, char *argv[]) { struct sockaddr_un address; int sockfd; int len; int i, bytes; int result; char ch_recv, ch_send; /*创建socket,AF_UNIX通信协议,SOCK_STREAM数据方式*/ if ((sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { perror ("socket"); exit (EXIT_FAILURE); } address.sun_family = AF_UNIX; strcpy (address.sun_path, "server_socket"); len = sizeof (address); /*向服务器发送连接请求*/ result = connect (sockfd, (struct sockaddr *)&address, len); if (result == -1) { printf ("ensure the server is up\n"); perror ("connect"); exit (EXIT_FAILURE); } for (i = 0, ch_send = 'A'; i < 5; i++, ch_send++) { if ((bytes = write(sockfd, &ch_send, 1)) == -1) { /*发消息给服务器*/ perror ("write"); exit (EXIT_FAILURE); } sleep (2); /*休息二秒钟再发一次*/ if ((bytes = read (sockfd, &ch_recv, 1)) == -1) { /*接收消息*/ perror ("read"); exit (EXIT_FAILURE); } printf ("receive from server data is %c\n", ch_recv); } close (sockfd); return (0); }