进程间通信,UNP2 这本经典的书籍讲的已经很清楚了,常见的进程间通信就是信号量 消息队列共享内存,其实本地套接字更是一种进程间通信的手段,而且起码要比信号量更加直观。本文描述下基本的利用本地套接字来进行进程通信。
点击(此处)折叠或打开
#define UNIX_PATH_MAX 108
struct sockaddr_un {
sa_family_tsun_family; /* AF_UNIX */
charsun_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()
{
structsigaction newact,oldact;
newact.sa_handler = SIG_IGN;
sigemptyset(&newact.sa_mask);
newact.sa_flags = 0;
sigaction(SIGPIPE,&newact,&oldact);
return0;
}
int main()
{
int server_sockfd,client_sockfd;
int server_len,client_len;
structsockaddr_un server_address;
structsockaddr_un client_address;
const charpath_unix[] = "MY_SOCKET";
int len_unix;
charbuf[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,(structsockaddr *)&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,(structsockaddr *)&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 charpath_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.
我们看到我们的套接字有了门牌号,这样客户端想要连接的话,就可以根据门牌号,按图索骥的找到我们了。
下面是客户端的代码:
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#defineUNIX_DOMAIN "MY_SOCKET"
int main(void)
{
int connect_fd;
int ret;
charsnd_buf[1024];
int i;
staticstruct sockaddr_un srv_addr;
connect_fd=socket(PF_UNIX,SOCK_STREAM,0);
if(connect_fd<0)
{
fprintf(stderr,"cannotcreate communication socket");
return1;
}
srv_addr.sun_family=AF_UNIX;
strcpy(srv_addr.sun_path,UNIX_DOMAIN);
ret=connect(connect_fd,(structsockaddr*)&srv_addr,sizeof(srv_addr));
if(ret==-1)
{
perror("cannotconnect to the server");
close(connect_fd);
return1;
}
memset(snd_buf,0,1024);
strcpy(snd_buf,"helloserver !");
write(connect_fd,snd_buf,sizeof(snd_buf));
close(connect_fd);
return0;
}
可以看到,关键部分就是加粗的那部分代码,客户端根据sun_path就能找到服务器,然后去连接服务器。我们看到客户端给服务器进程发了个helloserver就退出了。实际工程代码中,可以发送双方约定好的很复杂的数据,告诉服务器进程去处理客户端进程提交的数据。
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