进程间通信,UNP2 这本经典的书籍讲的已经很清楚了,常见的进程间通信就是信号量 消息队列 共享内存,其实本地套接字更是一种进程间通信的手段,而且起码要比信号量更加直观。本文描述下基本的利用本地套接字来进行进程通信。
#define UNIX_PATH_MAX 108
struct sockaddr_un {
sa_family_t sun_family; /* AF_UNIX */
char sun_path[UNIX_PATH_MAX]; /* pathname */
};
可以看到这就是本地套接字的数据结构,110个字节,sun_path相当于socket的门牌号,或者地址,用于通信。我们知道,两个人通信,如果你知道对方的门牌号,那么你就能找到他,和他聊天。本地套接字也是一样,如果我是服务器,就在我门牌号这里等待别人来找我。
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<errno.h>
#include<string.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<sys/socket.h>
#include<sys/un.h>
#include<signal.h>
int pipe_process()
{
struct sigaction newact,oldact;
newact.sa_handler = SIG_IGN;
sigemptyset(&newact.sa_mask);
newact.sa_flags = 0;
sigaction(SIGPIPE,&newact,&oldact);
return 0;
}
int main()
{
int server_sockfd,client_sockfd;
int server_len,client_len;
struct sockaddr_un server_address;
struct sockaddr_un client_address;
const char path_unix[] = "MY_SOCKET";
int len_unix;
char buf[1024];
int n;
unlink("MY_SOCKET");
server_sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
server_address.sun_family = AF_UNIX;
strncpy(server_address.sun_path, path_unix,sizeof(server_address.sun_path));
server_len = sizeof(server_address);
len_unix = SUN_LEN(&server_address);
bind(server_sockfd,(struct sockaddr *)&server_address,server_len);
pipe_process();
listen(server_sockfd, 5);
while(1){
printf("server waiting\n");
client_len = sizeof(client_address);
client_sockfd = accept(server_sockfd,(struct sockaddr *)&client_address, &client_len);
memset(buf,0,sizeof(buf)/sizeof(buf[0]));
n = read(client_sockfd,buf,1024);
if(n < 0)
{
fprintf(stderr,"read failed\n");
return -1;
}
fprintf(stderr,"recv : %s\n",buf);
close(client_sockfd);
}
}
我们看下这几行代码
const char path_unix[] = "MY_SOCKET";
unlink("MY_SOCKET");
server_sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
server_address.sun_family = AF_UNIX;
strncpy(server_address.sun_path, path_unix,sizeof(server_address.sun_path));
server_len = sizeof(server_address);
len_unix = SUN_LEN(&server_address);
bind(server_sockfd,(struct sockaddr *)&server_address,server_len);
我先定义了一个门牌号,然后将我的套接字和门牌号绑定,这样的话,别人就能通过我的门牌号找到我了。这里插一
段,SUN_LEN是一个宏来告知sockaddr_un的有效长度,对于本例子,len_unix = 2 + 9 =11.
bind之前
root@libin:~/program/C/sock/af_unix# netstat -ap|grep -Ei "serv|prot"
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
Proto RefCnt Flags Type State I-Node PID/Program name 路径
unix 2 [ ] 流 394869 4090/server
bind之后(当然也执行了listen)
root@libin:~/program/C/sock/af_unix# netstat -ap|grep -Ei "serv|prot"
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
Proto RefCnt Flags Type State I-Node PID/Program name 路径
unix 2 [ ACC ] 流 LISTENING 394869 4090/server MY_SOCKET
我们看到我们的套接字有了门牌号,这样客户端想要连接的话,就可以根据门牌号,按图索骥的找到我们了。
下面是客户端的代码:
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#define UNIX_DOMAIN "MY_SOCKET"
int main(void)
{
int connect_fd;
int ret;
char snd_buf[1024];
int i;
static struct sockaddr_un srv_addr;
connect_fd=socket(PF_UNIX,SOCK_STREAM,0);
if(connect_fd<0)
{
fprintf(stderr,"cannot create communication socket");
return 1;
}
srv_addr.sun_family=AF_UNIX;
strcpy(srv_addr.sun_path,UNIX_DOMAIN);
ret=connect(connect_fd,(struct sockaddr*)&srv_addr,sizeof(srv_addr));
if(ret==-1)
{
perror("cannot connect to the server");
close(connect_fd);
return 1;
}
memset(snd_buf,0,1024);
strcpy(snd_buf,"hello server !");
write(connect_fd,snd_buf,sizeof(snd_buf));
close(connect_fd);
return 0;
}
可以看到,关键部分就是加粗的那部分代码,客户端根据sun_path就能找到服务器,然后去连接服务器。我们看到客户端给服务器进程发了个hello server就退出了。实际工程代码中,可以发送双方约定好的很复杂的数据,告诉服务器进程去处理客户端进程提交的数据。
OK,看下效果: 先启动服务器进程,可以看到服务器在等待客户来连接。root@libin:~/program/C/sock/af_unix# ./server
server waiting
然后启动客户端进程,客户段打了招呼就退出了,
root@libin:~/program/C/sock/af_unix# ./client
root@libin:~/program/C/sock/af_unix#
看下服务器的反应:服务器的确是收到了发来的语句,同时继续等待。
recv : hello server !
server waiting
转载自:http://blog.chinaunix.net/uid-24774106-id-3165204.html