1. Select Model:
Select model: Through a Fd_set collection management socket, after the socket requirements are met, the socket is notified. Let the socket work. Avoid sockets entering blocking mode and making unnecessary waits. Select the Fd_set collection and the Select function at the core of the model. with this function, we can determine whether the data is present on the socket or whether it can be written to a socket.
usage : What should we do if we want to accept data from multiple sockets?
Because the current socket is blocked, direct processing is bound to complete the requirements
A. We can think of multi-threading, which really solves the problem of threading, but opening up a lot of threads is not a good choice;
b We can think of using the ioctlsocket () function to set the socket to non-blocking, and then loop through the socket to see whether the current socket has data, polling.
This solves the problem, but it can cause frequent switching of the state to the kernel to see if there is data to arrive and waste time.
C. Then try to use a switch only once to know if all socket buffers have data, so there is a select model
2.select function:
int Select (
int nfds,//ignored just to maintain compatibility with earlier Berkeley socket applications
fd_set far* readfds,//readability check (with data readable, connection closed, reset, terminate)
Fd_set far* writefds,//writable check (with data available)
Fd+set far* exceptfds,//out-of-band data check (out-of-band data)
const struct Timeval far* timeout//timeout
);
Working steps for the 3.select model:
(1) Define a collection fd_set and initialize to null
(2) Adding sockets to the Fd_set collection
(3) Check the accessibility of sockets
(4) Check whether the socket is still on the Fd_set collection
(5) Processing data
BOOL Udpnet::selectsocket () {timeval tv;tv.tv_sec =0;tv.tv_usec = 100;fd_set fdsets;//Create set Fd_zero (&fdsets);// Initialize the collection fd_set (m_socklisten,&fdsets);//Add the socket to the collection (this example is a socket), when adding multiple sockets, you can use the array plus for loop select (null,& FDSETS,NULL,NULL,&TV);//Only check readability, that is, fd_set in Fd_read to operate if (! Fd_isset (M_socklisten,&fdsets))//Check if S is a member of the set of S e t; if the answer is yes, then return T R U E. {return false;} return true;}
4.select function Parameter Description:
Three fd_set parameters: one for checking readability (Readfds), one for checking for writable (WRITEFDS), The other is for exception data (EXCEPFDS).
Fundamentally, the Fdset data type represents a collection of a specific set of sockets. which
The Readfds collection includes sockets that meet any one of the following conditions:
There is data to read in.
The connection has been closed, re-erected, or aborted.
If listen has been called and a connection is being established, the Accept function call succeeds.
The Writefds collection includes sockets that meet any one of the following conditions:
There is data to be sent.
If the processing of a non-locking connection call has been completed, the connection succeeds.
Finally, the Exceptfds collection includes sockets that meet any one of the following conditions:
If the processing of a non-locking connection call has been completed, the connection attempt fails.
There is out-of-band (OUT-OF-BAND,OOB) data available for reading.
Last parameter timeout:
corresponds to a pointer, which points to a timeval structure, used to determine how long the select waits for the I/O operation to complete.
If timeout is a null pointer, then the select call "locks" indefinitely or pauses until at least one descriptor meets the specified condition after the end.
The definition of the TIMEVAL structure is as follows:
struct Timeval {
Long tv_sec;
Long tv_usec;
} ;
Setting the timeout value to (0,0) indicates that select returns immediately, allowing the application to "poll" the select operation. For performance reasons, you should avoid such a setting.
When select completes successfully, it returns the total amount of all socket handles in the FD_SET structure that just have outstanding I/O operations.
If it exceeds the time set by Timeval, it will return 0.
How do I test whether a socket is "readable"?
You must add your own sockets to the Readfds collection, and then wait for the Select function to complete.
After the select is complete, you must determine whether your socket is still part of the Readfds collection. If the answer is yes, it indicates that the socket is "readable" and immediately proceeds to read the data from it.
In three parameters (Readfds, WRITEDFSS, and Exceptfds), any two can be null (NULL), but at least one cannot be a null value! In any non-empty collection, at least one socket handle must be included;
Otherwise, the Select function does not have anything to wait for.
For whatever reason, if the select call fails, it will return Socket_error
5.select
a socket is blocked or not blocked, select is there, it can be used for these 2 sockets, polling of any kind of socket detection, time-out is valid , the difference is:
When the select is complete and the socket is considered readable,
1. A blocked socket causes read to block until it reads all the required bytes;
2. A non-blocking socket will allow read to return after reading the data in FD, but if you originally requested to read 10 data, then read only 8 data, if you do not use Select again to determine whether it is readable, but directly read, it is possible to return Eagain or =ewouldblock (BSD style),
This error is returned by an operation that cannot be completed immediately on a non-blocking socket, for example, the recv () function is called when there is no queued data readable on the socket. This error is not a critical error, and the appropriate action should be retried later. Reporting Ewouldblock is normal for calling the Connect () function on a non-blocking sock_stream socket because it takes some time to establish a connection.
Ewouldblock means that if you do not set the socket to non-blocking (that is, blocking) mode, the read operation will block, that is, the data is not ready (but the system knows the data is coming, so select tells you that the socket is readable). The attentive person who uses non-blocking mode for I/O operations will check if errno is Eagain, Ewouldblock, eintr, and if so, it should be reread, usually with loops. If you are not sure to use non-blocking, do not set this up, which is why the default mode of the system is blocked.
Full Code reference:
#include "stdafx.h" #include <WinSock2.h> #include <iostream>using namespace std; #include <stdio.h># pragma comment (lib, "Ws2_32.lib") #define PORT 8000#define msgsize 255#define srv_ip "127.0.0.1" int g_nsockconn = 0;// The number of request connections//fd_setsize is defined in the Winsocket2.h header file, where Windows defaults to 64//by using a macro definition before the Winsocket2.h header file is included to modify the value of the struct clientinfo{ SOCKET sockclient; Sockaddr_in addrclient;}; Clientinfo G_client[fd_setsize];D word WINAPI workthread (LPVOID lpparameter); int _tmain (int argc, _tchar* argv[]) {// The basic steps are not explained, the Network Programming foundation that blog is very detailed wsadata wsadata; WSAStartup (Makeword (2,2), &wsadata); Socket Socklisten = socket (AF_INET,SOCK_STREAM,IPPROTO_TCP); Sockaddr_in addrsrv; Addrsrv.sin_addr. S_un. S_ADDR = inet_addr (SRV_IP); addrsrv.sin_family = af_inet; Addrsrv.sin_port = htons (port); Bind (Socklisten, (sockaddr*) &addrsrv,sizeof (sockaddr)); Listen (socklisten,64); DWORD dwthreadidrecv = 0; DWORD dwthreadidwrite = 0; HANDLE hand = CreateThread (null,0, WorkthreaD,NULL,0,&DWTHREADIDRECV);//process used to process the manipulation of messages if (hand = = NULL) {cout<< "Create work thread failed\n"; GetChar (); return-1; } SOCKET sockclient; Sockaddr_in addrclient; int nlenaddrclient = sizeof (SOCKADDR);//Here we use 0 for a half day to find out the error while (true) {sockclient = Accept (Socklisten, (Socka ddr*) &addrclient,&nlenaddrclient);//The third parameter must be initialized according to the addrclient size//Output connector address information//cout<<inet_ntoa (a DDRCLIENT.SIN_ADDR) << ":" <<ntohs (Addrclient.sin_port) << "has connect!" <<endl; if (sockclient! = invalid_socket) {g_client[g_nsockconn].addrclient = addrclient;//Save the connection-side address information G_client[g_nsockconn].sockclient = sockclient;//joins the connector queue g_nsockconn++; }} closesocket (Socklisten); WSACleanup (); return 0;} DWORD WINAPI workthread (lpvoid lpparameter) {fd_set fdread; int nret = 0;//record the number of bytes sent or received Timeval tv;//set timeout wait time tv.tv_sec = 1; tv.tv_usec = 0; Char buf[msgsize] = ""; while (true) {Fd_zero (&fdread); for (int i = 0;i < g_nsockconn;i++) {fd_set (g_client[i].sockclient,&fdread); }//Handle only the Read event, but there will be a read-write message sent nret = select (0,&FDREAD,NULL,NULL,&TV); if (nret = = 0) {//no connection or no read event continue; } for (int i = 0;i < g_nsockconn;i++) {if (Fd_isset (G_client[i].sockclient,&fdread)) {nret = recv (g_client[i].sockclient,buf,sizeof (BUF), 0); if (nret = = 0 | | (nret = = Socket_error && wsagetlasterror () = = Wsaeconnreset)) {cout<< "Client" <<inet_ntoa (g_client[i].addrclient.sin_addr) << "closed" <<endl; Closesocket (g_client[i].sockclient); if (I < g_nsockconn-1) {//To reject the failed sockclient, use the last one in the array to fill up G_cliEnt[i--].sockclient = g_client[--g_nsockconn].sockclient; }} else {Cout<<inet_ntoa (g_client[i].addrclient.si N_ADDR) << ":" <<endl; cout<<buf<<endl; cout<< "Server:" <<endl; Gets (BUF); strcpy (buf, "hello!"); nret = Send (G_client[i].sockclient,buf,strlen (BUF) +1,0); }}}} return 0;}
Main steps of the server:
1. Create a listener socket, bind, listen
2. Create Worker threads
3. Create a socket group to hold the client sockets for all current activities, and update the array once the connection is not received
4. Receive client connections because the Fd_size macros are not redefined and the server supports up to 64 concurrent connections. It is best to record the number of connections, do not accept the connection unconditionally
Worker threads
A worker thread is a dead loop, and the action of looping through it in turn is:
1. Add the current client socket to the Fd_read set
2. Call the Select function
3. Use Fd_isset to see when the socket is still in the reading set, if it is to receive data. If the received data length is 0, or a wsaeconnreset error occurs, the
Indicates that the client socket is actively shutting down, we want to release this socket resource, and adjust our socket string (let next fill up). There's a nret==0 judgment on it,
Just because the Select function returns immediately, the number of connections is 0 to a dead loop.
This article references: http://blog.csdn.net/rheostat/article/details/9815725
The selection (select) model of the IO model under Windows