How do I link client and server to the same semaphore

260 Views Asked by At

I am working on an assignment that uses IPC schemes to communicate between and "Server" and a "Client" over shared files.

The shared file is created in the server application called the Data Reader along with a semaphore which is initialized. The code for this is here:

/*
*
*   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;
}

The Data monitor ("Client") needs to use be in contact with this semaphore to make sure they never talk at the same time. I am not sure if the client needs to have access to this same semaphore ID, or what the protocol is for these two processes to be in a semaphore together?

The code for the data monitor is below, and it is not able to enter the critical region, nor do I think it will correctly connect with the server process.

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;
        }
1

There are 1 best solutions below

2
On BEST ANSWER

Seems to be some SystemV or POSIX IPC code....

For using a semaphore among several processes every user needs to execute a call on semget() using the very same key (first parameter to semget). This key is kind of a global name that needs to be known (and shared) among all participants of the semaphore access to get access to the very same semaphore instance.

Using IPC_PRIVATE for the key as you do will create a unique (private) semaphore that is very unlikely to be shared among different processes. (Actualy the purpose is to get a semaphore that is not knowable to anybody else.)

So defined a common key for both your server and your client (chose some int value) and call semget() from both processes. Then all calls to semop (using the samephoreId returned) will access the same instance of the semaphore.