So welcome back, guys.
So here we will going to discuss a new server design which has multiplexing capabilities.
That is, our server will be able to handle multiple clients at the same time.
So the source code you can find in the following directory.
In multiplexing directory, you can find a file server dot c.
So this is the file that we will going to discuss.
Since you already have a code walk and now you know how to implement a Unix domain server.
So many steps of implementing Unix domain server will going to be stay same.
There is no difference.
However, since it is a multiplex server, therefore there shall be a little design change because of
which this Unix domain server can handle multiple clients at the same time.
So Unix domain socket name that we will going to use is same as previous, that is demo socket and buffer
size for receiving and sending a data is 128 bytes and as this server will going to maintain multiple
clients at the same time, we have taken an upper limit on the number of clients that can be connected
to this server at the same time.
So let us say that maximum number of clients that can be connected to this server is 31.
That is one less than this macro.
The reason is that a server has to maintain one additional.
File descriptor and that is master socket file descriptor.
Now, we have taken a global array here.
The name of the array is monitored file descriptor set.
So as the name suggests, that it is an array of all the file descriptors which are server process is
maintaining.
So if our server process, let's say, has three clients connected at the same time, so this array
will going to contain four file descriptors.
The three file descriptors of the three clients and one is the master socket file descriptor.
So basically this is an array of all the active file descriptors that our server is maintaining.
And what is the functionality of our server?
The functionality of our server is remain unchanged.
That is, our server process will going to accept the integer values that is being sent by the client
and our server process will keep on computing the summation of all those integer values and our server
will send back the summation of all the values to our client.
When the client send a value as zero to the server.
So this server functionality we have already discussed.
So here the functionality of the server is unchanged.
So I have written a few APIs.
For example, initialize monitor file descriptor set and add to monitor file descriptor set and remove
from monitored file descriptor set.
So these APIs actually perform operations on our global array of monitored file descriptors.
So initialize monitor file descriptor set is a function which does nothing except it initializes all
the elements in the array with minus one.
So here minus one is a representation that the array is empty.
So if all the blocks in the array is minus one, it means the server is not maintaining any file descriptors
at that point of time.
So initialize monitor file descriptor set actually.
Empty is the monitored file descriptor set area.
Then the second API is add to monitored file descriptor set and it takes an argument, an integer value,
which is a file descriptor.
So this API is simply finds an empty slot in the monitored file descriptor set array.
And if it finds an empty slot then it adds this argument to this array.
So basically this function adds a new file descriptor to be monitored by the server to the monitored
file descriptor set array.
Similarly, we have the API remove from monitored file descriptor set, which removes a given file descriptor
from the monitored file descriptor set array.
Right.
So why have we written all these APIs?
Because we know that our server process has to maintain the communication file descriptors for all the
clients that it is carrying out communication with.
So it is for this reason that we have written these APIs which perform an operation on an array and
array is a collection of file descriptors, which are server process is maintaining.
Then the next API is refresh Fdset and the pointer to this API is a pointer to the structure fd underscore
set.
So remember, this set is a standard data structure that is provided by C library.
And as the name suggests, this API simply removes all the older file descriptors from this set data
structure and it recopies all the monitored file descriptors present in our array to this empty set
data structure.
So basically this function performs the cloning of file descriptors present in monitored file descriptor
set array into a standard data structure feed set data structure.
So when we will discuss the code further, you will understand that what is the use of this API?
For now, just understand that this API simply removes the older values of file descriptors from data
structure and copies.
The file descriptors which are being maintained in our array to this set data structure.
So basically this API refreshes the standard set data structure.
With the file descriptors present in the array.
Then the next API is get max feed.
So this API simply returns the numerical maximum value among all the file descriptors which server is
maintaining.
So, for example, if the server is maintaining the file descriptors say six, seven, eight.
So this API will going to return me eight.
Now, having discussed all these APIs, now we can proceed to discuss our server design in detail.
So let us start with the main function.
So in the main functions, the first thing that we have done is to call the initialize monitored feed
set function.
So remember, what does this function do?
This function simply initialize the monitored file descriptor set array with minus one value.
It means that currently when our server has booted up, our server is not maintaining any file descriptor
as of now.
So I'm skipping the steps which we have already discussed in our previous server design.
There is no change with respect to these steps, so I am skipping them.
So the next thing our server will do is to create a master socket file descriptor, which we also call
it as connection socket.
Then after creating a connection socket, our server again invokes the bind system call.
And after the bind system call, we are invoking the listen system call.
So all these steps are unchanged as compared to our previous server design discussion.
So all these steps that is creating a connection socket, then doing a bind and then invoking a lesson
system call are exactly the same and remain unchanged.
As compared to our last server design discussion.
Now at this point of time, that is by line number 167.
Our server process has created a master socket file descriptor successfully.
So you can see that when the server process boots up, the first thing that the server process does
is to create a master socket file descriptor and add this master socket file descriptor to set data
structure.
So here we have created a master socket file descriptor.
And next thing that the server process will do is to add this master socket file descriptor to the set
data structure.
So here by invoking this API, we are actually adding the master socket file descriptor to the monitored
file descriptor set array.
And now here we are entering into the infinite server process loop.
Now you can see here that our server process is invoking refresh set API.
Now the argument to this refresh set API is a pointer to a set data structure.
So you can see in the beginning of this function we had declared read FDs as a variable of type FD set
data structure.
And this set data structure is actually a collection of file descriptors which are being monitored.
So this data structure must contain all the file descriptors which are also present in our monitored
file descriptor set array.
So basically our monitored file descriptor set array, which is a global array that is this array and
feed set data structure that is this variable which is also a set has to be clone of each other before
invoking the select system call.
So it is for this reason that before invoking a select system call, we had invoked refresh set function
and we have passed the standard set data structure to this function so that all the monitored file descriptors
which are present in monitored file descriptor set array will get copied to this standard.
The set data structure.
This is done because to invoke a select system call.
The second argument has to be set data structure and while invoking the select system call, the set
data structure must contain all the monitored file descriptors, including master socket file descriptor
to be maintained by the server.
So basically before just invoking the select system call.
So we are just doing the cloning thing.
We are cloning all the file descriptors present in our monitored file descriptor set array into the
standard set data structure.
Now.
The first argument of the select system call is the maximum numerical file descriptor present in the
set data structure plus one.
So such is the synopsis of select system call that whatever be the file descriptors.
You are trying to monitor using select system call.
The first argument to the select system call has to be one higher value.
So, for example, if your server process is monitoring file descriptor, say six, seven, eight,
then the first argument to the select system call you should pass is nine.
So such is the synopsis of Select system call and the argument three, four and five.
You can just pass as null.
So as I said, that Select system call is a blocking system call.
That is, as soon as the select system call will be invoked, the server process will get blocked on
line number 183.
So comparing with this diagram, our server process has booted up.
Our server process has created master socket file descriptor and we have added this master socket file
descriptor to set data structure.
And now our server process has invoked the select system call on this set data structure.
So at this point of time the set data structure contains only one file descriptors, which is master
socket file descriptor.
So it means that our server process will get unblocked when some client C1 sends the connection initiation
request to our server process.
Right.
So we will hit line number 185 only when some new client has sent connection initiation request to our
server process.
So in line number 185, we are checking that whether it is the master socket file descriptor which is
activated.
So remember, master socket file descriptor was a member of set data structure.
So the C API provide us the standard macro, which is FD, underscore is set and we can use this macro
to test whether the file descriptor which is specified as first argument that is connection socket in
this case has been activated or not.
So if this condition is true, it means that some new client has sent connection initiation request
to our server process.
So we are printing that new connection has been received.
Now the second thing that our server process has to do is to accept this connection request from the
client C one.
So you can see that here our server process is accepting the connection and the return value of accept
system call is a communication file descriptor, which we also call it as data socket.
And the next thing that our server process has to do is to add this data socket to monitor file descriptor
set array.
Because.
In the next invocation of select System call, our server process will have to monitor this new data
socket as well.
So this data socket is actually a client handle.
So you can see in this diagram that as soon as the server process has created communication file descriptor
for the client C1, it will add this communication file descriptor to fdset data structure so that in
the invocation of next select system, call the newly created communication file descriptor for client
C1 can also be monitored.
So since this if condition is true.
Therefore, we will go back to the select system call again because we are in infinite loop.
So again, you can see that we are again refreshing the set data structure.
Means that we are now copying the master socket file descriptor as well as the newly created communication
file descriptor for the client C1.
To the to this data structure.
And again, we are now invoking the select system call.
At this point of time when we invoke the select system, call or set data structure now contains two
file descriptors that is master socket file descriptor and the communication file descriptor of client
C1.
So it means that select system call will get unblocked if either our server receives new connection
initiation request from new client or our server process receives data request from client one.
Right.
It is because.
The select System call has been invoked on set data structure, which contains two file descriptors.
The master socket file descriptor and communication file descriptor.
So again, when the select system call Unblocks, then we need to check the reason that why Select System
Call has been unblocked.
Is it been unblocked because some new client has sent new connection initiation request to our server
process.
If yes, then this if condition will going to be true.
And if not, it means that we will land up in the else part.
So if master socket is not activated, it means that some communication file descriptor present in set
data structure has been activated.
Now the next thing that our server process has to do is to find that particular communication file descriptor
which has been activated.
So basically we will end up in the loop when some already connected client has sent data request to
our server process.
So our server now has to find that exactly which connected client has sent data request to.
To it.
So this is done by looping over the entire monitored file descriptor set array.
And then we are testing each element in the array, whether that particular element has been activated
or not.
Right.
So this condition will be true only for those client which has sent data request to our server process.
So let us say that some client has send data request to our server process so our server process will
go into fetch the communication file descriptor from this monitored file descriptor set array.
So remember the monitored file descriptor set array is nothing, but it is a set of integer values which
actually represent client handles.
So we have got the client handle in line number two, zero and eight, and it is this client which actually
send the data request to our server process.
So the next thing our server process will have to do is to read the data which is sent by this client.
So using read system call, our server process is now reading the actual data that is sent by this client.
And remember that our server process expects integer value from the clients.
So our server process is now testing that.
Whether the client has sent zero.
If the client has sent zero, then our server process has to send back the result to the client.
So you can see that our server process is replying back to the client using a write system call.
And the buffer contains the result which our server process is returning to the client.
So you can see that this buffer has been prepared above that is in this line.
So you can see that client result is an array which stores the summation of all the values that is sent
by that particular client.
And once the server.
Returns the result back to the client.
The server closes the connection with that client and it will remove.
The client handle from the monitored file descriptor set array.
Why it is removing?
Because our server process is now done with this client.
And in the next invocation of the select system call our server process need not to maintain this client
handle anymore.
So let us assume that the client process has sent some non-zero value.
So if the client process sends some non-zero value, then our server process will hit the line number
244.
So in this line, the server process simply computing the summation of all the values that is being
sent by the client.
And after the server process has processed, the value that is received by the client or server process
goes back and get blocked at the select system call again, that is waiting either for the new connection
initiation request from new client or waiting for the new data from any connected client.
So this is the implementation of the entire state machine diagram of the server, which has multiplexing
capabilities that is, can entertain or process multiple clients request at the same time.
So I have explained each and every line of this program, and you are requested to analyze the implementation
of this program.
And and it should be very clear to you by now that how the state machine diagram of a multiplex server
is implemented.
So next, let us discuss.
So next, let us see the demonstration.
Regarding how this server process can handle multiple clients at the same time.