进程间通讯

进程间通讯
本文出自:UNIX快餐店 作者: (2001-10-06 07:05:00)

进程通讯是unix中很重要的知识。
产生一个新的进程主要有以下3种方法:
1,fork调用;
2,System调用;
3,Exec调用;
 
我们常说的进程通讯编程主要有以下3种方法:
1,Message queue队列编程;
2,Tcp/IP socket编程;
3,共享内存编程;
 



一、进程调用
1,产生进程Fork调用例子:
fork()

功能:创建一个新的进程.
语法:#include <unistd.h>
#include <sys/types.h>
pid_t fork();
说明:本系统调用产生一个新的进程, 叫子进程, 是调用进程的一个复制品. 调用进程叫父进程, 
子进程继承了父进程的几乎所有的属性:
. 实际UID,GID和有效UID,GID.
. 环境变量.
. 附加GID.
. 调用exec()时的关闭标志.
. UID设置模式比特位.
. GID设置模式比特位.
. 进程组号.
. 会话ID.
. 控制终端.
. 当前工作目录.
. 根目录.
. 文件创建掩码UMASK.
. 文件长度限制ULIMIT.
. 预定值, 如优先级和任何其他的进程预定参数, 根据种类不同决定是否可以继承.
. 还有一些其它属性.

但子进程也有与父进程不同的属性:
. 进程号, 子进程号不同与任何一个活动的进程组号.
. 父进程号.
. 子进程继承父进程的文件描述符或流时, 具有自己的一个拷贝并且与父进程和其它子进程共享该资源.
. 子进程的用户时间和系统时间被初始化为0.
. 子进程的超时时钟设置为0.
. 子进程的信号处理函数指针组置为空.
. 子进程不继承父进程的记录锁.
返回值: 调用成功则对子进程返回0, 对父进程返回子进程号, 这也是最方便的区分父子进程的方法. 
若调用失败则返回-1给父进程,子进程不生成.
例子:pid_t pid;

if ((pid=fork())>0) {

/*父进程处理过程*/

}

else if (pid==0) {

/*子进程处理过程*/

exit(0); /*注意子进程必须用exit()退出运行*/

}

else {

printf("fork error/n");

exit(0);

}



2,产生进程system调用例子:
功能:产生一个新的进程, 子进程执行指定的命令.
语法:#include <stdio.h>
#include <stdlib.h>
int system(string)
char *string;
说明:本调用将参数string传递给一个命令解释器(一般为sh)执行, 即string被解释为一条命令, 
由sh执行该命令.若参数string为一个空指针则为检查命令解释器是否存在.该命令可以同命令行命
令相同形式, 但由于命令做为一个参数放在系统调用中, 
应注意编译时对特殊意义字符的处理. 命令的查找是按PATH环境变量的定义的. 命令所生成的后果
一般不会对父进程造成影响.返回值:当参数为空指针时, 
只有当命令解释器有效时返回值为非零.若参数不为空指针, 返回值为该命令的返回状态
(同waitpid())的返回值. 
命令无效或语法错误则返回非零值,所执行的命令被终止. 其他情况则返回-1.

例子1:char command[81];
int i;
for (i=1;i<8;i++) {
sprintf(command,"ps -t tty%02i",i);
system(command);
}

