I used VC to create a chat program to familiarize myself with the socket programming model. Of course, I also put it on my resume. I didn't expect to be asked about the network models for each interview. I have long been unable to remember them, but I have to know a rough idea. Although there is no need for an interview, it is still necessary to summarize it. To learn something, you must clarify it.
I have not studied the development history of socket, But I have understood the development process through the analysis and comparison of these network models. The blocking model was first introduced as an example to illustrate the computer network. It is also the simplest. The basic principle is: first establish a socket connection and then operate on it, for example, read data from the socket. Because network transmission takes some time, even if the network is smooth, it takes time to accept data operations. For a simple single-threaded program, the process of receiving data cannot process other operations. For example, a window program does not work when you click the button or close the window when receiving data. Its disadvantage is obvious. You can only process one socket for a single thread, which is used for teaching, but the actual usage will not work.
To deal with multiple socket connections, wise people have invented the select model. This model uses a set to manage socket connections. Each time it queries the socket status in the set to achieve the ability to process multiple connections, the function prototype is int select (INT NFDs, fd_set far * readfds, fd_set far * writefds, fd_set far * contains TFDs, const struct timeval far * timeout ). For example, to determine whether a socket is readable, we first leave a fdread set empty, then add the socket to the set, and call select (0, & fdread, null, null, null). Then, we determine whether the socket is still in fdread. If it is still in fdread, the data is readable. The Data Reading and blocking model are the same. Call the Recv function. However, each set has a capacity limit, which is 64 by default. Of course, you can redefine the size of the set, but there is still a maximum limit, and you cannot set it to exceed this value, generally, it is 1024. Although the select model can process multiple connections, It is cumbersome to manage the set.
All users familiar with Windows operating systems know that window processing is message-based. Another new network model, wsaasyncselect, was invented. This model binds a message to each socket. When a socket event is set in advance on the socket, the operating system sends the message to the application to process the socket event, the function prototype is int wsaasynselect (socket S, hwnd, unsigned int wmsg, long Levent ). Hwnd indicates the handle to receive the message, wmsg specifies the Message ID, Levent sets the network events of interest by bit, and enters wsaasyncselect (S, hwnd, wm_socket, fd_connect | fd_read | fd_close ). The advantage of this model is that it processes many connections at the same time without any collection management. The disadvantage is that even if your program does not need a window, you need to define a window for the wsaasyncselect model. In addition, allowing a single window to handle thousands of socket operation events may become a performance bottleneck.
Similar to the wsaasynselect model, the wsaeventselect model is also invented. You can guess the name based on the event. When a socket event occurs in the wsaasynselect model, the system sends a message. In the wsaeventselect model, when a socket event is of interest, the system sets the corresponding wsaevent event to send a message. Maybe you are not very clear about sokect events and common wsaevent events. Socket events are related to socket operations, such as fd_read, fd_write, and fd_accept. Wsaevent is a traditional event, which has two statuses: signaled and non-signaled ). A message transmission event has occurred, and a message has not yet been sent. Each time we establish a connection, we bind an event to it. When the connection changes, the event will change to the mail status. So who will accept this event change? We use a wsawaitformultipleevents (...) function to wait for the event to occur. In the input parameter event array, only one event occurs, and the function will return (or you can set it to all events to return, which is useless here ), the returned value is the serial number of the event array, so that we know which event occurred, that is, the socket corresponding to the event has a socket operation event. This model has obvious advantages over the wsaasynselect model and does not require a window. The only drawback is that this model can only wait for 64 events at a time. This limit makes it necessary to organize a thread pool when processing multiple sockets. The scalability is not as good as the overlap model described later.
Overlapping I/O (overlapped I/O) models allow applications to achieve better system performance. The basic design principle of the overlap model is to allow applications to use overlapping data structures to deliver one or more Winsock I/O requests at a time. What exactly is an overlapping model? Similar to the wsaeventselect model (which is not appropriate later), The Event Selection Model binds an event to each socket connection, while the overlap model binds an overlap to each socket connection. When a socket event occurs on the connection, the corresponding overlap will be updated. In fact, the best of overlap lies in that, while updating and overlapping, it also transfers network data to the specified cache area. We know that the previous network model requires users to use the Recv function to accept data, which reduces the efficiency. For example, the wsaeventselect model is like a package notification from the post office. After receiving the notification, the user must go to the post office to get the package. The overlapping model is like door-to-door delivery. When the postman sends you a notification, the package is also placed in the warehouse you specified in advance.
The overlap model is divided into two modes: Event Notification and completion routine. Before analyzing the two modes, let's take a look at the overlapping data structure:
Typedef struct wsaoverlapped
{
DWORD internal;
DWORD internalhigh;
DWORD offset;
DWORD offsethigh;
Wsaevent hevent;
} Wsaoverlapped, far * lpwsaoverlapped;
In this data structure, internal, internalhigh, offset, and offsethigh are all used by the system. You don't have to worry about them. The only concern is hevent. If the event notification mode is used, the hevent points to the corresponding event handle. If the routine mode is completed, hevent is set to null. Now let's look at the event notification mode. First, create an event hevent, create an acceptoverlapped overlapping structure, and set acceptoverlapped. hevent = hevent. databuf is the data cache area we set in advance. When wsarecv (acceptsocket, & databuf, 1, & recvbytes, & flags, & acceptoverlapped, null) is called, The acceptsocket and acceptoverlapped are overlapped and bound together. After receiving the data, the hevent is set to send messages, and the data is placed in databuf. We then receive the Event Notification through wsawaitformultipleevents. Here, we should note that since it is based on event notification, there is an event processing ceiling, usually 64.
The difference between the completion routine and the Event Notification mode is that when a socket event occurs, the system calls the callback function specified in advance instead of setting the event. In fact, it is to set the last parameter of wsarecv as a function pointer. The callback function is prototype as follows:
Void callback completionroutine (
DWORD dwerror,
DWORD cbtransferred,
Lpwsaoverlapped lpoverlapped,
DWORD dwflags
);
Cbtransferred indicates the number of transmitted bytes, and lpoverlapped indicates the overlapped pointer in case of a socket event. We call wsarecv (acceptsocket, & databuf, 1, & recvbytes, & flags, & acceptoverlapped, workerroutine) to bind the acceptsocket to the workroutine routine. Here is a small note: When we create multiple socket connections, we 'd better put the overlap and the corresponding data cache area in a large data structure, so that, through the lpoverlapped pointer in the routine, we can directly find the corresponding data cache zone. Note that the same data cache zone cannot be used for multiple overlapping data so that data confusion occurs when multiple overlapping data are processed.
Next we will introduce the network model specifically used to process a large number of socket connections-the complete port. Because a lot of work needs to be done to add the socket to a complete port, and the initialization steps of other methods are much easier, it seems too complicated for new users to complete the port model. However, once you understand what is going on, you will find that the steps are not that complex. The so-called completion port is actually an I/O constructor used by windows. Besides socket handles, it can accept other things. Before using this mode, create an I/O completion port object. The function is defined as follows:
Handle createiocompletionport (
Handle filehandle,
Handle existingcompletionport,
DWORD completionkey,
DWORD numberofconcurrentthreads
);
This function is used for two completely different purposes: 1) to create a complete port object. 2) associate a handle with the completion port.
Using the numberofconcurrentthreads parameter, we can specify the number of threads that run simultaneously. Ideally, we want each processor to be responsible for running one thread separately to provide services for port completion and avoid too frequent thread task switching. For a socket connection, we use createiocompletionport (handle) Accept, completionport, (DWORD) perhandledata, 0) to bind the accept connection with the completionport completion port, the threads corresponding to the competionport constantly use getqueuedcompletionstatus to query whether I/O operations are completed for the socket connection associated with it. If yes, data is processed accordingly, then, wsarecv is used to re-deliver the socket connection and continue to work. The completion port performs well in terms of performance and scalability, and there is no limit on the number of associated socket connections.
The preceding six socket programming models are introduced. It seems that a new model has emerged. However, I have not done any network-related projects. I will try again later.