/*一个例子程序,来自《linux环境下C编程指南》,有小改动: *简单的服务器和客户端程序,启动不带参数运行服务器,带参数则是客户端 *服务器启动后,创建信号量和共享内存,并将共享内存的引用ID显示出来, * 将信号量的引用ID放在共享内存中,利用服务器端提供的共享内存引用ID *将共享内存附加到地址段,读取信号量以实现两个进程之间的同步,之后,这两个进程就可 *利用共享内存进行进程间通信,客户端输入的信息将在服务器端显示出来 */
#include <sys/sem.h> #include <sys/shm.h> #include <sys/ipc.h> #include <stdio.h> #include <string.h> #include <signal.h> #include <stdlib.h>
#define SHMDATASZ 1000 #define BUFSZ(SHMDATASZ-sizeof(int)) #define SN_EMPTY 0 #define SN_FULL 1
int delete_semid = 0; union semun { int val; struct semid_ds *buf; ushort array; };
void server(void); void client(int shmid); void delete(void); void sigdelete(int signum); void locksem(int semid,int semnum); void unlocksem(int semid,int semnum); void clientwrite(int shmid,int semid, char *buffer);
int main(int argc,char *argv[]) { if(argc < 2) server(); else client(atoi(argv[1])); return 0; }
void server(void) { union semun sunion; int semid, shmid; void *shmdata; char *buffer; //创建2个信号量 semid = semget(IPC_PRIVATE, 2, SHM_R|SHM_W); if(semid == -1) perror("semget"); delete_semid = semid;
// 当接收到SIGINT信号时删除信号量并终止程序 atexit(&delete); signal(SIGINT,&sigdelete);
//设EN_EMPYT的信号值为1 sunion.val = 1; if(semctl(semid, SN_EMPTY, SETVAL, sunion)== -1) perror("semctl"); sunion.val = 0; //设EN_FULL的信号值为0,说明没有一个资源可用 if(semctl(semid, SN_FULL, SETVAL, sunion)== -1) perror("semctl");
//创建一块共享内存 shmid = shmget(IPC_PRIVATE, SHMDATASZ, IPC_CREAT|SHM_R|SHM_W); if(shmid == -1) perror("shmget");
//附加到shmdata shmdata = shmat(shmid, 0, 0); if(shmdata== (void*)-1) perror("shmat");
//删除共享内存,刚刚创建还没用呢,就删了,不明白 // if(shmctl(shmid, IPC_RMID, NULL) == -1) // perror("shmctl");
//把信号标识符放在首地址 *(int*)shmdata= semid; buffer = shmdata + sizeof(int); //后面是缓冲区
printf("Server is running with SHM id ** %d **\n", shmid); while(1) { printf("waiting until full..."); fflush(stdout);
//申请一个资源 locksem(semid, SN_FULL); printf("done\n"); printf("message received :%s\n", buffer); //释放用完的资源 unlocksem(semid, SN_EMPTY); } } void client(int shmid) { int semid; void *shmdata; char *buffer; //把server创建的共享内存附加到shmdata shmdata = shmat(shmid, 0, 0); //取出信号标识符 semid = *(int*)shmdata; //再找到缓冲区 buffer = shmdata+sizeof(int); printf("client operational: shm id is %d, sem id is %d\n", shmid, semid); while(1) { char input[3]; printf("\n\nMenu\n1.Send a message\n"); printf("2.Exit\n"); fgets(input,sizeof(input),stdin); switch(input[0]) { case ‘1‘:clientwrite(shmid, semid, buffer); break; case ‘2‘:exit(0); break; } } }
void clientwrite(int shmid,int semid, char *buffer) { printf("waiting until empty.."); fflush(stdout);
//申请EMPTY资源 locksem(semid, SN_EMPTY); printf("Enter Message:"); fgets(buffer, BUFSZ,stdin); //释放资源 unlocksem(semid, SN_FULL); }
void delete() { printf("\nMaster exiting; deleting semaphore %d\n", delete_semid); if(semctl(delete_semid, IPC_RMID, 0)== -1) perror("release semaphore"); }
void sigdelete(int num) { exit(0); }
void locksem(int semid,int semnum) { struct sembuf sb; sb.sem_num = semnum; sb.sem_op =-1; sb.sem_flg = SEM_UNDO; semop(semid,&sb, 1); }
void unlocksem(int semid,int semnum) { struct sembuf sb; sb.sem_num = semnum; sb.sem_op = 1; sb.sem_flg = SEM_UNDO; semop(semid,&sb, 1); }
|