例子2:
char befehl[200];  /* string buffer for csh command */ 
char *runserver = "hosts1"; /* server name */
short shift_act_l; /* currect shift number */
char shift_act_c[1];
char shift_beg[20]; /* shift begin */
char shift_end[20]; /* shift end */
....
T_report_p->shift_no='0';
memcpy(T_report_p->time_from,"yyyy-mm-dd 
hh:mi:ss",sizeof(T_report_p->time_from));
memcpy(T_report_p->time_to,"yyyy-mm-dd hh:mi:ss",sizeof(T_report_p->time_to));

memset(befehl, '/0', sizeof(befehl));
sprintf (befehl, "rsh %s %sprot.sh '%s %s %c /"%19.19s/" /"%19.19s/" /"%9.9s/" 
0' &",
runserver,
REPORT_RSH_PATH,
PROD_LOG,
DRUCKER_NAME_1,
T_report_p->shift_no,
T_report_p->time_from,
T_report_p->time_to,
T_report_p->coil_id );

system (befehl);
 



3,产生进程exec()调用例子:

exec()

功能:执行一个文件
语法:#include <unistd.h>
int execl(path,arg0,...,argn,(char*)0)
char *path,*arg0,...,*argn;
int execv(path,argv)
char *path,*argv[];
int execle(path,arg0,...,argn,(char*)0,envp)
char *path,*arg0,...,*argn,*envp[];
int execve(path,argv,envp)
char *path,*argv[],*envp[];
int execvp(file,argv)
char *file,*argv[];

说明:这是一个系统调用族, 用于将一个新的程序调入本进程所占的内存, 并覆盖之, 产生新的
内存进程映象. 
新的程序可以是可执行文件或SHELL批命令.当C程序被执行时,是如下调用的:
main(int argc,char *argv[],char *envp[]);
argc是参数个数,是各个参数字符串指针数组,envp是新进程的环境变量字符串的指针数组.argc至
少为1,argv[0]为程序文件名,所以,在上面的exec系统调用族中,path为新进程文件的路径名,
file为新进程文件名,若file不是全路径名,系统调用会按PATH环境变量自动找对应的可执行文件
运行.若新进程文件不是一个可执行的目标文件(如批处理文件),则execlp()和execvp()会将该文
件内容作为一个命令解释器的标准输入形成system().arg0,...等指针指向'/0'结束的字符串,组成
新进程的有效参数,且该参数列表以一个空指针结束.反过来,arg0至少必须存在并指向新进程文件
名或路径名.同样,argv是字符串指针数组,argv[0]指向新进程文件名或路径名,并以一空指针结束.
envp是一个字符串指针数组,以空指针结束,这些字符串组成新进程的环境.在调用这些系统调用前
打开的文件指针对新进程来说也是打开的,除非它已定义了close-on-exec标志.打开的文件指针在
新进程中保持不变,所有相关的文件锁也被保留.调用进程设置并正被捕俘的信号在新进程中被恢复
为缺省设置,其它的则保持不变.新进程启动时按文件的SUID和SGID设置定义文件的UID和GID为有效
UID和GID.新进程还继承了如下属性:
. 附加GID.
. 进程号.
. 父进程号.
. 进程组号.
. 会话号.
. 控制终端.
. alarm时钟信号剩下的时间.
. 当前工作目录.
. 根目录.
. 文件创建掩码.
. 资源限制.
. 用户时间,系统时间,子进程用户时间,子进程系统时间.
. 记录锁.
. 进程信号掩码.
. 信号屏蔽.
. 优先级.
. 预定值.
调用成功后,系统调用修改新进程文件的最新访问时间.返回值:该系统调用一般不会有成功返回值,
 因为原来的进程已荡然无存.
例子:printf("now this process will be ps command/n");
execl("/bin/ps","ps","-ef",NULL);



二、进程通讯编程
1,Message queue队列编程例子
/*****************************************************************************
Excerpt from "Linux Programmer's Guide - Chapter 6"
(C)opyright 1994-1995, Scott Burkett
***************************************************************************** 
MODULE: msgtool.c
*****************************************************************************
A command line tool for tinkering with SysV style Message Queues
*****************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

#define MAX_SEND_SIZE 80

struct mymsgbuf {
long mtype;
char mtext[MAX_SEND_SIZE];
};

void send_message(int qid, struct mymsgbuf *qbuf, long type, char *text);
void read_message(int qid, struct mymsgbuf *qbuf, long type);
void remove_queue(int qid);
void change_queue_mode(int qid, char *mode);
void usage(void);


int main(int argc, char *argv[])
{
key_t key;
int msgqueue_id;
struct mymsgbuf qbuf;

if(argc == 1)
usage();

/* Create unique key via call to ftok() */
/* key = ftok(".", 'w'); */ 
key = 123456;
printf("key=%d/n",key);
key=IPC_PRIVATE;
/* Open the queue - create if necessary */

if((tolower(argv[1][0]))!='s')
{
if((msgqueue_id = msgget(key, IPC_CREAT|0666)) == -1) {
perror("msgget");
exit(1);
}
printf("msgqueue_id=%d/n",msgqueue_id);
}

switch(tolower(argv[1][0]))
{
case 's': send_message(atoi(argv[4]), (struct mymsgbuf *)&qbuf,
atol(argv[2]), argv[3]); 
break;
case 'r': read_message(msgqueue_id, &qbuf, atol(argv[2])); 
break;
case 'd': remove_queue(atoi(argv[2])); 
remove_queue(msgqueue_id);
break; 
case 'm': change_queue_mode(msgqueue_id, argv[2]); 
break;

default: usage();

}

return(0);
}

