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