天气转暖,脱掉羽绒长衫,换上格子衬衫。我不但知道4种茴字写法,我还知道进程间通信的6种方法。6种!
从操作系统层面看进程通信:我们知道,为了保证安全,每个进程的用户地址空间都是独立的,一般而言一个进程不能直接访问另一个进程的地址空间,不过内核空间是每个进程都共享的,所以进程之间想要进行信息交换就必须通过内核
- 管道
- 消息队列
- 共享内存
- 信号量
- 信号
套接字
介于泛泛介绍这几种通信的文章很多,这里我们也不再重复了。这里展开的是套接字(socket)如何实现进程间通信的。
socket可以实现不同主机之间通信,也可以支持本地进程间通信。根据通信域的不同可以划分成:Unix domain socket 和 Internet domain socket。
Unix domain socket 又叫 IPC (inter-process communication) socket,用于实现同一主机上的进程间通信。socket 原本是为网络通讯设计的,但后来在 socket 的框架上发展出一种 IPC 机制,就是 UNIX domain socket。
注:虽然网络 socket 也可用于同一台主机的进程间通讯(通过 loopback 地址 127.0.0.1),但是 UNIX domain socket 用于 IPC 更有效率:不需要经过网络协议栈,不需要打包拆包、计算校验和、维护序号和应答等,只是将应用层数据从一个进程拷贝到另一个进程。这是因为,IPC 机制本质上是可靠的通讯,而网络协议是为不可靠的通讯设计的。
UNIX domain socket 是全双工的,API 接口语义丰富,相比其它 IPC 机制有明显的优越性,目前已成为使用最广泛的 IPC 机制,比如 X Window 服务器和 GUI 程序之间就是通过 UNIX domain socket 通讯的。Unix domain socket 是 POSIX 标准中的一个组件,所以不要被名字迷惑,linux 系统也是支持它的。
UNIX domain socket 使用上与internet domain socket的不同之处如下。
创建socket
绑定过程
// AF_UNIX, Local communication(本地,进程间通信)
server_fd = socket(AF_UNIX, SOCK_STREAM, 0);
struct sockaddr_un server_address;
server_address.sun_family = AF_UNIX;
strcpy(server_address.sun_path, "./SocketIPCTest");
unlink("./SocketIPCTest");
server_len = sizeof(server_address);
//与网络编程不一样的地方是服务器端bind的时候用的是sockaddr_un结构,客户端connect的时候用的也是sockaddr_un结构,而不是sockaddr_in或sockaddr。
bind(server_fd, (struct sockaddr *)&server_address, server_len);
服务器端代码
int main(int argc,char *argv[])
{
char buf[1024];
char send_msg[]="l am server!";
int msg_len;
int server_fd,client_fd;
int server_len,client_len;
struct sockaddr_un server_address;
struct sockaddr_un client_address;
server_fd = socket(AF_UNIX, SOCK_STREAM, 0);
server_address.sun_family = AF_UNIX;
strcpy(server_address.sun_path, "./SocketIPCTest");
unlink("./SocketIPCTest");
server_len = sizeof(server_address);
client_len = sizeof(client_address);
bind(server_fd, (struct sockaddr *)&server_address, server_len);
listen(server_fd,5);
client_fd = accept(server_fd, (struct sockaddr *)&client_address,&client_len);
while(1)
{
if(-1 == (msg_len = read(client_fd, buf, sizeof(buf))))
{
perror("read");
exit(-1);
}
printf("recv msg is : %s\n",buf);
if(-1 == (msg_len = write(client_fd, send_msg, sizeof(buf))))
{
perror("write");
exit(-1);
}
printf("send_msg is : %s\n",send_msg);
}
close(server_fd);
close(client_fd);
return 0;
}
客户端代码
int main()
{
char send_msg[1024];
char recv_msg[1024];
int sockfd;
int ret;
int address_len,result;
struct sockaddr_un address;
if(-1 == (sockfd = socket(AF_UNIX, SOCK_STREAM, 0))){
perror("socket");
return -1;
}
address.sun_family = AF_UNIX;
strcpy(address.sun_path, "./SocketIPCTest");
address_len = sizeof(address);
result = connect(sockfd, (struct sockaddr *)&address,address_len);
if(result == -1){
if(0 != access("./SocketIPCTest", F_OK))
{
printf("[Warning]: Wait for Server socket Creating!!!\n");
usleep(500 * 1000);
if(-1 == connect(sockfd, (struct sockaddr *)&address,address_len)){
perror("connect");
return -1;
}
}else{
perror("connect");
return -1;
}
}
while(1)
{
memset(send_msg, 0, sizeof(send_msg));
scanf("%s",send_msg);
ret = write(sockfd,send_msg,sizeof(send_msg));
if (ret <= 0)
{
perror("send\n");
}
ret = read(sockfd,recv_msg, sizeof(recv_msg));
if (ret <= 0)
{
perror("read");
exit(-1);
}
printf("recv msg is %s\n",recv_msg);
}
return 0;
}