0

IPC スキームを使用して共有ファイルを介して「サーバー」と「クライアント」の間で通信する課題に取り組んでいます。

共有ファイルは、データ リーダーと呼ばれるサーバー アプリケーションで、初期化されたセマフォと共に作成されます。このコードは次のとおりです。

/*
*
*   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 にアクセスする必要があるかどうか、またはこれら 2 つのプロセスが一緒にセマフォになるためのプロトコルが何であるかがわかりません。

データ モニターのコードを以下に示しますが、クリティカル リージョンに入ることができず、サーバー プロセスに正しく接続されるとは思いません。

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(返された同じ ID を使用して) へのすべての呼び出しは、セマフォの同じインスタンスにアクセスします。

于 2016-04-08T23:22:19.307 に答える