/*一个例子程序,来自《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);
}