0

我正在处理一项使用 IPC 方案通过共享文件在“服务器”和“客户端”之间进行通信的任务。

共享文件是在名为 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;
}

数据监视器(“客户端”)需要与此信号量保持联系,以确保它们不会同时交谈。我不确定客户端是否需要访问这个相同的信号量 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;
        }
4

1 回答 1

1

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

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

IPC_PRIVATE像您一样使用密钥将创建一个独特的(私有)信号量,该信号量不太可能在不同进程之间共享。(实际上目的是获得一个其他人都不知道的信号量。)

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

于 2016-04-08T23:22:19.307 回答