Socket Programming Select ()

Source: Internet
Author: User

Select is also important in socket programming, and it is able to monitor the changes in the file descriptors we need to monitor-read-write or exceptions.
The function format of select (The Berkeley socket Programming under UNIX system, and the slightly different under Windows, embodies two aspects: one is the first parameter of the Select function, can be ignored under Windows, but must be set to maximum file description under Linux multibyte 1 The second is that structural fd_set are defined differently in both systems):

int Select(intMaxfdp,fd_set *readfds,fd_set *writefds,fd_set *errorfds,structTimeval *timeout); /*The argument list int MAXFDP is an integer value that refers to the range of all file descriptors in the collection, that is, the maximum value of all file descriptors plus 1, not wrong!   The value of this parameter in Windows does not matter and can be set incorrectly. Fd_set *readfds is a pointer to the FD_SET structure, which should include the file descriptor, we want to monitor the read changes of these file descriptors, that is, we care whether the data can be read from these files, if there is a file in this collection is readable, Select returns a value greater than 0, indicating that the file is readable, and if there is no readable file, the timeout parameter is used to determine whether to time out, and if timeout is exceeded, select returns 0 if an error returns a negative value.   You can pass in a null value to indicate that you do not care about any file read changes. Fd_set *writefds is a pointer to the FD_SET structure, which should include the file descriptor, we want to monitor the write changes of these file descriptors, that is, we care about whether the data can be written to these files, if there is a file in this collection can be written, Select returns a value greater than 0, indicating that a file is writable, and if there is no writable file, the timeout parameter is used to determine whether to time out, and if timeout is exceeded, select returns 0 if an error returns a negative value.   You can pass in a null value to indicate that you do not care about any file write changes.   Fd_set *errorfds with the above two parameters to monitor file error exceptions. The struct timeval* timeout is the time-out for Select, which is critical, which allows the select to be in three states: first, if NULL is passed in as a parameter, that is, the time structure is not passed in, the select is put in a blocking state. Be sure to wait until one of the file descriptors in the monitor file descriptor collection changes; second, if the time value is set to 0 seconds 0 milliseconds, it becomes a purely non-blocking function, regardless of whether the file descriptor is changed, immediately return to continue execution, the file has no change return 0, there is a change to return a positive value; Timeout value is greater than 0, this is the waiting time-out period, that is, select in timeout time block, the timeout period has the arrival of the event to return, otherwise after the timeout, anyway must return, the return value with the above. *//*return Values: Negative value: Select Error positive value: Some files can be read or write or error 0: Wait timeout, no writable or incorrect files*/

describes two structures:

First, the struct fd_set can be understood as a collection, this collection is stored in the file descriptor (descriptor), that is, the file handle, this can be what we call the ordinary meaning of the file, of course, UNIX under any Device, pipeline, FIFO, etc. are file forms, All included, so there is no doubt that a socket is a file, and the socket handle is a file descriptor. The Fd_set collection can be manipulated by some macros, such as emptying the set Fd_zero (Fd_set *), adding a given file descriptor to the collection fd_set (int, fd_set *), removing a given file descriptor from the collection fd_clr (int, fd_set*), checks whether the specified file descriptor in the collection can read and write Fd_isset (int, fd_set*). A moment to illustrate.
Second, struct timeval is a common structure that is used to represent time values, have two members, one is seconds, the other is the number of milliseconds.

After you have a select, you can write a decent network program! As a simple example, the acceptance of data from the network is written to a file.

