WEBVTT

00:05.410 --> 00:06.910
So welcome back, guys.

00:07.030 --> 00:13.420
So here we will going to discuss a new server design which has multiplexing capabilities.

00:13.450 --> 00:18.250
That is, our server will be able to handle multiple clients at the same time.

00:18.430 --> 00:21.730
So the source code you can find in the following directory.

00:21.730 --> 00:25.960
In multiplexing directory, you can find a file server dot c.

00:26.500 --> 00:30.040
So this is the file that we will going to discuss.

00:32.290 --> 00:38.380
Since you already have a code walk and now you know how to implement a Unix domain server.

00:38.650 --> 00:44.470
So many steps of implementing Unix domain server will going to be stay same.

00:44.470 --> 00:45.890
There is no difference.

00:45.910 --> 00:53.320
However, since it is a multiplex server, therefore there shall be a little design change because of

00:53.320 --> 00:59.170
which this Unix domain server can handle multiple clients at the same time.

00:59.440 --> 01:07.570
So Unix domain socket name that we will going to use is same as previous, that is demo socket and buffer

01:07.570 --> 01:14.770
size for receiving and sending a data is 128 bytes and as this server will going to maintain multiple

01:14.770 --> 01:20.260
clients at the same time, we have taken an upper limit on the number of clients that can be connected

01:20.260 --> 01:22.090
to this server at the same time.

01:22.300 --> 01:29.080
So let us say that maximum number of clients that can be connected to this server is 31.

01:29.110 --> 01:31.880
That is one less than this macro.

01:31.880 --> 01:35.870
The reason is that a server has to maintain one additional.

01:37.050 --> 01:40.590
File descriptor and that is master socket file descriptor.

01:41.990 --> 01:45.130
Now, we have taken a global array here.

01:45.140 --> 01:48.570
The name of the array is monitored file descriptor set.

01:48.590 --> 01:55.700
So as the name suggests, that it is an array of all the file descriptors which are server process is

01:55.700 --> 01:56.570
maintaining.

01:57.220 --> 02:04.810
So if our server process, let's say, has three clients connected at the same time, so this array

02:04.810 --> 02:07.990
will going to contain four file descriptors.

02:08.080 --> 02:13.630
The three file descriptors of the three clients and one is the master socket file descriptor.

02:13.900 --> 02:21.460
So basically this is an array of all the active file descriptors that our server is maintaining.

02:21.610 --> 02:24.220
And what is the functionality of our server?

02:24.250 --> 02:27.480
The functionality of our server is remain unchanged.

02:27.490 --> 02:33.790
That is, our server process will going to accept the integer values that is being sent by the client

02:33.790 --> 02:41.860
and our server process will keep on computing the summation of all those integer values and our server

02:41.860 --> 02:46.270
will send back the summation of all the values to our client.

02:46.300 --> 02:50.260
When the client send a value as zero to the server.

02:50.500 --> 02:54.100
So this server functionality we have already discussed.

02:54.340 --> 02:58.310
So here the functionality of the server is unchanged.

02:59.200 --> 03:01.450
So I have written a few APIs.

03:01.450 --> 03:09.130
For example, initialize monitor file descriptor set and add to monitor file descriptor set and remove

03:09.130 --> 03:11.100
from monitored file descriptor set.

03:11.110 --> 03:20.350
So these APIs actually perform operations on our global array of monitored file descriptors.

03:21.310 --> 03:30.340
So initialize monitor file descriptor set is a function which does nothing except it initializes all

03:30.340 --> 03:32.650
the elements in the array with minus one.

03:32.830 --> 03:37.780
So here minus one is a representation that the array is empty.

03:39.280 --> 03:46.330
So if all the blocks in the array is minus one, it means the server is not maintaining any file descriptors

03:46.330 --> 03:47.740
at that point of time.

03:48.010 --> 03:51.490
So initialize monitor file descriptor set actually.

03:52.390 --> 03:55.580
Empty is the monitored file descriptor set area.

03:56.780 --> 04:04.070
Then the second API is add to monitored file descriptor set and it takes an argument, an integer value,

04:04.070 --> 04:05.930
which is a file descriptor.

04:06.140 --> 04:12.170
So this API is simply finds an empty slot in the monitored file descriptor set array.

