UNIX进程之间的通信

http://www.sina.com.cn 2006年10月30日 22:17  ChinaByte

  进程通讯是unix中很重要的知识。产生一个新的进程主要有以下3种方法:

  1,fork调用;

  2,System调用;

  3,Exec调用;

  我们常说的进程通讯编程主要有以下3种方法:

  1,Message queue队列编程;

  2,Tcp/IP socket编程;

  3,共享内存编程;

  一、进程调用

  1,产生进程Fork调用例子:

  fork()

  功能:创建一个新的进程.

  语法:#include

  #include

  pid_t fork();

  说明:本系统调用产生一个新的进程, 叫子进程, 是调用进程的一个复制品. 调用进程叫父进程, 子进程继承了父进程的几乎所有的属性:

  . 实际UID,GID和有效UID,GID.

  . 环境变量.

  . 附加GID.

  . 调用exec()时的关闭标志.

  . UID设置模式比特位.

  . GID设置模式比特位.

  . 进程组号.

  . 会话ID.

  . 控制终端.

  . 当前工作目录.

  . 根目录.

  . 文件创建掩码UMASK.

  . 文件长度限制ULIMIT.

  . 预定值, 如优先级和任何其他的进程预定参数, 根据种类不同决定是否可以继承.

  . 还有一些其它属性.

  但子进程也有与父进程不同的属性:

  . 进程号, 子进程号不同与任何一个活动的进程组号.

  . 父进程号.

  . 子进程继承父进程的文件描述符或流时, 具有自己的一个拷贝并且与父进程和其它子进程共享该资源.

  . 子进程的用户时间和系统时间被初始化为0.

  . 子进程的超时时钟设置为0.

  . 子进程的信号处理函数指针组置为空.

  . 子进程不继承父进程的记录锁.

  返回值: 调用成功则对子进程返回0, 对父进程返回子进程号, 这也是最方便的区分父子进程的方法. 若调用失败则返回-1给父进程,子进程不生成.

  2,产生进程system调用例子:

  功能:产生一个新的进程, 子进程执行指定的命令.

  语法:#include

  #include

  int system(string)

  char *string;

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

  [code:1:d22bc4f5e9]例子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

  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[];[/code:1:d22bc4f5e9]

  说明:这是一个系统调用族, 用于将一个新的程序调入本进程所占的内存, 并覆盖之, 产生新的内存进程映象. 新的程序可以是可执行文件或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);

  二、进程通讯编程

  [code:1:d22bc4f5e9]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

  #include

  #include

  #include

  #include

  #include

  #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 \n");

  fprintf(stderr, " (r)ecv \n");

  fprintf(stderr, " (d)elete\n");

  fprintf(stderr, " (m)ode \n");

  fprintf(stderr, "note: type must be number!\n");

  exit(1);

  }

  2,Tcp/IP socket编程例子

  1), Client方

  #include

  #include

  #include

  #include

  #include

  #include

  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 \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

  buff[help] = '0'+help%10;

  write(sockfd, buff, 5000);

  close(sockfd);

  }

  2, Server方

  #include

  #include

  #include

  #include

  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

  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

  #include

  #include

  #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

  #include

  #include

  #include

  #include

  #include

  #include

  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

  #include

  #include

  #include

  #include

  #include

  #include

  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);

Powered By Google
不支持Flash
·城市对话改革30年 ·新浪城市同心联动 ·诚招合作伙伴 ·企业邮箱畅通无阻
不支持Flash