UNIX 域协议并不是一个实际的协议族,而是在单个主机上执行客户/服务器通信的一种方式。UNIX域提供两类套接字:字节流套接字(类似TCP)和数据报套接字(类似UDP)
Unix 域套接字的地址结构
struct sockaddr_un {
sa_family_t sun_family; /*AF_UNIX*/
char sun_path[108]; /*pathname*/
};
域套接字函数
socketpair 函数
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int socketpair(int domain, int type, int protocol, int sv[2]);
domain 必须是AF_LOCAL
protocol 必须是 0
type 可以是SOCK_STREAM 或者SOCK_DGRAM
新创建的两个套接字描述符sv[0],sv[1];
域套接字和套接字存在的差别
程序实例
服务端程序
#include <sys/types.h> /* basic system data types */
#include <sys/socket.h> /* basic socket definitions */
#include <sys/time.h> /* timeval{} for select() */
#include <time.h> /* timespec{} for pselect() */
#include <netinet/in.h> /* sockaddr_in{} and other Internet defns */
#include <arpa/inet.h> /* inet(3) functions */
#include <netinet/sctp.h> /* note if sctp does not exist we blow up :> */
#include <errno.h>
#include <fcntl.h> /* for nonblocking */
#include <netdb.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h> /* for S_xxx file mode constants */
#include <sys/uio.h> /* for iovec{} and readv/writev */
#include <unistd.h>
#include <sys/wait.h>
#include <sys/un.h> /* for Unix domain sockets */
#define UNIXSTR_PATH "/tmp/unix.str" /* Unix domain stream cli-serv */
#define UNIXDG_PATH "/tmp/unix.dg" /* Unix domain datagram cli-serv */
void str_echo(int sockfd)
{
ssize_t n;
char buf[65507];
again:
while ( (n = read(sockfd, buf, 65507)) > 0)
Writen(sockfd, buf, n);
if (n < 0 && errno == EINTR)
goto again;
else if (n < 0)
err_sys("str_echo: read error");
}
int main(int argc, char **argv)
{
int listenfd, connfd;
pid_t childpid;
socklen_t clilen;
struct sockaddr_un cliaddr, servaddr;
void sig_chld(int);
listenfd = Socket(AF_LOCAL, SOCK_STREAM, 0);
unlink(UNIXSTR_PATH);
bzero(&servaddr, sizeof(servaddr));
servaddr.sun_family = AF_LOCAL;
strcpy(servaddr.sun_path, UNIXSTR_PATH);
Bind(listenfd, (SA *) &servaddr, sizeof(servaddr));
Listen(listenfd, LISTENQ);
Signal(SIGCHLD, sig_chld);
for ( ; ; ) {
clilen = sizeof(cliaddr);
if ( (connfd = accept(listenfd, (SA *) &cliaddr, &clilen)) < 0) {
if (errno == EINTR)
continue; /* back to for() */
else
err_sys("accept error");
}
if ( (childpid = Fork()) == 0) { /* child process */
Close(listenfd); /* close listening socket */
str_echo(connfd); /* process the request */
exit(0);
}
Close(connfd); /* parent closes connected socket */
}
}
客户端程序
#include <sys/types.h> /* basic system data types */
#include <sys/socket.h> /* basic socket definitions */
#include <sys/time.h> /* timeval{} for select() */
#include <time.h> /* timespec{} for pselect() */
#include <netinet/in.h> /* sockaddr_in{} and other Internet defns */
#include <arpa/inet.h> /* inet(3) functions */
#include <netinet/sctp.h> /* note if sctp does not exist we blow up :> */
#include <errno.h>
#include <fcntl.h> /* for nonblocking */
#include <netdb.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h> /* for S_xxx file mode constants */
#include <sys/uio.h> /* for iovec{} and readv/writev */
#include <unistd.h>
#include <sys/wait.h>
#include <sys/un.h> /* for Unix domain sockets */
#define UNIXSTR_PATH "/tmp/unix.str" /* Unix domain stream cli-serv */
#define UNIXDG_PATH "/tmp/unix.dg" /* Unix domain datagram cli-serv */
void str_cli(FILE *fp, int sockfd)
{
char sendline[65507], recvline[65507];
while (Fgets(sendline, 65507, fp) != NULL) {
Writen(sockfd, sendline, strlen(sendline));
if (Readline(sockfd, recvline, 65507) == 0)
err_quit("str_cli: server terminated prematurely");
Fputs(recvline, stdout);
}
}
int main(int argc, char **argv)
{
int sockfd;
struct sockaddr_un servaddr;
sockfd = Socket(AF_LOCAL, SOCK_STREAM, 0);
bzero(&servaddr, sizeof(servaddr));
servaddr.sun_family = AF_LOCAL;
strcpy(servaddr.sun_path, UNIXSTR_PATH);
Connect(sockfd, (SA *) &servaddr, sizeof(servaddr));
str_cli(stdin, sockfd); /* do it all */
exit(0);
}