分类: LINUX
2009-12-15 01:54:16
Unix域套接字是通过套接字API实现的简单的协议族。实际上它并不代表一个网络协议;它只能连接到同一台机器上的套接字。它提供了灵活的IPC机制。它的地址是它所在的文件系统的路径名,创建之后套接字就和路径名绑定在一起。用来表示Unix域地址的套接字文件能够使用stat()但是不能通过open()打开,而且应该使用套接字API对它进行操作。
Unix域套接字是面向连接的,每个套接字的连接都建立了一个新的通讯信道。服务器可能同时处理许多连接,但对于每个连接都有不同的文件描述符。这个属性使Unix域套接字能够比命名管道更好的适应IPC任务。
.
在一个终端运行服务器,然后在另一个终端(在相同目录下)运行客户端。当从客户端输入一行时,数据将通过套接字送到服务器。当退出客户端,服务器将等待另外一个连接。还可以通过客户端程序的重定向输入来传送文件,cat uclient.c | ./uclient 或 ./uclient < uclient.c。
服务器程序userver.c
/* userver.c - Simple Unix Domain Socket server */
/* Waits for a connection on the ./sample-socket Unix domain
socket. Once a connection has been established, copy data
from the socket to stdout until the other end closes the
connection, and then wait for another connection to the
socket. */
#include
#include
#include
#include
#include "sockutil.h" /* some utility functions */
int main(void) {
struct sockaddr_un address;
int sock, conn;
size_t addrLength;
if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)
die("socket");
/* Remove any preexisting socket (or other file) */
unlink("./sample-socket");
address.sun_family = AF_UNIX; /* Unix domain socket */
strcpy(address.sun_path, "./sample-socket");
/* The total length of the address includes the sun_family
element */
addrLength = sizeof(address.sun_family) +
strlen(address.sun_path);
if (bind(sock, (struct sockaddr *) &address, addrLength))
die("bind");
if (listen(sock, 5))
die("listen");
while ((conn = accept(sock, (struct sockaddr *) &address,
&addrLength)) >= 0) {
printf("---- getting data\n");
copyData(conn, 1);
printf("---- done\n");
close(conn);
}
if (conn < 0)
die("accept");
close(sock);
return 0;
}
客户端程序uclient.c
/* uclient.c - Simple Unix Domain Socket client */
/* Connect to the ./sample-socket Unix domain socket, copy stdin
into the socket, and then exit. */
#include
#include
#include
#include "sockutil.h" /* some utility functions */
int main(void) {
struct sockaddr_un address;
int sock;
size_t addrLength;
if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)
die("socket");
address.sun_family = AF_UNIX; /* Unix domain socket */
strcpy(address.sun_path, "./sample-socket");
/* The total length of the address includes the sun_family
element */
addrLength = sizeof(address.sun_family) +
strlen(address.sun_path);
if (connect(sock, (struct sockaddr *) &address, addrLength))
die("connect");
copyData(0, sock);
close(sock);
return 0;
}
注:如果客户端在服务器bind之前进行connect操作,connect会因为缺少套接字文件而失败。
accept和connect是两个阻塞调用。
/* sockutil.c - Utility functions used in socket example programs */
#include
#include
#include
#include "sockutil.h"
/* issue an error message via perror() and terminate the program */
void die(char * message) {
perror(message);
exit(1);
}
/* Copies data from file descriptor 'from' to file descriptor
'to' until nothing is left to be copied. Exits if an error
occurs. This assumes both from and to are set for blocking
reads and writes. */
void copyData(int from, int to) {
char buf[1024];
int amount;
while ((amount = read(from, buf, sizeof(buf))) > 0) {
if (write(to, buf, amount) != amount) {
die("write");
return;
}
}
if (amount < 0)
die("read");
}