#ifndef _socket_thread_server_h_#define_socket_thread_server_h_#include<iostream>#include<windows.h>#include<winsock.h>#pragmaComment (lib, "Wsock32.lib")#definePORT 4111#defineMsgsize 1024intG_itotalconn =0; SOCKET G_clisocketarr[fd_setsize];D word WINAPI workerthread (lpvoid lpparameter);intMain () {wsadata wsadata;    SOCKET Slisten, sclient;    Sockaddr_in local, client; intIaddrsize =sizeof(sockaddr_in);    DWORD dwThreadID; //Initialize Windows Socket LibraryWSAStartup (0x0202, &wsadata); //Create Listening Socket//Slisten = socket (af_inet, sock_stream, ipproto_tcp);Slisten = socket (af_inet, Sock_stream,0); if(Slisten = =invalid_socket) {Std::cout<<"socket () fail!"<<Std::endl;        WSACleanup (); return 0; }    //Bind//local.sin_addr. S_un. S_ADDR = htonl (inaddr_any);LOCAL.SIN_ADDR.S_ADDR =htonl (Inaddr_any); Local.sin_family=af_inet; Local.sin_port=htons (PORT); if(Bind (Slisten, (structSOCKADDR *) &local,sizeof(sockaddr_in)) <0) {Std::cout<<"Bind fail!"<<Std::endl;        Closesocket (Slisten);        WSACleanup (); return 0; }    //Listen    if(Listen (Slisten,3) == -1) {Std::cout<<"Listen fail!"<<Std::endl;        Closesocket (Slisten);        WSACleanup (); return 0; }    //Create worker ThreadCreateThread (NULL,0, Workerthread, NULL,0, &dwThreadID);  while(TRUE) {//Accept a connection        if(sclient = Accept (Slisten, (structSOCKADDR *) &client, &iaddrsize) = =socket_error) {            //std::cout << "Accept fail!" << Std::endl;            Continue; } printf ("Accepted client:%s:%d\n", Inet_ntoa (CLIENT.SIN_ADDR), Ntohs (Client.sin_port)); //ADD socket to G_clisocketarr        if(G_itotalconn <fd_setsize) {G_clisocketarr[g_itotalconn++] =sclient; }    }    return 0;} DWORD WINAPI workerthread (lpvoid lpparam) {inti;    Fd_set Fdread; intret; structTimeval TV = {1,0 }; CharSzmessage[msgsize];  while(TRUE) {Fd_zero (&fdread);  for(i =0; i < G_itotalconn; i++) {fd_set (g_clisocketarr[i],&fdread); }                     //We only Care Read EventRET =Select(0, &fdread, NULL, NULL, &TV); if(ret = =0)        {       //Time expired            Continue; }         for(i =0; i < G_itotalconn; i++)        {            if(Fd_isset (g_clisocketarr[i), &fdread)) {         //A Read event happened on G_clisocketarrret = recv (G_clisocketarr[i], szmessage, Msgsize,0); if(ret = =0|| (ret = = Socket_error && wsagetlasterror () = =wsaeconnreset)) {                    //Client Socket closedprintf"Client Socket%d closed.\n", G_clisocketarr[i]);                    Closesocket (G_clisocketarr[i]); //Move the last socket in the array to the current position                    if(I < g_itotalconn-1) {G_clisocketarr[i--] = g_clisocketarr[--G_itotalconn]; }                    Else{G_clisocketarr[i]=0; --G_itotalconn; }                }                Else                {                    //We received a message from clientSzmessage[ret] =' /'; printf ("Client say%s", Szmessage); Send (G_clisocketarr[i], szmessage, strlen (szmessage),0); }            } //if}// for}// while    return 0;}#endif

Several main actions of the server are as follows:
1. Create a listener socket, bind, listen;
2. Create worker threads;
3. Create a socket string that holds the client sockets for all current activities, updating the array each time a connection is received;
4. Accept the client connection.
One thing to note here is that I did not redefine the Fd_setsize macro, so the maximum number of concurrent connections supported by the server is 64. Moreover, there is no unconditional acceptance, and the server should decide whether to accept connections from a client based on the current number of connections. A better implementation is to use the Wsaaccept function, and let Wsaaccept callback itself to implement the condition function.


As shown below:

 int  CALLBACK conditionfunc (lpwsabuf lpcallerid,lpwsabuf Lpcallerdata, Lpqos lpsqos,lpqos lpgqos,lpwsabuf Lpcalleeid, lpwsabuf lpcalleedata,group far * G,DWORD Dwcallbackdata) { if  (current number of connections < fd_   SETSIZE)  return   cf_accept;  else  return   Cf_reject; }

A worker thread is a dead loop, and a loop completes the action:
1. Add all current client sockets to the read set Fdread;
2. Call the Select function;
3. See if a socket is still in the read set, and if so, receive data. If the received data length is 0, or a wsaeconnreset error occurs, the client socket is actively shut down, it is necessary to release the resources that are bound to the corresponding socket in the server, and then adjust our socket group (move the last socket in the array to the current position).
In addition to having to conditionally accept the client's connection, special handling is required in the case of 0 connections, because if there are no sockets in the read set, the Select function returns immediately, which causes the worker thread to become a dead loop without a pause, and the CPU's occupancy rate reaches 100% immediately.
The operation that relates to the socket list needs to use a loop, which needs to be traversed at polling time, and then a new round starts, and the list is added to the queue again. That is, one of the reasons why select needs to traverse at least 2 lists at the time of work is that it is less efficient.
The IOCP or Epoll model is recommended for large-scale network connectivity. But the select model can be used in games like StarCraft, for example, because it is small and easy to implement, and the network connection of PvP games is not large. For a select model that wants to break through Windows 64 limits, you can take a segmented poll and poll 64 at a time. For example, the socket list is 128, and on the first polling, the first 64 are placed in a queue with select for state queries. After this operation is all over. The next 64 are added to the polling queue for polling processing. This processing needs to work non-blocking. And so on, select can support an unlimited number of.

Socket Programming Select ()

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.