C语言---Unix套接字用于本地通信
1、作用:用于本地间通信
2、使用:
创建套接字的时候使用本地协议通信,AF_UNIX(或者AF_LOCAL),分为流式套接字和用户数据报套接字。
unix_socket = socket(AF_LOCAL, SOCK_STREAM, 0);
unix_socket = socket(AF_LOCAL, SOCK_DGRAM, 0);
3、进程间通信:(6种情况)
3.1进程间数据共享:
管道、消息队列、共享内存、unix套接字
易用性:消息队列>unix套接字>管道>共享内存(经常要和信号量一起用)
效率上:共享内存>unix套接字>管道>消息队列
共享内存相当于把一块内存从内核空间放到内存空间去操作。
效率上,常常共享内存和信号量一起使用,或者unix套接字。
3.2异步通信:
信号
3.3同步和互斥:
信号量
4、Unix域套接字
/*本地地址结构*/#include <sys/un.h>
strcut sockaddr_in{sa_family_t sun_family; char sun_path[108]; //套接字文件的路径
};/*填充地址结构*/
strcut sockaddr_un myaddr;
bzero(&myaddr, sizeof(myaddr));
myaddr.sun_family = AF_UNIX;
strcpy(myaddr.sun_path, "/tmp/mysock");
5、
5.1流式套接字服务器端
socket(AF_UNIX, SOCK_STREAM, 0);
bind(,本地地址,); //
listen();
accept(); //可以使用多路复用、多进程、多线程处理
recv() / send()
close()
注意:bind()函数详解
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
之前互联网通信,这里绑定绑定的是通用地址结构体sockaddr。
现在本地通信,绑定的是sockaddr_un结构体,格式如下:
//A UNIX domain socket address is represented in the following structure:#define UNIX_PATH_MAX 108struct sockaddr_un {sa_family_t sun_family; /* AF_UNIX */char sun_path[UNIX_PATH_MAX]; /* pathname */
};//sun_family always contains AF_UNIX / AF_local
// unix_path_max 从96~108,是unix域套接字的文件路径名:
// 注意:1.这个文件(位于内存中)必须事先不存在;2.一般给绝对路径名;
5.2流式套接字客户端
socket(AF_UNIX, SOCK_STREAM, 0);
bind(,本地地址,); //
listen();
accept(); //可以使用多路复用、多进程、多线程处理
recv() / send()
close()
6、实例代码
/*服务器:*/
void sig_child_handle(int signo){if(SIGCHLD == signo){//NULL:状态不许要,WNOHANG非阻塞方式waitpid(-1, NULL, WNOHANG);}
}void cli_data_handle(int *arg);int main(int argc, char *argv[])
{//1.create socketint sockfd;//struct sockaddr_in sin;/* typedef void (*sighandler_t)(int);sighandler_t signal(int signum, sighandler_t handler);*/signal(SIGCHLD, sig_child_handle);if((sockfd = socket(AF_LOCAL, SOCK_STREAM, 0))<0){perror("create socket");return -1;}struct sockaddr_un sun;bzero(&sun, sizeof(sun));sun.sun_family = AF_UNIX;if(!access(UNIX_DOMAIN_FILE, F_OK)){unlink(UNIX_DOMAIN_FILE);}strncpy(sun.sun_path, UNIX_DOMAIN_FILE, strlen(UNIX_DOMAIN_FILE));if( ( bind(sockfd, (struct sockaddr *)(&sun), sizeof(sun)) ) == -1){perror("bind");exit(1);}
//3.listenif(listen(sockfd, BACKLOG)<0){perror("listen");exit(1);}printf("server start\\n");int newfd;while(1){pid_t pid = -1;if((newfd = accept(sockfd, NULL, NULL))<0){perror("accept");break;}//创建一个子进程,用于处理连接的客户端的交互数据if((pid = fork()) < 0){perror("fork");exit(1);}if(pid > 0){//父进程close(newfd);}else if(pid == 0){//子进程close(sockfd);cli_data_handle(&newfd);exit(1);}break;}//6.closeclose(sockfd);return 0;
}
void cli_data_handle(int *arg){int newfd = *(int *)arg;printf("child handling process:newfd=%d\\n", newfd);//5.write() 与newfd读写数据char buf[128];//char resp_buf[138];int ret = -1;while(1){bzero(buf, strlen(buf));do{ret = read(newfd, buf, 127);}while(ret<0 && errno==EINTR);if(ret < 0){perror("read");exit(1);}//客户端已经关闭if(!ret){break;}printf("recive data:%s\\n", buf);if( !strncasecmp(buf, QUIT_STR, strlen(QUIT_STR)) ){printf("client(%d) exiting\\n", newfd);break;}}close(newfd);
}
/*./client unix_domain_file */
#include "inet.h"void usage(char *s){printf("\\n%s unix_domain_file\\n", s);
}int main(int argc, char *argv[])
{ if(argc != 2){ usage(argv[0]);exit(1);} //1.create socketint sockfd;if((sockfd = socket(AF_LOCAL, SOCK_STREAM, 0))<0){perror("create socket");exit(1);}
//2.连接服务器//填充sockaddr_in 结构体变量,struct sockaddr_un sun;bzero(&sun, sizeof(sun));sun.sun_family = AF_LOCAL;/*确保文件先存在并且可写,如果不存在,退出*/if(access(UNIX_DOMAIN_FILE, W_OK) < 0){exit(1);}strncpy(sun.sun_path, UNIX_DOMAIN_FILE, strlen(UNIX_DOMAIN_FILE));if(connect(sockfd, (struct sockaddr *)&sun, sizeof(sun)) < 0){perror("connect");exit(1);}printf("unix start....\\n");//3.read()读写数据int ret = -1;char buf[128];while(1){bzero(buf, 128);if(fgets(buf, 127, stdin) == NULL){continue;}do{ret = write(sockfd, buf, strlen(buf));}while(ret<0 && errno==EINTR);if(! strncasecmp(buf, QUIT_STR, strlen(buf)-1)){printf("client is exiting\\n");break;}}//4.close()关闭套接字close(sockfd);return 0;
}