- 不需要IP和Port, 而是通过一个文件名来表示
- domain 为 AF_UNIX
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,可使用并非全限定(未指定 /)的路径名。这表示该项在文件系统层次结构中的位置应根据当前工作目录确定。
注意:
文件系统中的路径名是启用了 NLS 的。
下图举例说明了 AF_UNIX 地址系列的客户机/服务器关系。有关将环境设置为使用 AF_UNIX 地址系列的详细信息,参见套接字编程的先决条件。
在服务器和客户机 AF_UNIX 地址系列示例程序中使用的套接字事件流。
套接字事件流:使用 AF_UNIX 地址系列的服务器应用程序
示例:使用 AF_UNIX 地址系列的服务器应用程序使用以下函数调用序列:
socket() 函数返回表示端点的套接字描述符。该语句还标识将对此套接字使用带有流传输(SOCK_STREAM)的 UNIX 地址系列。该函数返回表示端点的套接字描述符。还可使用socketpair() 函数初始化 UNIX 套接字。
AF_UNIX 或 AF_UNIX_CCSID 是支持 socketpair() 函数的唯一地址系列。socketpair() 函数返回未命名的和已连接的套接字描述符。
在创建套接字描述符之后,bind() 函数获取套接字的唯一名称。
UNIX 域套接字的名称空间由路径名组成。当套接字程序调用 bind() 函数时,会在文件系统目录中创建一项。如果路径名已存在,则bind() 失败。因此,UNIX 域套接字程序应总是调用 unlink() 函数以在结束时除去该目录项。
listen() 允许服务器接受入局客户机连接。在此示例中,储备设置为 10。这表示系统将对 10 个入局连接请求排队,然后才开始拒绝入局请求。
recv() 函数从客户机应用程序接收数据。在此示例中,我们知道客户机将发送超过 250 字节的数据。既然如此,就可以使用 SO_RCVLOWAT 套接字选项指定在所有 250 字节数据都到达之前不要唤醒recv()。
send()函数将数据回传至客户机。
close() 函数关闭所有打开的套接字描述符。
unlink() 函数从文件系统除去 UNIX 路径名。
套接字事件流:使用 AF_UNIX 地址系列的客户机应用程序
示例:使用 AF_UNIX 地址系列的客户机应用程序使用以下函数调用序列:
socket() 函数返回表示端点的套接字描述符。该语句还标识将对此套接字使用带有流传输(SOCK_STREAM)的 UNIX 地址系列。该函数返回表示端点的套接字描述符。还可使用socketpair() 函数初始化 UNIX 套接字。
AF_UNIX 或 AF_UNIX_CCSID 是支持 socketpair() 函数的唯一地址系列。socketpair() 函数返回未命名的和已连接的套接字描述符。
接收到套接字描述符后,使用 connect() 函数来建立与服务器的连接。
send()函数发送指定的 250 字节数据,该数据是在服务器应用程序中使用 SO_RCVLOWAT 套接字选项指定的。
recv() 函数一直循环,直到所有 250 字节数据都到达为止。
close() 函数关闭所有打开的套接字描述符。
程序说明:
程序里包含服务端和客户端两个程序,它们之间使用 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);
}
程序说明:
先运行服务器端,然后再运行客户端可以在两边同时看到输出。服务器端先运行后会出现如下提示:
引用
./sock_local_server
Server is waiting for client connect...
这表示,服务器端已经被阻塞到到 accept() 这里,服务器就在此等候客户端的连接。
如果不是先运行服务器端,而直接运行客户端,那么客户端会提示:
引用
./sock_local_client
ensure the server is up
connect: Connection refused
提示服务器没有准备好,连接被拒绝,从而直接退出程序。
如果服务器和客户端依次运行,可以在两边看到输出:
服务器端:
引用
./sock_local_server
Server is waiting for client connect...
The server is waiting for client data...
The character receiver from client is A
The character receiver from client is B
The character receiver from client is C
The character receiver from client is D
The character receiver from client is E
客户端:
引用
./sock_local_client
receive from server data is 1
receive from server data is 2
receive from server data is 3
receive from server data is 4
receive from server data is 5