04:12.320 --> 04:18.350
And if it finds an empty slot then it adds this argument to this array.

04:18.380 --> 04:25.370
So basically this function adds a new file descriptor to be monitored by the server to the monitored

04:25.370 --> 04:26.960
file descriptor set array.

04:27.260 --> 04:35.600
Similarly, we have the API remove from monitored file descriptor set, which removes a given file descriptor

04:35.600 --> 04:37.880
from the monitored file descriptor set array.

04:39.040 --> 04:39.670
Right.

04:40.360 --> 04:42.640
So why have we written all these APIs?

04:42.970 --> 04:50.380
Because we know that our server process has to maintain the communication file descriptors for all the

04:50.380 --> 04:53.350
clients that it is carrying out communication with.

04:55.200 --> 05:02.010
So it is for this reason that we have written these APIs which perform an operation on an array and

05:02.010 --> 05:06.150
array is a collection of file descriptors, which are server process is maintaining.

05:06.450 --> 05:15.000
Then the next API is refresh Fdset and the pointer to this API is a pointer to the structure fd underscore

05:15.000 --> 05:15.630
set.

05:15.810 --> 05:22.020
So remember, this set is a standard data structure that is provided by C library.

05:23.790 --> 05:33.300
And as the name suggests, this API simply removes all the older file descriptors from this set data

05:33.300 --> 05:42.540
structure and it recopies all the monitored file descriptors present in our array to this empty set

05:42.570 --> 05:43.560
data structure.

05:43.770 --> 05:50.850
So basically this function performs the cloning of file descriptors present in monitored file descriptor

05:50.850 --> 05:56.550
set array into a standard data structure feed set data structure.

05:58.030 --> 06:03.940
So when we will discuss the code further, you will understand that what is the use of this API?

06:04.120 --> 06:11.500
For now, just understand that this API simply removes the older values of file descriptors from data

06:11.500 --> 06:13.300
structure and copies.

06:13.300 --> 06:20.530
The file descriptors which are being maintained in our array to this set data structure.

06:21.150 --> 06:27.000
So basically this API refreshes the standard set data structure.

06:28.150 --> 06:31.150
With the file descriptors present in the array.

06:32.780 --> 06:35.230
Then the next API is get max feed.

06:36.410 --> 06:43.820
So this API simply returns the numerical maximum value among all the file descriptors which server is

06:43.820 --> 06:44.660
maintaining.

06:45.410 --> 06:51.460
So, for example, if the server is maintaining the file descriptors say six, seven, eight.

06:51.470 --> 06:54.890
So this API will going to return me eight.

06:55.820 --> 07:03.260
Now, having discussed all these APIs, now we can proceed to discuss our server design in detail.

07:03.980 --> 07:06.290
So let us start with the main function.

07:07.690 --> 07:14.170
So in the main functions, the first thing that we have done is to call the initialize monitored feed

07:14.200 --> 07:16.120
set function.

07:16.510 --> 07:18.910
So remember, what does this function do?

07:19.120 --> 07:26.410
This function simply initialize the monitored file descriptor set array with minus one value.

07:26.680 --> 07:34.630
It means that currently when our server has booted up, our server is not maintaining any file descriptor

07:34.630 --> 07:35.590
as of now.

07:36.910 --> 07:42.410
So I'm skipping the steps which we have already discussed in our previous server design.

07:42.430 --> 07:46.330
There is no change with respect to these steps, so I am skipping them.

07:47.450 --> 07:53.240
So the next thing our server will do is to create a master socket file descriptor, which we also call

07:53.240 --> 07:54.770
it as connection socket.

07:55.950 --> 08:01.890
Then after creating a connection socket, our server again invokes the bind system call.

08:02.960 --> 08:07.230
And after the bind system call, we are invoking the listen system call.

08:07.250 --> 08:13.580
So all these steps are unchanged as compared to our previous server design discussion.

08:14.400 --> 08:21.880
So all these steps that is creating a connection socket, then doing a bind and then invoking a lesson

08:21.960 --> 08:26.850
system call are exactly the same and remain unchanged.

08:27.890 --> 08:31.160
As compared to our last server design discussion.

08:31.810 --> 08:36.100
Now at this point of time, that is by line number 167.

08:36.310 --> 08:40.900
Our server process has created a master socket file descriptor successfully.

