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 108
struct 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 socket
int 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.listen
if(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.close
close(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 socket
int 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;
}