Limitations of Select
Concurrent servers implemented with select, the number of concurrency that can be reached is generally limited by two ways:
1) The maximum file descriptor limit that a process can open. This can be done by adjusting the kernel parameters. You can adjust or use the setrlimit function setting by ulimit-n (number) , but the maximum size that a system can open is limited, and is related to the amount of memory, which can be cat/proc/sys/fs/ File-max View
/** Example: Getrlimit/setrlimit gets/sets the number of open files for a process **/int main () { struct rlimit rl; if (Getrlimit (rlimit_nofile, &rl) = =-1) err_exit ("Getrlimit error"); cout << "Soft limit:" << rl.rlim_cur << Endl; cout << "Hard limit:" << rl.rlim_max << Endl; cout << "------------------------->" << endl; Rl.rlim_cur = 2048; Rl.rlim_max = 2048; if (Setrlimit (rlimit_nofile, &rl) = =-1) err_exit ("Setrlimit error"); if (Getrlimit (rlimit_nofile, &rl) = =-1) err_exit ("Getrlimit error"); cout << "Soft limit:" << rl.rlim_cur << Endl; cout << "Hard limit:" << rl.rlim_max << Endl;}
2) The limit of the Fd_set collection capacity in select (fd_setsize,1024), which requires recompiling the kernel to change.
/** test: The maximum number of connection server-side full source code to be established by the test server is as follows (note using the TCPServer class implementation > in <socket Programming Practice (7):* */int Main () {signal (sigpipe, Sighandlerforsigpipe); try {tcpserver server (8001); int listenfd = SERVER.GETFD (); struct sockaddr_in clientaddr; Socklen_t Addrlen; int maxfd = LISTENFD; Fd_set RSet; Fd_set Allset; Fd_zero (&rset); Fd_zero (&allset); Fd_set (LISTENFD, &allset); Used to save the connected client socket int Client[fd_setsize]; for (int i = 0; i < fd_setsize; ++i) client[i] = 1; int maxi = 0; Used to hold the largest non-idle position for the Select to return after iterating over the array int count = 0; while (true) {rset = Allset; int nready = SELECT (maxfd+1, &rset, NULL, NULL, NULL); if (Nready = =-1) {if (errno = = eintr) continue; Err_exit ("select Error"); } if (Fd_isset (LISTENFD, &rset)) { Addrlen = sizeof (CLIENTADDR); int CONNFD = Accept (LISTENFD, (struct sockaddr *) &clientaddr, &addrlen); if (CONNFD = =-1) err_exit ("Accept error"); int i; for (i = 0; i < fd_setsize; ++i) {if (Client[i] < 0) { Client[i] = CONNFD; if (i > Maxi) maxi = i; Break }} if (i = = fd_setsize) {Cerr << "too many clients "<< Endl; Exit (Exit_failure); }//Print client IP address and port number cout << "Client information:" << Inet_ntoa (clientaddr.sin_addr << "," << Ntohs (clientaddr.sin_port) << Endl; cout << "Count =" << ++count<< Endl; Put the connection socket interface into Allset and update the MAXFD fd_set (CONNFD, &allset); if (Connfd > maxfd) maxfd = CONNFD; if (--nready <= 0) continue; }/** if it is a connected socket interface, a readable event occurs **/for (int i = 0; I <= maxi; ++i) if ((client[i]! =-1) &am p;& Fd_isset (Client[i], &rset)) {char buf[512] = {0}; int readbytes = ReadLine (Client[i], buf, sizeof (BUF)); if (readbytes = =-1) err_exit ("ReadLine error"); else if (readbytes = = 0) {cerr << "client connect closed ..." << end L FD_CLR (Client[i], &allset); Close (Client[i]); Client[i] =-1; } cout << buf; if (writEn (Client[i], buf, readbytes) = =-1) err_exit ("writen error"); if (--nready <= 0) break; }}} catch (const socketexception &e) {cerr << e.what () << Endl; Err_exit ("TCPServer error"); }}
/** High concurrency test-side code: Contest full source code is as follows **/int Main () {//Best not modify: Otherwise it will produce a segment overflow (stack-overflow)//struct Rlimit rlim;//RLIM.RLIM_CU r = 2048;//Rlim.rlim_max = 2048;//if (Setrlimit (rlimit_nofile, &rlim) = =-1)//Err_exit ("Setrlimit Erro R "); int count = 0; while (true) {int sockfd = socket (af_inet, sock_stream, 0); if (SOCKFD = =-1) {sleep (5); Err_exit ("socket error"); } struct sockaddr_in serveraddr; serveraddr.sin_family = af_inet; Serveraddr.sin_port = htons (8001); SERVERADDR.SIN_ADDR.S_ADDR = inet_addr ("127.0.0.1"); int ret = Connect_timeout (SOCKFD, &SERVERADDR, 5); if (ret = =-1 && errno = = etimedout) {cerr << "timeout ..." << Endl; Err_exit ("Connect_timeout error"); } else if (ret = =-1) err_exit ("Connect_timeout error"); Acquiring and printing peer-to-peer information struct sockaddr_in peeraddr; socklen_t PEErLen = sizeof (PEERADDR); if (Getpeername (SOCKFD, (struct sockaddr *) &peeraddr, &peerlen) = =-1) err_exit ("Getpeername"); cout << "Server information:" << Inet_ntoa (peeraddr.sin_addr) << "," << Ntohs (Peera Ddr.sin_port) << Endl; cout << "Count =" << ++count << Endl; }}
Server-side operation:
Resolution: For clients, you can only open up to 1021 connection sockets, as a total of up to 1024 file descriptions in Linux, such as, where you have to remove 0,1,2. The server side can only accept return 1020 connected sockets, because in addition to 0,1,2 there is a listener socket LISTENFD, a client socket (not necessarily the last one) although the connection has been established, in the completed connection queue, However, when accept returns, it reaches the maximum descriptor limit, returns an error, and prints the prompt message.
The client in the socket () returns 1 is the call to sleep (5) parsing
When the client calls the socket to create a 1022th socket, as shown above will also prompt an error, when the socket function returns 1 error, if there is no sleep 4s and then quit the process what is the problem? If you exit the process directly, all the sockets opened by the client are closed off, that is, a lot of fin segments are sent to the server, and perhaps the server is still receiving the connected sockets from the connected queue, where the server side is concerned with the readable events of the listening sockets. Also began to care about the readable event of a socket that was already connected, read returns 0, so there will be a lot of client close fields that are mixed in the output of the entry, and the problem is that because read returns 0, the server side will shut off its own connected sockets. Then maybe just said that a client connection will be accepted to return, that is, the test does not show the server side of the true concurrency capacity;
Poll Call
Poll does not have a select second limit, that is, the fd_setsize limit, but the first limit is unavoidable for the time being;
#include <poll.h>int poll (struct POLLFD *fds, nfds_t nfds, int timeout);
Parameter Nfds: The number of events to be detected, the size of the structure array (also represented as the number of file descriptors) (the caller should specify the value of the items in the FDS array in Nfds.)
Parameter timeout: Time-out (in milliseconds, milliseconds), or 1, indicating never time-out.
POLLFD structure struct pollfd{ int fd; /* File descriptor */short events; /* Requested events: Requested event */short revents; /* Returned events: event returned */};
Events and Revents values (top 3 most commonly used):
return value:
Success: Returns a positive integer (this is the number of structures which has nonzero revents
Fields (in other words, those descriptors with events or errors reported).
Timeout: returns 0 (A value of 0 indicates the call timed out and no file descriptors
were ready)
failed: Return-1 (on error, -1 is returned, and errno is set appropriately.)
/**poll-server example (the previous Select-server is modified as follows, there is no fd_setsize limit, about the first limit can be changed using the method in the previous article) (Client and test-side code, such as the former) **/const int SETSIZE = 2048;int Main () {signal (sigpipe, sighandlerforsigpipe); try {tcpserver server (8001); Used to save a connected client socket struct POLLFD client[setsize]; Leave the client blank for (int i = 0; i < SETSIZE; ++i) client[i].fd = 1; int maxi = 0; Used to save the largest occupied position int count = 0; CLIENT[0].FD = Server.getfd (); Client[0].events = Pollin; while (true) {int nready = poll (client, maxi+1,-1); if (Nready = =-1) {if (errno = = eintr) continue; Err_exit ("poll error"); }//If the listener interface has a readable event (Client[0].revents & pollin) {int CONNFD = ACC EPT (SERVER.GETFD (), NULL, NULL); if (CONNFD = =-1) err_exit ("Accept error"); BOOL Flags = false; Skip CLIENT[0].FD (LISTENFD), starting from 1 to detect for (int i = 1; i < SETSIZE; ++i) { if (CLIENT[I].FD = =-1) {client[i].fd = CONNFD; Client[i].events = Pollin; Flags = TRUE; if (i > Maxi) maxi = i; Break }}//did not find a suitable location if (!flags) {Cerr << ; "Too Many clients" << Endl; Exit (Exit_failure); } cout << "Count =" << ++count << Endl; if (--nready <= 0) continue; }/** if it is a connected socket interface, a readable event occurs **/for (int i = 1; I <= maxi; ++i) if (client[i].revents &am P Pollin) {char buf[512] = {0}; int readbytes = ReadLine (CLIENT[I].FD, buf, sizeof (BUF)); if (readbytes = =-1) err_exit ("ReadLine error"); else if (readbytes = = 0) {cerr << "client connect closed ..." << end L Close (CLIENT[I].FD); CLIENT[I].FD =-1; } cout << buf; if (writen (CLIENT[I].FD, buf, readbytes) = =-1) err_exit ("writen error"); if (--nready <= 0) break; }}} catch (const socketexception &e) {cerr << e.what () << Endl; Err_exit ("TCPServer error"); }}
Attached-getrlimit and Setrlimit functions
Each process has a set of resource constraints, some of which can be queried and changed with the Getrlimit and Setrlimit functions.
#include <sys/time.h> #include <sys/resource.h>int getrlimit (int resource, struct rlimit *rlim); int Setrlimit (int resource, const struct RLIMIT *rlim);
Rlimit structure struct rlimit{ rlim_t rlim_cur; /* Soft Limit */ rlim_t Rlim_max; /* Hard limit (ceiling for rlim_cur) */};
The soft limit is a recommended, best not to exceed the limit, if beyond, the system may send a signal to the process to terminate its operation.
And the hard limit is generally the upper limit of soft limit;
Resource Available values |
Rlimit_as |
The maximum amount of virtual memory space available to a process, including stacks, global variables, dynamic memory |
Rlimit_core |
Maximum size of core files generated by the kernel |
Rlimit_cpu |
The total CPU time used, measured in seconds |
Rlimit_data |
Process data segment (Initialize data segment, non-initialized BSS segment and heap) limit (in units of B) |
Rlimit_fsize |
File Size Limits |
Rlimit_sigpending |
Limit of number of signals a user can suspend |
Rlimit_nofile |
Maximum number of open files |
Rlimit_nproc |
Limits on the number of processes users can create |
Rlimit_stack |
Process stack memory limit, exceeding will produce SIGSEGV signal |
The resource limits of a process are usually established by the 0# process at the beginning of the system, and the following three rules apply when changing resource limits:
1. Any process can change a soft limit to less than or equal to its hard limit.
2. Any process can reduce its hard limit value, but it must be greater than or equal to its soft limit value. This reduction is not antagonistic to ordinary users.
3. Only super users can increase the hard limit.
Socket Programming Practice (--select) limitations and the use of poll