void send_message(int qid, struct mymsgbuf *qbuf, long type, char *text)
{
printf("msgqueue_id=%d/n",qid);
/* Send a message to the queue */
printf("Sending a message .../n");
qbuf->mtype = type;
strcpy(qbuf->mtext, text);
printf(" Type: %ld Text: %s/n", qbuf->mtype, qbuf->mtext);

if((msgsnd(qid, (struct msgbuf *)qbuf,
strlen(qbuf->mtext)+1, 0)) ==-1)
{
perror("msgsnd");
exit(1);
}
}

void read_message(int qid, struct mymsgbuf *qbuf, long type)
{
/* Read a message from the queue */
printf("Reading a message .../n");
qbuf->mtype = type;
msgrcv(qid, (struct msgbuf *)qbuf, MAX_SEND_SIZE, type, 0);

printf(" Type: %ld Text: %s/n", qbuf->mtype, qbuf->mtext);
}

void remove_queue(int qid)
{
/* Remove the queue */
msgctl(qid, IPC_RMID, 0);
}

void change_queue_mode(int qid, char *mode)
{
struct msqid_ds myqueue_ds;

/* Get current info */
msgctl(qid, IPC_STAT, &myqueue_ds);

/* Convert and load the mode */
sscanf(mode, "%ho", &myqueue_ds.msg_perm.mode);

/* Update the mode */
msgctl(qid, IPC_SET, &myqueue_ds);
}

void usage(void)
{
fprintf(stderr, "msgtool - A utility for tinkering with msg queues/n");
fprintf(stderr, "/nUSAGE: msgtool (s)end <type> <messagetext> <msgid>/n");
fprintf(stderr, " (r)ecv <type>/n");
fprintf(stderr, " (d)elete/n");
fprintf(stderr, " (m)ode <octal mode>/n");
fprintf(stderr, "note: type must be number!/n");
exit(1);
}




2,Tcp/IP socket编程例子
1), Client方
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>

int main(int argc, char *argv[])
{
int sockfd ,newsockfd, help, sent;
struct sockaddr_in peer;
struct hostent *serverhost;
char buff[5000];


if(argc<2) {
fprintf(stderr, "Usage: coc <hostname>/n");
exit(1);
}

if ((sockfd = socket(AF_INET,SOCK_STREAM,0)) < 0 ) {
perror("socket");
exit(1);
}


if((serverhost = gethostbyname(argv[1])) == 0) {
perror("gethostbyname");
exit(1);
}


peer.sin_family = AF_INET;
peer.sin_port = htons(10000); 
peer.sin_addr = *(struct in_addr*)serverhost->h_addr_list[0];

if (connect(sockfd, &peer, sizeof(peer)) < 0 ) {
perror("connect");
exit(1);
}

for(help=0; help<sizeof(buff); help++)
buff[help] = '0'+help%10;

write(sockfd, buff, 5000);

close(sockfd);
}

2, Server方
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>

void process(int fd)
{
char buff[10000];
int received;
int help,read_bytes;

received = 5000;
memset ( buff, '.', received );
read_bytes = read(fd, buff, received);
if (read_bytes < 0) {
perror("read");
exit(1);
}

printf("%d bytes have received on socket %d/n", read_bytes, fd);
printf("buff=/n%s/n", buff);
for(help=0; help<received; help++)
if(buff[help] != '0'+help%10) 
{
printf("Error on position %d/n", help); 
break;
}
}

