细说linux IPC(一):基于socket的进程间通信(上)
【版权声明:尊重原创。转载请保留出处:blog.csdn.net/shallnet 或 .../gentleliu,文章仅供学习交流,请勿用于商业用途】
在一个较大的project其中。一般都会有多个进程构成,各个功能是一个独立的进程在执行。
既然多个进程构成一个project,那么多个进程之间肯定会存在一些信息交换或共享数据,这就涉及到进程间通信。进程间通道有非常多种。比方有最熟悉网络编程中的socket、还有共享内存、消息队列、信号、管道等非常多方式。每一种方式都有自己的适用情况,在本系列文章中笔者将会对多种进程间通信方式进行具体解释,一是对自己工作多年在这方面的经验做一个积累,二是将其分享给各位民工。也许还能从大家的拍砖其中得到意外收获。
socket网络编程可能使用得最多,经经常使用在网络上不同主机之间的通信。
事实上在同一主机内通信也能够使用socket来完毕。socket进程通信与网络通信使用的是统一套接口,不过地址结构与某些參数不同。在使用socket创建套接字时通过指定參数domain是af_inet(ipv4因特网域)或af_inet6(ipv6因特网域)或af_unix(unix域)来实现。
在笔者这一篇文章中曾有具体介绍创建socket通信流程及基础知识。
http://blog.csdn.net/shallnet/article/details/17734919。
首先来看一下使用af_inet域以及本地环回地址来实现本地主机进程间通信。
服务进程创建监听套接字:
int ser_afinet_listen(int port)
{
int listenfd, on;
struct sockaddr_in seraddr; listenfd = socket(af_inet, sock_stream, 0);
if (listenfd < 0) {
fprintf(stderr, "socket: %s\n", strerror(errno));
return -1;
} on = 1;
setsockopt(listenfd, sol_socket, so_reuseaddr, &on, sizeof(on)); seraddr.sin_family = af_inet;
seraddr.sin_port = port;
seraddr.sin_addr.s_addr = htonl(inaddr_any); if (bind(listenfd, (struct sockaddr *)&seraddr, sizeof(struct sockaddr_in)) < 0) {
fprintf(stderr, "bind: %s\n", strerror(errno));
return -1;
} if (listen(listenfd, sock_ipc_max_conn) < 0) {
fprintf(stderr, "listen: %s\n", strerror(errno));
return -1;
} return listenfd;
}
服务进程处理连接请求例如以下:
int ser_accept(int listenfd)
{
int connfd;
struct sockaddr_un cltaddr;
ssize_t recvlen, sendlen;
char buf[sock_ipc_max_buf];
socklen_t addrlen; addrlen = sizeof(cltaddr);
for (;;) {
connfd = accept(listenfd, (struct sockaddr *)&cltaddr, &addrlen);
if (connfd < 0) {
fprintf(stderr, "accept: %s\n", strerror(errno));
return -1;
} if (recvlen = ipc_recv(connfd, buf, sizeof(buf)) < 0) {
continue;
} printf("recv: %s\n", buf);
snprintf(buf, sizeof(buf), "hello, ipc client!");
if (ipc_send(connfd, buf, strlen(buf)) < 0) {
continue;
} close(connfd);
}
}
客户进程初始化例如以下:
指定要连接的服务器地址为本地换回地址,这样发送的连接就会回到本地服务进程。
int clt_afinet_conn_init(int port)
{
int fd; fd = socket(af_inet, sock_stream, 0);
if (fd < 0) {
fprintf(stderr, "socket: %s\n", strerror(errno));
return -1;
} seraddr.sin_family = af_inet;
seraddr.sin_port = port;
if (inet_pton(af_inet, "127.0.0.1", &seraddr.sin_addr) < 0) {//环回地址
fprintf(stderr, "inet_pton: %s\n", strerror(errno));
return -1;
} return fd;
}
客户进程向服务进程发送接收请求例如以下:
if (connect(fd, (struct sockaddr *)&seraddr, sizeof(struct sockaddr_in)) < 0) {
fprintf(stderr, "connect: %s\n", strerror(errno));
return -1;
} if ((sendlen = ipc_send(fd, buf, strlen(buf))) < 0) {
return -1;
} if ((recvlen = ipc_recv(fd, buf, sizeof(buf))) < 0) {
return -1;
}
服务进程先执行,客户进程执行:
# ./client
recv: hello, ipc client!
# ./server
recv: hello ipc server!
通信过程完毕。
创建类型为af_unix(或af_local)的socket,表示用于进程通信。
socket进程通信与网络通信使用的是统一套接口:
#include<sys/socket.h>
int socket(int domain, int type, int protocol);
其中,domain 參数指定协议族,对于本地套接字来说,其值被置为 af_unix 枚举值,随便说一下,af_unix和af_local是同一个值,看以下linux/socket.h头文件部分例如以下,两个宏的值都一样为1。
……
/* supported address families. */
#define af_unspec 0
#define af_unix 1 /* unix domain sockets */
#define af_local 1 /* posix name for af_unix */
#define af_inet 2 /* internet ip protocol */
#define af_ax25 3 /* amateur radio ax.25 */
……
以af_xx开头和pf_xx开头的域都是一样的。继续看头文件部分内容就一切都明确了:
……
#define pf_unspec af_unspec
#define pf_unix af_unix
#define pf_local af_local
#define pf_inet af_inet
#define pf_ax25 af_ax25
……
所以我们在指定socket的类型时这四个域能够随便用啦,笔者这里统一使用af_unix了。
type 參数可被设置为 sock_stream(流式套接字)或 sock_dgram(数据报式套接字),对于本地套接字来说,流式套接字(sock_stream)是一个有顺序的、可靠的双向字节流,相当于在本地进程之间建立起一条数据通道。数据报式套接字(sock_dgram)相当于单纯的发送消息。在进程通信过程中。理论上可能会有信息丢失、复制或者不按先后次序到达的情况,但因为其在本地通信,不通过外界网络,这些情况出现的概率非常小。
本地套接字的通信两方均须要具有本地地址,地址类型为 struct sockaddr_un结构体(位于linux/un.h):
#ifndef _linux_un_h
#define _linux_un_h #define unix_path_max 108 struct sockaddr_un {
sa_family_t sun_family; /* af_unix */
char sun_path[unix_path_max]; /* pathname */
};
#endif /* _linux_un_h */
创建监听套接字:
int ser_afunix_listen(const char *pathname)
{
int listenfd, on;
struct sockaddr_un seraddr; listenfd = socket(af_unix, sock_stream, 0);
if (listenfd < 0) {
fprintf(stderr, "socket: %s\n", strerror(errno));
return -1;
} unlink(pathname);
seraddr.sun_family = af_unix;
snprintf(seraddr.sun_path, sizeof(seraddr.sun_path), "%s", pathname); if (bind(listenfd, (struct sockaddr *)&seraddr, sizeof(struct sockaddr_un)) < 0) {
fprintf(stderr, "bind: %s\n", strerror(errno));
return -1;
} if (listen(listenfd, sock_ipc_max_conn) < 0) {
fprintf(stderr, "listen: %s\n", strerror(errno));
return -1;
} return listenfd;
}
服务进程处理连接请求相似上面网络通信。
客户进程初始化套接字过程为:
int clt_afunix_conn_init(const char *pathname)
{
int fd;
struct sockaddr_un localaddr; fd = socket(af_unix, sock_stream, 0);
if (fd < 0) {
fprintf(stderr, "socket: %s\n", strerror(errno));
return -1;
} localaddr.sun_family = af_unix;
snprintf(localaddr.sun_path, sizeof(localaddr.sun_path), "%s-cltid%d", pathname, getpid()); if (bind(fd, (struct sockaddr *)&localaddr, sizeof(struct sockaddr_un)) < 0) {
fprintf(stderr, "bind: %s\n", strerror(errno));
return -1;
} seraddr.sun_family = af_unix;
snprintf(seraddr.sun_path, sizeof(seraddr.sun_path), "%s", pathname); return fd;
}
客户进程向服务进程发送接收请求相似上面网络通信。
执行结果同网络通信部分。
本节只给出了一个非常easy的通信程序,只简单实现了客户进程和服务进程之间的通信。在下一节笔者将会在本节演示样例的基础上做改动,写一个在实际应用中能够使用的代码。
本节演示样例代码下载链接:
http://download.csdn.net/detail/gentleliu/8140459
细说linux IPC(一):基于socket的进程间通信(上)的更多相关文章
- 细说linux IPC(三):mmap系统调用共享内存
[版权声明:尊重原创,转载请保留出处:blog.csdn.net/shallnet 或 .../gentleliu,文章仅供学习交流,请勿用于商业用途] 前面讲到socket的进程间通 ...
- Linux IPC udp/ip socket 编程
模型 #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include < ...
- Linux IPC tcp/ip socket 编程
模型 #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include < ...
- 细说linux IPC(四):posix 共享内存
[版权声明:尊重原创.转载请保留出处:blog.csdn.net/shallnet 或 .../gentleliu,文章仅供学习交流,请勿用于商业用途] 上一节讲了由open函数打开一 ...
- C语言 linux环境基于socket的简易即时通信程序
转载请注明出处:http://www.cnblogs.com/kevince/p/3891033.html ——By Kevince 最近在看linux网络编程相关,现学现卖,就写了一个简易 ...
- 基于socket实现上传文件
基于socket实现文件上传 客户端代码: #!/usr/bin/env python # -*- coding:utf-8 -*- """ 这个是实现上传文件 首先让客 ...
- 【Linux 应用编程】进程管理 - 进程间通信IPC之管道 pipe 和 FIFO
IPC(InterProcess Communication,进程间通信)是进程中的重要概念.Linux 进程之间常用的通信方式有: 文件:简单,低效,需要代码控制同步 管道:使用简单,默认阻塞 匿名 ...
- 【Linux 应用编程】进程管理 - 进程间通信IPC之共享内存 mmap
IPC(InterProcess Communication,进程间通信)是进程中的重要概念.Linux 进程之间常用的通信方式有: 文件:简单,低效,需要代码控制同步 管道:使用简单,默认阻塞 匿名 ...
- linux下socket编程-进程间通信
一.什么是Socket Socket接口是TCP/IP网络通信的API,Socket接口定义了许多函数或例程,可以用它们来开发TCP/IP网络上的应用程序. Socket类型有两种:流式Socket ...
随机推荐
- 定位所用的class
方案 为解决类冲突,我们可以使用下述的方案定位一个class所在的位置 ClassName. package cn.j2se.junit.classpath; import static org.ju ...
- Bzoj 1014&Luogu 4036 火星人Prefix(FHQ-Treap)
题面 洛谷 Bzoj 题解 首先,这种带修改的是不能用$SA$的,然后,我们做$SA$的题一般也能二分+$Hash$,所以不妨考虑用$FHQ-Treap$维护树,然后查询就用二分+$Hash$. $H ...
- 洛谷——P1104 生日
P1104 生日 题目描述 cjf君想调查学校OI组每个同学的生日,并按照从大到小的顺序排序.但cjf君最近作业很多,没有时间,所以请你帮她排序. 输入输出格式 输入格式: 有2行, 第1行为OI组总 ...
- 洛谷——P1629 邮递员送信
P1629 邮递员送信 题目描述 有一个邮递员要送东西,邮局在节点1.他总共要送N-1样东西,其目的地分别是2~N.由于这个城市的交通比较繁忙,因此所有的道路都是单行的,共有M条道路,通过每条道路需要 ...
- 安装SQL2008时显示必须重启计算机才可以继续安装的错误—解决办法
数据库学习已经有一段时间了,前几天进入了SQL视频的学习,在安装数据库的时候,出现问题,总显示重启失败 ,无法继续安装,如图所示 出现这种问题 ,应该如何解决呢? 解决方法如下: (1).开始菜单-搜 ...
- Codeforces 500 E. New Year Domino
\(>Codeforces \space 500 E. New Year Domino<\) 题目大意 : 数轴上有序排列着 \(n\) 块多米诺骨牌, 第 \(i\) 块骨牌坐标为 \( ...
- [BZOJ2007][NOI2010]海拔(对偶图最短路)
首先确定所有点的海拔非0即1,问题转化成裸的平面图最小割问题,进而转化成对偶图最短路(同BZOJ1002). 这题的边是有向的,所以所有边顺时针旋转90度即可. 如下图(S和T的位置是反的). #in ...
- 【贪心】hdu5969 最大的位或
对于右端点r和左端点l,考虑他们的二进制位从高到低,直到第一位不同的为止. 更高的都取成相同的,更低的都取成1. 比如 101011110001 101011101001 101011111111 # ...
- python基础之模块,面向对象
hash 什么是hash? hash是一种算法,该算法接受传入的内容,经过运算得到一串hash值 为何用hash? hash值有三大特性: 1.只要传入的内容一样,得到的hash值必然一样 2.只要使 ...
- usaco-2.2.2Subset Sums 集合
01背包,对每个数至多取一次,为了避免重复,应倒序dp usaco-2.2.2Subset Sums 集合 时间限制: 1 Sec 内存限制: 128 MB 题目描述 对于从1到N的连续整集合合,能 ...