我如何 link 客户端和服务器到同一个信号量

How do I link client and server to the same semaphore

我正在进行一项作业,该作业使用 IPC 方案在 "Server" 和 "Client" 之间通过共享文件进行通信。

共享文件是在名为 Data Reader 的服务器应用程序中创建的,同时还有一个已初始化的信号量。代码在这里:

/*
*
*   Function Name:  initializeSemaphores()
*   Description:    This function initializes the semaphoreID and sets initial values for
*                   the semaphore.
*   
*   Parameters:     void.
*   Returns:        semaphoreID (pid_t) = The semaphore ID of the semaphore we initialized.
*/
pid_t initializeSemaphore(void)
{
    pid_t semaphoreID = -1;

    semaphoreID = semget(IPC_PRIVATE, 1, IPC_CREAT | 0666);
    if(semaphoreID == -1)
    {
        printf("(SERVER) Cannot create semaphore.\n");
        logErrorStatus("Cannot create semaphore.", __FILE__, __LINE__);
    }

    printf("(SERVER) Semaphore ID is: %d\n", semaphoreID);

    //Initialize semaphore to a known value
    if(semctl(semaphoreID, 0, SETALL, init_values) == -1)
    {
        printf("(SERVER) Cannot initialize semaphores.\n");
        logErrorStatus("Cannot initialize semaphores.", __FILE__, __LINE__);
        semaphoreID = -1;
    }

    return semaphoreID;
}


/*
*   Function Name:  writeToSharedFile
*   Description:    Write machineID and status code to the shared file using semaphore control.
*
*   Parameters:     semaphoreID (pid_t) = The id of the semaphore we are using to communicate
*                   machineID (pid_t) = The id of the DataCreator to be written to the shared file.
*                   statusCode (int) = The status code to be written to the shared file.
*   Returns:        success (int) = Success code.
*/
int writeToSharedFile(pid_t semaphoreID, pid_t machineID, int statusCode)
{
    int success = kNoError;
    FILE* sharedFilePointer = NULL;

    //Enter the critical region (gain access to the "talking stick")
    if(semop (semaphoreID, &acquire_operation, 1) == -1)
    {
        printf("(SERVER) Cannot start critical region\n");
        logErrorStatus("Cannot start critical region", __FILE__, __LINE__);
        success = kCriticalRegionError;
    }

    //Open the shared file for appending in binary
    if((sharedFilePointer = fopen(kSharedFile, "ab+")) == NULL)
    {
        printf("(SERVER) Cannot write to shared file.\n");
        logErrorStatus("Cannot write to shared file.", __FILE__, __LINE__);
        success = kSharedFileError;
    }

    //Write the machineID and statusCode to the shared file
    fwrite(&machineID, sizeof(int), 1, sharedFilePointer);
    fwrite(&statusCode, sizeof(int), 1, sharedFilePointer);

    //Exit the critical region (make access to the "talking stick" available to use) 
    if(semop(semaphoreID, &release_operation, 1) == -1)
    {
        printf("(SERVER) Cannot exit critical region.\n");
        logErrorStatus("Cannot exit critical region.", __FILE__, __LINE__);
        success = kCriticalRegionError;
    }

    //Close the shared file
    if(fclose(sharedFilePointer) != 0)
    {
        printf("(SERVER) Cannot close shared file.\n");
        logErrorStatus("Cannot close shared file.", __FILE__, __LINE__);
        success = kSharedFileError;
    }

    return success;
}

数据监视器 ("Client") 需要使用与此信号量的联系,以确保它们不会同时通话。我不确定客户端是否需要访问相同的信号量 ID,或者这两个进程一起位于信号量中的协议是什么?

数据监控的代码如下,无法进入临界区,我认为也不能正确连接服务器进程。

if(FindSharedFile())
{
    while (1) 
    {
        usleep(500000);


        // attempt to set initial semaphore flag for dr
        if (semop (semID, &acquire_operation, 1) == -1)
        {
            printf ("Cannot start critical region\n");
            break;
        }


        if ((filePointer = fopen (kNameOfSharedFile, "rb")) != NULL) 
        {
            if(fgets (data, sizeof (data), filePointer) != NULL)
            {

                printf ("DataMonitor Received data from DataReader ... <%s>\n", data);

                previousMachineID = machineID;
                previousStatusCode = statusCode;

                // seek to end and use pointer arithmetic to calculate
                // how many bytes we want to read at a time
                fseek(filePointer, SEEK_END - (sizeof(int) * 2), 0);

                // read data
                fread(&machineID, sizeof(int), 1, filePointer);

                printf("Machine id: %d\n", machineID);

                fread(&statusCode, sizeof(int), 1, filePointer);

                printf("Status Code: %d\n", statusCode);

                // check if machine has gone off line
                if(machineID == 0x00000000 || statusCode == 0xFFFFFFFF)
                {
                    // get time stamp
                    time_t currentTime;
                    struct tm* timeinfo;
                    time ( &currentTime );
                    timeinfo = localtime ( &currentTime );

                    char* subject = "Server Has Gone Offline\n";

                    char* message = "";
                    sprintf(message, "DC Machine ID: %d \nStatus Reported: %s \nStatus Effective: %s \n", machineID, GetStatusCode(statusCode), asctime(timeinfo));

                    // if the email sent succesfully, break out of loop and continue to clean up environment
                    if(SendEmail(kNameOfSender, kNameOfRecipent, subject, message) == 0)
                    {
                        break;
                    }
                }

                if(machineID != previousMachineID && statusCode != previousStatusCode)
                {
                    // get time stamp
                    time_t currentTime;
                    struct tm* timeinfo;
                    time ( &currentTime );
                    timeinfo = localtime ( &currentTime );

                    char* subject = "Update Status for Machine ID: ";
                    sprintf(subject, "Update Status for Machine ID: %d", machineID);

                    char* message = "";
                    sprintf(message, "DC Machine ID: %d \nStatus Reported: %s \nStatus Effective: %s \n", machineID, GetStatusCode(statusCode), asctime(timeinfo));

                    if(SendEmail(kNameOfSender, kNameOfRecipent, subject, message) == 0)
                    {
                        continue;
                    }
                }
            }
            fclose (filePointer);
        }

        // attempt to change semaphore status
        if (semop (semID, &release_operation, 1) == -1) 
        {
            printf ("DM can't end critical region\n");
            break;
        }

似乎是一些 SystemV 或 POSIX IPC 代码....

要在多个进程中使用信号量,每个用户都需要使用相同的 key(semget 的第一个参数)对 semget() 执行调用。这个 key 是一种全局名称,需要在信号量访问的所有参与者之间知道(和共享)才能访问同一个信号量实例。

像您一样使用 IPC_PRIVATE 作为密钥将创建一个唯一的(私有)信号量,该信号量不太可能在不同进程之间共享。 (其实目的是得到一个别人不知道的信号量。)

因此为您的服务器和客户端定义了一个公共键(选择一些 int 值)并从两个进程调用 semget()。然后所有对 semop 的调用(使用返回的 samephoreId)将访问信号量的相同实例。