【发布时间】:2023-03-25 01:36:01
【问题描述】:
所以我目前正在编写一个服务器/客户端程序,它将接收三个命令(HI、PID 和 GOODBYE)并相应地处理它们。我在 server.c 代码中使用 semget() 似乎遇到了一些麻烦。
我得到的错误是“EEXIST”,根据手册页,它说密钥已经存在(duh lol) - 问题是,我每次都手动更改密钥,它仍然给我错误。我不明白这里的东西吗?它似乎也适用于 client.c 代码。你们中有人知道我为什么会遇到这种情况吗?
抱歉,代码有点草率,我整晚都在敲键盘,我会尽力注释掉我的思维过程。让我知道是否有什么可以使它更易于阅读。
client.c:
#include "stdio.h"
#include "stdlib.h"
#include "sys/shm.h"
#include "sys/ipc.h"
#include "sys/types.h"
#include "sys/sem.h"
#include "signal.h"
#include "string.h"
#include <unistd.h>
#define MEM_KEY 99 // memory key
#define SEM_KEY 1337 // semaphore key
#define SEG_SIZE ( (size_t)100 ) // segment size
#define oops( m, x ) { perror(m); exit(x); } // for error checking
int seg_id, semset_id;
union semun{ int val; struct semid_ds* buf; ushort* array; }; // for wait and release functions
void wait_and_lock( int );
void release_lock( int );
int main()
{
char c;
key_t memKey = MEM_KEY, semKey = SEM_KEY; // not sure if this is necessary
char *memPtr;
if ((seg_id = shmget(memKey, SEG_SIZE, IPC_CREAT | 0777)) < 0) // get segment ID
oops("shmget", 1);
if ((memPtr = shmat(seg_id, NULL, 0)) == (char *) -1) // attach the memory segment
oops("shmat", 2);
semset_id = semget(semKey, 2, ( 0666 | IPC_CREAT | IPC_EXCL )); // for some reason I couldn't include this in an if-statement
// but it seems to work here in the server code
if (semset_id == -1)
oops("semset", 2.5);
wait_and_lock( semset_id ); // this function was something our teacher went over with us.
// I'm still a little confused with what it's doing.
while(1)
{
printf("enter: "); // get the commands, is there a better way of doing this?
scanf("%s", memPtr);
}
release_lock( semset_id );
while (*memPtr != '*') // not sure if this is necessary, left over from old code that I was experimenting with.
sleep(1);
shmdt( memPtr ); // detach the memory
exit(0);
}
void wait_and_lock( int semset_id )
{
union semun sem_info; // some properties
struct sembuf actions[2]; // action set, an array
actions[0].sem_num = 1; // sem[1] is n_writers
actions[0].sem_flg = SEM_UNDO; // auto cleanup
actions[0].sem_op = 0; // wait for 0
actions[1].sem_num = 0; // sem[0] is n_readers
actions[1].sem_flg = SEM_UNDO; // auto cleanup
actions[1].sem_op = 1; // incr n_readers
if ( semop( semset_id, actions, 2 ) == -1 )
oops( "semop: locking", 10 );
}
void release_lock( int semset_id )
{
union semun sem_info; // some properties
struct sembuf actions[1]; // action set
actions[0].sem_num = 0; // sem[0] is n_readers
actions[0].sem_flg = SEM_UNDO; // auto cleanup
actions[0].sem_op = -1; // decr reader country
if ( semop( semset_id, actions, 1 ) == -1 )
oops( "semop: unlocking", 10 );
}
server.c:
#include "stdio.h"
#include "stdlib.h"
#include "sys/shm.h"
#include "sys/ipc.h"
#include "sys/types.h"
#include "sys/sem.h"
#include "signal.h"
#include "string.h"
#include <unistd.h>
#define MEM_KEY 99
#define SEM_KEY 1337
#define SEG_SIZE ( (size_t)100 )
#define oops( m, x ) { perror(m); exit(x); }
union semun { int val; struct semid_ds* buf; unsigned short* array; };
int seg_id, semset_id;
void cleanup( int );
void set_sem_value( int, int, int );
void wait_and_lock( int );
void release_lock( int );
int main()
{
int id = 0;
char *memPtr;
key_t memKey = MEM_KEY, semKey = SEM_KEY;
signal( SIGINT, cleanup ); // to handle Ctrl-C
seg_id = shmget( memKey, SEG_SIZE, 0777 ); // get segment ID
if( seg_id == -1 )
oops( "shmget", 1 );
if ((memPtr = shmat(seg_id, NULL, 0)) == (char *) -1) // attach to memPtr
oops("shmat",2);
semset_id = semget( semKey, 2, ( 0666 | IPC_CREAT | IPC_EXCL ) );
// this is where there seems to be an issue? This is where the code stops.
if ( semset_id == -1 )
oops( "semget", 3 );
set_sem_value( semset_id, 0, 0 ); // set counters
set_sem_value( semset_id, 1, 0 ); // both to zero
//Now read what the client put in the memory (still not sure if this works
//because the program hasn't technically gotten that far. So this while loop is more
//of a prototype).
while(1)
{
wait_and_lock( semset_id );
printf( "\tshm_ts2 update memory\n" ); // will be removed at the end
sleep(1);
if(strcmp(memPtr, "HI")==0) // look for HI
{
printf("Greetings!\n"); // print this to the server screen
fflush(stdout);
memPtr[0] = '\0';
}
else if(strcmp(memPtr, "PID")==0) // look for PID and get server's PID
{
id = (int)getpid();
printf("Server pid: %i\n", id);
fflush(stdout);
memPtr[0] = '\0';
}
else if(strcmp(memPtr, "QUIT")==0){ // check for quit
shmctl(seg_id, IPC_RMID, NULL); // mark seg to be destroyed
shmdt(memPtr); // detach segment
printf("GOODBYE!\n");
exit(0);
}
release_lock( semset_id );
printf( "\tshm_ts2 released lock\n" ); // will be removed at the end
}
*memPtr = '*'; // still not sure if this is necessary, from old code
cleanup(0);
return 0;
}
void cleanup( int n )
{
shmctl( seg_id, IPC_RMID, NULL );
semctl( semset_id, 0, IPC_RMID, NULL );
}
void set_sem_value( int semset_id, int semnum, int val )
{
union semun initval;
initval.val = val;
if ( semctl( semset_id, semnum, SETVAL, initval ) == -1 )
oops( "semctl", 4 );
}
void wait_and_lock( int semset_id )
{
struct sembuf actions[2]; // action set, an array
actions[0].sem_num = 0; // sem[0] is n_readers
actions[0].sem_flg = SEM_UNDO; // auto cleanup
actions[0].sem_op = 0; // wait til no readers
actions[1].sem_num = 1; // sem[1] is n_writers
actions[1].sem_flg = SEM_UNDO; // auto cleanup
actions[1].sem_op = 1; // increment number of writers
if ( semop( semset_id, actions, 2 ) == -1 )
oops("semop: locking", 10 );
}
// Thing 4: build and execute a 1-element action set: decrement num_writers
void release_lock( int semset_id )
{
struct sembuf actions[1]; // action set, an array
actions[0].sem_num = 1; // sem[0] is n_writers
actions[0].sem_flg = SEM_UNDO; // auto cleanup
actions[0].sem_op = -1; // decrement number of writer count
if ( semop( semset_id, actions, 1 ) == -1 )
oops( "semop: unlocking", 10 );
}
【问题讨论】:
-
那么这里的问题是什么?这不是最小的吗?我觉得删除任何东西都可能难以发现问题?我想我可以取出client.c,因为服务器问题最多?只是链接该页面对我没有任何帮助。 @PasserBy
-
您可能想重新阅读
shmctl()上的手册页并阅读shmdt()上的手册页 -
对于初学者,您有一个标记为永远无法到达的循环。这与您的问题无关。尝试将问题提炼到完全复制您的问题所需的绝对最小值。