1

I have to create for academic purpose an "On-Demand Server" that is based on the TCP protocol. The client each time sends a KEY and a VALUE that I have to store them in a global struct like the one bellow:

I use a function named "put" to store every KEY and VALUE to the struct and a "get" function that uses the key and finds the correct value:

My problem is that if a client makes a change in the struct the next one won't be able to know. I used semaphores in order to make the server wait until the child finishes and then accept the next child but I have still the same problem.

I read that I have to make the memory of this struct shared in order to make this work using mmaps but still I can't find a proper solution.

I make my first steps in server programming and every help would be great.

Aris Kantas
  • 375
  • 1
  • 5
  • 15
  • Simply don't `fork`. It makes no sense and serves no purpose. – n. m. could be an AI Apr 27 '17 at 13:51
  • Not the central topic of your question (which really has more to do with architectural issues then technique at this point) but do the sizes of `keys` and `values` really need to be so large. As written, your struct requires an 8Mbyte minimum stack size. – ryyker Apr 27 '17 at 13:56
  • In fact no! They have to be at least 51 size. But that is something I can change at any time. @ryyker – Aris Kantas Apr 27 '17 at 13:59
  • @n.m. You see in every example I have found on the Internet as far as "On demand server" is concerned fork() is used. – Aris Kantas Apr 27 '17 at 14:00
  • Have you seen the post _[here](http://stackoverflow.com/a/13274800/645128)_ ?. It deals with sharing memory between forked processes, and has demo code to illustrate concept. – ryyker Apr 27 '17 at 14:26
  • @ryyker Yes. I tried everything but I never succeed to take the correct results. – Aris Kantas Apr 27 '17 at 14:52
  • @ArisKantas - Your original post centers around how to share information (memory) between processes. I do not see in your code example where you have tried _everything_ regarding that yet. Try some of the things discussed, then come back and share your success, or ask another question. – ryyker Apr 27 '17 at 15:05
  • You lock the entire data structure in order to make any change so only one process is running at a time. Might just as well have no concurrency at all. – n. m. could be an AI Apr 27 '17 at 15:12

1 Answers1

1

My problem is that if a client makes a change in the struct the next one won't be able to know.

As you noted, mmap() is part of the solution...
Shared memory needs of your application can be addressed with _shm_open()_, _shm_unlink()_, mmap etc. as illustrated in this post. And here for additional examples on shared memory

All of the essentials are summarized in the links, but this excerpt describes the basic concept:

shm_open() creates and opens a new, or opens an existing, POSIX shared memory object. A POSIX shared memory object is in effect a handle which can be used by unrelated processes to mmap(2) the same region of shared memory. The shm_unlink() function performs the converse operation, removing an object previously created by shm_open().

I also wanted to suggest that dynamic allocation of memory may be of use in creating space for your struct on an as-needed basis. The size of members, as shown are excessively large,

char keys[4096];
char values[4096];

but in comments you state they only need to be 51 bytes. The struct then can be created as a typedef:

struct keyvalue {
    char keys[51];
    char values[51];
} DATA;

The create an instance of a pointer to your struct:

DATA *pData = {0};

Which can then be sized on an as needed basis using standard malloc, and or realloc

pData = malloc(initialSize*sizeof(DATA));

As size requirements change, use the following to grow memory:

DATA *tmp = {0};
tmp = realloc(pData, newSize);
if(!tmp) return -1;//ensure memory allocation successful
pData = tmp;//tmp includes previous contents of pData, and more space
...  //continue using pData

Free pData when it is no longer needed.

free(pData);

To pass this struct in a function, the function might look like this:

void func1(DATA *d, int numElements)
{
    ...
    for(i=0;i<numElements;i++)
    {
        strcpy(d[i]->keys, "some key");
        strcpy(d[i]->values, "some value");
    }
    ...
}

To call that function with a copy of pData, if say it had a 1000 elements:

func1(pData, 1000);
Community
  • 1
  • 1
ryyker
  • 22,849
  • 3
  • 43
  • 87
  • At first, thank you very much for your detailed answer. I now have the following question. If I want to create 1000 instances of this struct and use them in a function how to I call the struct instance [i] etc? – Aris Kantas Apr 27 '17 at 15:01
  • Yes. it would look like `pData[i]->keys`, or `pData[i]->values`. See edit to my answer for illustration. – ryyker Apr 27 '17 at 15:15
  • Thank you again! So if i use your way every child will be able to use the struct and make changes that are visible to the other chlidren? – Aris Kantas Apr 27 '17 at 15:17
  • @ArisKantas - if your use of the functions discussed is implemented correctly, and your architecture is sound, yes. There is no reason to expect it wouldn't. Start off with a small project to prove the concept, then integrate your working code into your final project. – ryyker Apr 27 '17 at 15:21
  • The creation of the instance must be made in the main()? And also my problem is that the function I must use put() and get() must have strictly only the parameters I show in my question. So I can't pass the DATA pointer or the numElements. – Aris Kantas Apr 27 '17 at 15:30
  • If the prototypes of `get` and `put` are required as you have shown, that forces you to have a _process global_ copy of your struct, i.e. one for each client. Then you would write to, or read from a single element of the that process global using the functions. i.e. strcpy(pData->keys, "key"); The `put` and `get` prototypes force the issue. – ryyker Apr 27 '17 at 15:35
  • @ArisKantas - if I am not able to respond right away, it is because I have been called away for awhile. Leave any questions and I (or someone else) will try to answer when I return. Thank you. – ryyker Apr 27 '17 at 15:41
  • Could you please show me how can I use shmget and shmat properly in my exaple in order to make this work? – Aris Kantas Apr 28 '17 at 17:45