进程通讯是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); }
|