unix域
unix域协议并不是一个实际的协议族,而是在单个主机上执行客户/服务器通信的一种方法。
unix域是基于socket通信的一个特例unix进程通信,因为他的实现中使用了socket技术,但是他是基于单个主机上的进程间通信。因为在同一个主机内,所以就少了很多网络上的问题,那就减少了复杂度。unix域和传统的socket通信类型,服务器监听,客户端连接,由于在同主机,就不必要使用ip和端口的方式,浪费一个端口。unix域采用的是一个文件作为标记。大致原理如下。
1 服务器首先拿到一个socket结构体,和一个unix域相关的unix_proto_data结构体。
2 服务器bind一个文件。对于操作系统来说,就是新建一个文件,然后把文件路径信息存在unix_proto_data中。
3 listen
4 客户端通过同样的文件路径调用connect去连接服务器。这时候客户端的结构体插入服务器的连接队列,等待处理。
5 服务器调用accept摘取队列的节点,然后新建一个通信socket进行通信。
unix域通信本质还是基于内存之间的通信,客户端和服务器都维护一块内存,然后实现全双工通信,而unix域的文件路径,只不过是为了让客户端进程可以找到服务端进程。而通过connect和accept让客户端和服务器对应的结构体关联起来,后续就可以互相往对方维护的内存里写东西了。就可以实现进程间通信。
使用unix域套接字的三个好处:
unix域套接字中用于标识客户和服务器的协议地址是普通文件系统中的路径名。
socketpair函数
socketpair函数创建两个随后连接起来的套接字,本函数仅适用于unix域套接字。
#include int socketpair(int family, int type, int protocol, int sockfd[2]);/* 成功返回非0,失败返回-1 */
其中,family为AF_LOCAL, protocol为0,type可以为SOCK_STREAM或者SOCK_DGRAM。新创建的两个套接字描述符作为sockfd[0],sockfd[1]返回。
该函数与unix的pipe函数类似,返回两个彼此连接的描述符
使用字节流模式实现客户/服务器回射程序
服务器端程序:
#include #include #include #include #include #include #include
#define MAXLINE 4096 #define LISTENQ 1024 #define UNIX_STREAM_PATH "/tmp/unix_stream_path"
void str_echo(int sockfd) { ssize_t n; char buf[MAXLINE];
again: while ((n = read(sockfd, buf, MAXLINE)) > 0) { write(sockfd, buf, n); }
if (n < 0 && errno == EINTR) { goto again; } else if (n < 0) { printf("str_echo read error: %s\n", strerror(errno)); exit(-1); } } int main(int argc, char **argv) { int ret; int listenfd, connfd; pid_t childpid; socklen_t clilen; struct sockaddr_un cliaddr, servaddr;
listenfd = socket(AF_LOCAL, SOCK_STREAM, 0); if (listenfd < 0) { printf("socket error: %s\n", strerror(errno)); return -1; }
unlink(UNIX_STREAM_PATH); bzero(&servaddr, sizeof(servaddr)); servaddr.sun_family = AF_LOCAL; strncpy(servaddr.sun_path, UNIX_STREAM_PATH, sizeof(servaddr.sun_path) - 1);
ret = bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)); if (ret) { printf("bind error: %s\n", strerror(errno)); return -1; }
ret = listen(listenfd, LISTENQ); if (ret) { printf("listen error: %s\n", strerror(errno)); return -1; }
while (1) { clilen = sizeof(cliaddr); if ((connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &clilen)) < 0) { if (errno == EINTR) { continue; } else { printf("accept error: %s\n", strerror(errno)); return -1; } }
if ((childpid = fork()) == 0) { /* child close listening socket and process connected socket */ close(listenfd); str_echo(connfd); exit(0); } /* parent close connected socket */ close(connfd); } }
客户端:
#include #include #include #include #include #include #include #include
#define MAXLINE 4096 #define UNIX_STREAM_PATH "/tmp/unix_stream_path"
int max(int a, int b) { if (a > b) { return a; } else { return b; } }
void str_cli(FILE *fp, int sockfd) { int maxfdp1, stdineof; fd_set rset; char buf[MAXLINE]; int n;
stdineof = 0; FD_ZERO(&rset);
while (1) { if (stdineof == 0) { FD_SET(fileno(fp), &rset); } FD_SET(sockfd, &rset); maxfdp1 = max(fileno(fp), sockfd) + 1;
select(maxfdp1, &rset, NULL, NULL, NULL);
if (FD_ISSET(sockfd, &rset)) { if ((n = read(sockfd, buf, MAXLINE)) == 0) { if (stdineof == 1) { return; } else { printf("str_cli: server terminated prenatruely\n"); exit(-1); } } write(fileno(stdout), buf, n); }
if (FD_ISSET(fileno(fp), &rset)) { if ((n = read(fileno(fp), buf, MAXLINE)) == 0) { stdineof = 1; shutdown(sockfd, SHUT_WR); FD_CLR(fileno(fp), &rset); continue; } write(sockfd, buf, n); } } }
int main(int argc, char **argv) { int ret, sockfd; struct sockaddr_un servaddr;
sockfd = socket(AF_LOCAL, SOCK_STREAM, 0);
bzero(&servaddr, sizeof(servaddr)); servaddr.sun_family = AF_LOCAL; strncpy(servaddr.sun_path, UNIX_STREAM_PATH, sizeof(servaddr.sun_path)); connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
str_cli(stdin, sockfd);
return 0; }
使用数据报模式实现客户/服务器回射程序
服务器端:
#include #include #include #include #include #include #include
#define MAXLINE 4096 #define UNIX_DGRAM_PATH "/tmp/unix_dgram_path"
void dg_echo(int sockfd, struct sockaddr *pcliaddr, socklen_t clilen) { int n; socklen_t len; char mesg[MAXLINE];
while(1) { len = clilen; n = recvfrom(sockfd, mesg, MAXLINE, 0, pcliaddr, &len);
sendto(sockfd, mesg, n, 0, pcliaddr, len); } }
int main(int argc, char **argv) { int ret, sockfd; struct sockaddr_un cliaddr, servaddr;
sockfd = socket(AF_LOCAL, SOCK_DGRAM, 0); if (sockfd < 0) { printf("socket error: %s\n", strerror(errno)); return -1; }
unlink(UNIX_DGRAM_PATH); bzero(&servaddr, sizeof(servaddr)); servaddr.sun_family = AF_LOCAL; strncpy(servaddr.sun_path, UNIX_DGRAM_PATH, sizeof(servaddr.sun_path) - 1);
ret = bind(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)); if (ret) { printf("bind error: %s\n", strerror(errno)); return -1; }
dg_echo(sockfd, (struct sockaddr *)&cliaddr, sizeof(cliaddr));
}
客户端:
#include #include #include #include #include #include #include
#define MAXLINE 4096 #define UNIX_DGRAM_PATH "/tmp/unix_dgram_path"
void dg_cli(FILE *fp, int sockfd, const struct sockaddr *pservaddr, socklen_t servlen) { int n; char sendline[MAXLINE], recvline[MAXLINE + 1];
while (fgets(sendline, MAXLINE, fp) != NULL) { sendto(sockfd, sendline, strlen(sendline), 0, pservaddr, servlen);
n = recvfrom(sockfd, recvline, MAXLINE, 0, NULL, NULL);
recvline[n] = 0; fputs(recvline, stdout); } }
int main(int argc, char **argv) { int ret, sockfd; struct sockaddr_un cliaddr, servaddr;
sockfd = socket(AF_LOCAL, SOCK_DGRAM, 0); if (sockfd < 0) { printf("socket error: %s\n", strerror(errno)); return -1; }
bzero(&cliaddr, sizeof(cliaddr)); cliaddr.sun_family = AF_LOCAL; strncpy(cliaddr.sun_path, tmpnam(NULL), sizeof(cliaddr.sun_path) - 1);
ret = bind(sockfd, (struct sockaddr *)&cliaddr, sizeof(cliaddr)); if (ret) { printf("bind error: %s\n", strerror(errno)); return -1; }
bzero(&servaddr, sizeof(servaddr)); servaddr.sun_family = AF_LOCAL; strncpy(servaddr.sun_path, UNIX_DGRAM_PATH, sizeof(servaddr.sun_path) - 1);
dg_cli(stdin, sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
return 0; }
(编辑:好传媒网)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
|