08:41.110 --> 08:46.900
So you can see that when the server process boots up, the first thing that the server process does

08:46.930 --> 08:54.010
is to create a master socket file descriptor and add this master socket file descriptor to set data

08:54.010 --> 08:54.790
structure.

08:54.820 --> 08:58.750
So here we have created a master socket file descriptor.

08:59.620 --> 09:06.750
And next thing that the server process will do is to add this master socket file descriptor to the set

09:06.790 --> 09:07.820
data structure.

09:07.840 --> 09:14.380
So here by invoking this API, we are actually adding the master socket file descriptor to the monitored

09:14.380 --> 09:16.060
file descriptor set array.

09:16.930 --> 09:21.580
And now here we are entering into the infinite server process loop.

09:21.610 --> 09:28.720
Now you can see here that our server process is invoking refresh set API.

09:28.930 --> 09:35.860
Now the argument to this refresh set API is a pointer to a set data structure.

09:35.950 --> 09:43.150
So you can see in the beginning of this function we had declared read FDs as a variable of type FD set

09:43.180 --> 09:44.200
data structure.

09:45.820 --> 09:52.000
And this set data structure is actually a collection of file descriptors which are being monitored.

09:53.420 --> 09:59.990
So this data structure must contain all the file descriptors which are also present in our monitored

09:59.990 --> 10:01.580
file descriptor set array.

10:01.820 --> 10:10.180
So basically our monitored file descriptor set array, which is a global array that is this array and

10:10.460 --> 10:18.650
feed set data structure that is this variable which is also a set has to be clone of each other before

10:18.650 --> 10:20.330
invoking the select system call.

10:21.680 --> 10:30.770
So it is for this reason that before invoking a select system call, we had invoked refresh set function

10:30.770 --> 10:38.870
and we have passed the standard set data structure to this function so that all the monitored file descriptors

10:38.870 --> 10:45.890
which are present in monitored file descriptor set array will get copied to this standard.

10:47.080 --> 10:48.670
The set data structure.

10:49.680 --> 10:54.100
This is done because to invoke a select system call.

10:54.120 --> 11:02.570
The second argument has to be set data structure and while invoking the select system call, the set

11:02.580 --> 11:08.820
data structure must contain all the monitored file descriptors, including master socket file descriptor

11:08.820 --> 11:10.740
to be maintained by the server.

11:11.780 --> 11:15.610
So basically before just invoking the select system call.

11:15.620 --> 11:18.500
So we are just doing the cloning thing.

11:18.500 --> 11:25.190
We are cloning all the file descriptors present in our monitored file descriptor set array into the

11:25.190 --> 11:27.560
standard set data structure.

11:29.300 --> 11:30.050
Now.

11:32.220 --> 11:39.690
The first argument of the select system call is the maximum numerical file descriptor present in the

11:39.780 --> 11:42.810
set data structure plus one.

11:43.620 --> 11:50.970
So such is the synopsis of select system call that whatever be the file descriptors.

11:51.750 --> 11:54.910
You are trying to monitor using select system call.

11:54.930 --> 12:00.270
The first argument to the select system call has to be one higher value.

12:00.300 --> 12:07.200
So, for example, if your server process is monitoring file descriptor, say six, seven, eight,

12:07.230 --> 12:11.940
then the first argument to the select system call you should pass is nine.

12:13.010 --> 12:18.710
So such is the synopsis of Select system call and the argument three, four and five.

12:18.740 --> 12:20.780
You can just pass as null.

12:22.530 --> 12:26.490
So as I said, that Select system call is a blocking system call.

12:26.490 --> 12:34.110
That is, as soon as the select system call will be invoked, the server process will get blocked on

12:34.110 --> 12:36.540
line number 183.

12:36.960 --> 12:40.830
So comparing with this diagram, our server process has booted up.

12:40.830 --> 12:47.070
Our server process has created master socket file descriptor and we have added this master socket file

12:47.070 --> 12:49.860
descriptor to set data structure.

12:49.860 --> 12:56.190
And now our server process has invoked the select system call on this set data structure.

12:56.820 --> 13:02.460
So at this point of time the set data structure contains only one file descriptors, which is master

13:02.460 --> 13:03.750
socket file descriptor.