int main(void)
{
int sockfd ,newsockfd;
struct sockaddr_in myaddr, peer;

int addrlen1,addrlen2;

if ((sockfd = socket(AF_INET,SOCK_STREAM,0)) < 0 ) {
perror("socket");
exit(1);
}

addrlen1 = sizeof(myaddr);

myaddr.sin_family = AF_INET;
myaddr.sin_port = htons(10000);
myaddr.sin_addr.s_addr = INADDR_ANY;
if (bind(sockfd, &myaddr , addrlen1) < 0 ) {
perror("bind");
exit(1);
}

if (listen(sockfd, 5 )) {
perror("listen");
exit(1);
}

for (;;)
{
addrlen2 = sizeof(peer);
newsockfd = accept(sockfd, &peer , &addrlen2);
if ( newsockfd < 0) {
perror("accept");
exit(1);
}
if (fork() == 0) {
close(sockfd);

/* process request */
printf("connection on socket %d from %s/n", newsockfd, 
inet_ntoa(peer.sin_addr.s_addr));
process(newsockfd);
close(newsockfd);
exit(0);

}
close(newsockfd);
}
}




3,共享内存编程例子
例子1:
#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/shm.h>

#define SHMKEY 74

#define K 1024

int shmid;

cleanup()

{

shmctl(shmid,IPC_RMID,0);

exit(0);

}

main()

{

int *pint;

char *addr1,*addr2;

extern char *shmat();

extern cleanup();

for (i=0;i<20;i++)

signal(i,cleanup);

shmid=shmget(SHMKEY,128*K,0777|IPC_CREAT);

addr1=shmat(shmid,0,0);

addr2=shmat(shmid,0,0);

printf("addr1 0x%x addr2 0x%x/n",addr1,addr2);

pint=(int*)addr1;

for (i=0;i<256;i++)

*pint++=i;

pint=(int*)addr1;

*pint=256;

pint=(int*)addr2;

for (i=0;i<256;i++)

printf("index %d/tvalue%d/n",i,*pint++);

shmdt(addr1);

shmdt(addr2);

pause();

}

例子2
1),创建和写共享内存:
/* Includes */
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>

typedef struct
{
int tc_number;
char ap_name[5];
char mymessage[20];

} COMM_TABLE;

main()
{

/* local variables */
int ret= 0;
key_t key;
int i;
int shm_id;
int found = 0;
COMM_TABLE *comm_reg;

key = ftok(".",'w');

/* create a share memory if not exist */
if ((shm_id = shmget(key ,sizeof(COMM_TABLE),IPC_CREAT|IPC_EXCL|0666)) == -1)
{
/* share memory has been created */
if ((shm_id = shmget(key , sizeof(COMM_TABLE),0)) == -1)
{
printf("error = %d/n", errno);
return (ret);

}
}
comm_reg = (COMM_TABLE *) shmat(shm_id, (char *) 0, SHM_SHARE_MMU);
comm_reg->tc_number= 56110563;
}

2), 读共享内存,再删除共享内存:
/* Includes */
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>

typedef struct
{
int tc_number;
char ap_name[5];
char mymessage[20];

} COMM_TABLE;

main()
{

/* local variables */
int ret= 0;
key_t key;
int i;
int shm_id;
int found = 0;
COMM_TABLE *comm_reg;
char * pointer;


key = ftok(".",'w');

/* share memory has been created */
if ((shm_id = shmget(key , sizeof(COMM_TABLE),0)) == -1)
{
printf("error = %d/n", errno);
return (ret);

}
comm_reg = (COMM_TABLE *) shmat(shm_id, (char *) 0, SHM_SHARE_MMU);
printf("tc number=%d!!!/n", comm_reg->tc_number);

/* kill share memory */

shmctl(shm_id,IPC_RMID,0);
exit(0);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值