GB | BIG5
|
| 首頁 > 編程技術 > 其它 > 正文 |
 |
| 進程間通訊 |
| 本文出自: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);
}
(http://www.fanqiang.com)
進入【UNIX論壇】
|
|
| 相關文章 |
進程間通訊 (2001-10-06 07:05:00) Linux 核心--6.進程間通訊機制 (2001-04-27 13:56:30)
|
|
|
|
 |
★ 樊強制作 歡迎分享 ★ |