13:04.270 --> 13:12.280
So it means that our server process will get unblocked when some client C1 sends the connection initiation

13:12.280 --> 13:14.500
request to our server process.

13:15.450 --> 13:16.110
Right.

13:16.350 --> 13:26.100
So we will hit line number 185 only when some new client has sent connection initiation request to our

13:26.100 --> 13:27.210
server process.

13:28.560 --> 13:35.790
So in line number 185, we are checking that whether it is the master socket file descriptor which is

13:35.790 --> 13:36.780
activated.

13:36.810 --> 13:41.910
So remember, master socket file descriptor was a member of set data structure.

13:42.870 --> 13:50.850
So the C API provide us the standard macro, which is FD, underscore is set and we can use this macro

13:50.850 --> 13:58.140
to test whether the file descriptor which is specified as first argument that is connection socket in

13:58.140 --> 14:01.080
this case has been activated or not.

14:01.350 --> 14:07.890
So if this condition is true, it means that some new client has sent connection initiation request

14:07.890 --> 14:09.510
to our server process.

14:10.740 --> 14:14.670
So we are printing that new connection has been received.

14:14.700 --> 14:22.110
Now the second thing that our server process has to do is to accept this connection request from the

14:22.110 --> 14:23.130
client C one.

14:24.540 --> 14:32.380
So you can see that here our server process is accepting the connection and the return value of accept

14:32.380 --> 14:38.140
system call is a communication file descriptor, which we also call it as data socket.

14:39.920 --> 14:46.280
And the next thing that our server process has to do is to add this data socket to monitor file descriptor

14:46.280 --> 14:46.940
set array.

14:48.430 --> 14:49.630
Because.

14:50.300 --> 14:58.100
In the next invocation of select System call, our server process will have to monitor this new data

14:58.100 --> 14:59.150
socket as well.

15:00.370 --> 15:03.790
So this data socket is actually a client handle.

15:04.210 --> 15:10.570
So you can see in this diagram that as soon as the server process has created communication file descriptor

15:10.570 --> 15:18.160
for the client C1, it will add this communication file descriptor to fdset data structure so that in

15:18.160 --> 15:25.510
the invocation of next select system, call the newly created communication file descriptor for client

15:25.510 --> 15:27.460
C1 can also be monitored.

15:27.790 --> 15:31.060
So since this if condition is true.

15:33.820 --> 15:39.550
Therefore, we will go back to the select system call again because we are in infinite loop.

15:39.550 --> 15:45.130
So again, you can see that we are again refreshing the set data structure.

15:46.380 --> 15:53.730
Means that we are now copying the master socket file descriptor as well as the newly created communication

15:53.730 --> 15:56.520
file descriptor for the client C1.

15:58.060 --> 16:01.150
To the to this data structure.

16:01.690 --> 16:05.170
And again, we are now invoking the select system call.

16:05.930 --> 16:12.650
At this point of time when we invoke the select system, call or set data structure now contains two

16:12.650 --> 16:17.990
file descriptors that is master socket file descriptor and the communication file descriptor of client

16:18.030 --> 16:18.650
C1.

16:19.430 --> 16:28.070
So it means that select system call will get unblocked if either our server receives new connection

16:28.070 --> 16:36.530
initiation request from new client or our server process receives data request from client one.

16:38.300 --> 16:38.930
Right.

16:39.230 --> 16:41.000
It is because.

16:41.750 --> 16:50.150
The select System call has been invoked on set data structure, which contains two file descriptors.

16:51.390 --> 16:55.770
The master socket file descriptor and communication file descriptor.

16:56.810 --> 17:02.930
So again, when the select system call Unblocks, then we need to check the reason that why Select System

17:02.930 --> 17:04.430
Call has been unblocked.

17:04.550 --> 17:11.270
Is it been unblocked because some new client has sent new connection initiation request to our server

17:11.270 --> 17:11.930
process.

17:11.960 --> 17:15.680
If yes, then this if condition will going to be true.

17:18.530 --> 17:22.850
And if not, it means that we will land up in the else part.

17:23.270 --> 17:31.330
So if master socket is not activated, it means that some communication file descriptor present in set

17:31.340 --> 17:33.290
data structure has been activated.

17:33.680 --> 17:40.760
Now the next thing that our server process has to do is to find that particular communication file descriptor

17:40.760 --> 17:42.560
which has been activated.

17:43.290 --> 17:51.240
So basically we will end up in the loop when some already connected client has sent data request to

17:51.240 --> 17:52.480
our server process.

17:52.500 --> 17:59.430
So our server now has to find that exactly which connected client has sent data request to.

18:00.150 --> 18:01.090
To it.

18:01.110 --> 18:07.530
So this is done by looping over the entire monitored file descriptor set array.

18:08.190 --> 18:15.300
And then we are testing each element in the array, whether that particular element has been activated

18:15.300 --> 18:16.110
or not.

18:16.770 --> 18:17.490
Right.

18:20.490 --> 18:27.090
So this condition will be true only for those client which has sent data request to our server process.

18:27.450 --> 18:35.190
So let us say that some client has send data request to our server process so our server process will

18:35.190 --> 18:40.920
go into fetch the communication file descriptor from this monitored file descriptor set array.

18:41.320 --> 18:46.890
So remember the monitored file descriptor set array is nothing, but it is a set of integer values which

18:46.920 --> 18:48.810
actually represent client handles.

18:48.930 --> 18:55.380
So we have got the client handle in line number two, zero and eight, and it is this client which actually

18:55.410 --> 18:57.990
send the data request to our server process.

18:59.070 --> 19:05.550
So the next thing our server process will have to do is to read the data which is sent by this client.

19:05.760 --> 19:11.700
So using read system call, our server process is now reading the actual data that is sent by this client.

19:12.830 --> 19:19.550
And remember that our server process expects integer value from the clients.

19:19.640 --> 19:22.310
So our server process is now testing that.

19:22.310 --> 19:24.230
Whether the client has sent zero.

19:24.440 --> 19:29.360
If the client has sent zero, then our server process has to send back the result to the client.

19:30.520 --> 19:37.420
So you can see that our server process is replying back to the client using a write system call.

19:38.280 --> 19:43.860
And the buffer contains the result which our server process is returning to the client.

19:44.010 --> 19:51.210
So you can see that this buffer has been prepared above that is in this line.

19:51.950 --> 19:57.590
So you can see that client result is an array which stores the summation of all the values that is sent

19:57.590 --> 19:59.180
by that particular client.

19:59.450 --> 20:01.370
And once the server.

20:02.740 --> 20:05.300
Returns the result back to the client.

20:05.320 --> 20:11.620
The server closes the connection with that client and it will remove.

20:12.600 --> 20:16.050
The client handle from the monitored file descriptor set array.

20:16.560 --> 20:17.910
Why it is removing?

20:17.910 --> 20:21.210
Because our server process is now done with this client.

20:22.300 --> 20:29.740
And in the next invocation of the select system call our server process need not to maintain this client

20:29.770 --> 20:30.880
handle anymore.

20:32.020 --> 20:37.490
So let us assume that the client process has sent some non-zero value.

20:37.510 --> 20:43.990
So if the client process sends some non-zero value, then our server process will hit the line number

20:43.990 --> 20:45.640
244.

20:45.670 --> 20:52.360
So in this line, the server process simply computing the summation of all the values that is being

20:52.360 --> 20:53.560
sent by the client.

20:54.460 --> 21:01.480
And after the server process has processed, the value that is received by the client or server process

21:01.480 --> 21:07.720
goes back and get blocked at the select system call again, that is waiting either for the new connection

21:07.720 --> 21:14.230
initiation request from new client or waiting for the new data from any connected client.

21:14.260 --> 21:22.150
So this is the implementation of the entire state machine diagram of the server, which has multiplexing

21:22.150 --> 21:28.870
capabilities that is, can entertain or process multiple clients request at the same time.

21:29.710 --> 21:37.570
So I have explained each and every line of this program, and you are requested to analyze the implementation

21:37.570 --> 21:38.770
of this program.

21:38.890 --> 21:46.960
And and it should be very clear to you by now that how the state machine diagram of a multiplex server

21:46.960 --> 21:48.440
is implemented.

21:48.460 --> 21:50.520
So next, let us discuss.

21:50.530 --> 21:53.830
So next, let us see the demonstration.

21:54.570 --> 21:59.100
Regarding how this server process can handle multiple clients at the same time.
