Asynchronous socket basics: select function and FD_ZERO, FD_SET, FD_CLR, FD_ISSET

Source: Internet
Author: User

Select function:

The system provides the select function to achieve multiplexing of input/output models. Prototype:

# Include <sys/time. h>

# Include <unistd. h>

Select function:

The system provides the select function to achieve multiplexing of input/output models. Prototype:

# Include <sys/time. h>

# Include <unistd. h>

Int select (int maxfd, fd_set * rdset, fd_set * wrset, fd_set * exset, struct timeval * timeout );

The maxfd parameter is the maximum file descriptor value to be monitored plus 1. rdset, wrset, and exset correspond to the set of readable file descriptors to be detected, respectively, set of writable file descriptors and the set of abnormal file descriptors. The struct timeval structure is used to describe the length of a period of time. If no event occurs in the descriptor to be monitored during this time, the function returns and the return value is 0.

FD_ZERO, FD_SET, FD_CLR, FD_ISSET: The maxfd parameter is the maximum file descriptor value to be monitored plus 1; rdset, wrset, and exset correspond to the set of readable file descriptors to be detected, respectively, set of writable file descriptors and the set of abnormal file descriptors. The struct timeval structure is used to describe the length of a period of time. If no event occurs in the descriptor to be monitored during this time, the function returns and the return value is 0.

FD_ZERO, FD_SET, FD_CLR, FD_ISSET:

FD_ZERO (fd_set * fdset); clears the specified file descriptor set. Initialization is required before setting the file descriptor set, the result is unknown because the system usually does not clear the memory space after it is allocated.

FD_SET (fd_set * fdset) is used to add a new file descriptor to the file descriptor set.

FD_CLR (fd_set * fdset) is used to delete a file descriptor in the file descriptor set.

FD_ISSET (int fd, fd_set * fdset); used to test whether the specified file descriptor is in this set.

Struct timeval structure:

Struct timeval {

Long TV _sec; // second

Long TV _usec; // minisecond

}

Timeout settings:

Null: select is blocked until an event occurs on a file descriptor.

0: Only checks the state of the descriptor set and returns immediately without waiting for the occurrence of an external event.

Specific Time Value: If no event occurs in the specified time period, select will return timeout.

--

('Fd _ set') is a collection of file descriptors (fd. Because the length of the fd_set type varies on different platforms, a set of standard macro definitions should be used to process such variables:

Fd_set set; FD_ZERO (& set);/* clears set */FD_SET (fd, & set);/* adds fd to set */FD_CLR (fd, & set ); /* clear fd from set */FD_ISSET (fd, & set);/* If fd is true in set */

In the past, an fd_set usually only contains less than or equal to 32 file descriptors, because fd_set actually uses only one int bit vector. In most cases, checking that fd_set can include any value of the file descriptor is the responsibility of the system, but determining how much your fd_set can put sometimes you should check/modify the value of the macro FD_SETSIZE. * This value is related to the system. * Check the man manual of select () in your system. Some systems have problems with support for more than 1024 file descriptors.

Multiplexing is a practical server program. A non-multiplexing network program can only serve as a learning or testing partner. I will talk about this article

Used multiplexing functions: select/poll/epoll/port. The * nix System of kqueue has never been used. I guess I am familiar with the above.

Four, kqueue just needs to be familiar with it.

I. select model

Select prototype: int select (int n, fd_set * readfds, fd_set * writefds, fd_set * limit TFDs, struct timeval * timeout );

The parameter n indicates the maximum value + 1 of all fd monitored.

The four macros closely integrated with the select model do not have an explanation:

FD_CLR (int fd, fd_set * set );

FD_ISSET (int fd, fd_set * set );

FD_SET (int fd, fd_set * set );

FD_ZERO (fd_set * set );

The key to understanding the select model is to understand fd_set. For convenience, the length of fd_set is 1 byte. Each bit in fd_set can correspond to a file descriptor fd. The fd_set with a length of 1 byte can correspond to a maximum of 8 fd.

(1) execute fd_set set; FD_ZERO (& set); then set uses bits to indicate that it is 00.

(2) If fd = 5, execute FD_SET (fd, & set); then set to 0001,0000 (5th position is 1)

(3) If fd = 2 or fd = 1 is added, set Becomes 0001,0011.

(4) execute select (6, & set, 0, 0) to block the wait

(5) If both fd = 1 and fd = 2 have readable events, select returns, and set changes. Note: fd = 5 where no event occurs is cleared.

Based on the above discussion, we can easily draw the features of the select model:

(1) the number of monitored file descriptors depends on the value of sizeof (fd_set. Sizeof (fd_set) = 512 on my server. Each bit represents a file descriptor. The maximum file descriptor supported on my server is 512x8 = 4096. It is said to be adjustable. It is also said that although it is adjustable, the adjustment ceiling is determined by the variable value during kernel compilation. I am not very interested in adjusting the size of fd_set, refer to the Model in http://www.cppblog.com/cpp1_e/archive/2008/03/21/45061 .html 2 (1) can effectively break through the select can be monitored file descriptor limits.

(2) When fd is added to the select monitoring set, another data structure array must be used to store fd in the select monitoring set. The first is used to return the result after the select statement, array is used as the source data and fd_set for FD_ISSET judgment. Second, after the select statement is returned, the previously added but no event occurs in fd will be cleared, and the fd will be re-obtained from the array one by one before each start of the select statement (FD_ZERO first ), scans the array and obtains the maximum fd value maxfd, which is used as the first parameter of select.

(3) it can be seen that the select model must loop array (add fd, take maxfd) before select, And Then loop array (FD_ISSET to determine whether a time has occurred) After select returns ).

The following is a pseudo code that describes the server model of the basic select model:

Array [slect_len];

NSock = 0;

Array [nSock ++] = listen_fd; (previously, the listen port was bound and listen)

Maxfd = listen_fd;

While {

FD_ZERO (& set );

Foreach (fd in array)

{

If fd is greater than maxfd, maxfd = fd

FD_SET (fd, & set)

}

Res = select (maxfd + 1, & set, 0, 0 );

If (FD_ISSET (listen_fd, & set ))

{

Newfd = accept (listen_fd );

Array [nsock ++] = newfd;

If (-- res <= 0) continue

}

Foreach subscript 1 (fd in array)

{

If (FD_ISSET (fd, & tyle = "COLOR: # ff0000"> set ))

Perform read and other operations

If it is incorrect or disabled, delete the fd and swap the corresponding position in the array with the last element. nsock minus one.

If (-- res <= 0) continue

}

}

 

 

 

Server code:

Reference

# Include <sys/types. h>

# Include <sys/socket. h>

# Include <stdio. h>

# Include <netinet/in. h>

# Include <sys/time. h>

# Include <sys/ioctl. h>

# Include <unistd. h>

# Include <stdlib. h>

Int main ()

{

Int server_sockfd, client_sockfd;

Int server_len, client_len;

Struct sockaddr_in server_address;

Struct sockaddr_in client_address;

Int result;

Fd_set readfds, testfds;

/* Create a socket: IPv4 and tcp streaming socket */

Server_sockfd = socket (AF_INET, SOCK_STREAM, 0 );

Server_address.sin_family = AF_INET;

/* INADDR_ANY indicates the IP address of the Local Machine. htonl converts the IP address to the network byte sequence (large-end mode )*/

Server_address.sin_addr.s_addr = htonl (INADDR_ANY );

Server_address.sin_port = htons (9734 );

Server_len = sizeof (server_address );

/* Bind the port to the socket */

Bind (server_sockfd, (struct sockaddr *) & server_address, server_len );

/* Listen. Five connection requests are allowed */

Listen (server_sockfd, 5 );

FD_ZERO (& readfds );

FD_SET (server_sockfd, & readfds );

/* Wait for the client request */

While (1 ){

Char ch;

Int fd;

Int nread;

Testfds = readfds;

/* The server waits for the client request (server blocking) After select )*/

Printf ("server waiting/n ");

Result = select (FD_SETSIZE, & testfds, (fd_set *) 0,

(Fd_set *) 0, (struct timeval *) 0 );

If (result <1 ){

Perror ("server ");

Exit (1 );

}

/* Polling. The actual program does not use this extremely time-consuming Method */

For (fd = 0; fd <FD_SETSIZE; fd ++ ){

If (FD_ISSET (fd, & testfds )){

If (fd = server_sockfd ){

Client_len = sizeof (client_address );

Client_sockfd = accept (server_sockfd, (struct sockaddr *) & client_address,

& Client_len);/* receives client connection requests and returns the connection socket used to send and receive data */

FD_SET (client_sockfd, & readfds);/* You need to monitor the client sending the request */

Printf ("adding client on fd % d/n", client_sockfd );

} Else {/* "status" of the client "*/

Ioctl (fd, FIONREAD, & nread );

If (nread = 0 ){

Close (fd);/* close the connection socket with the client if no content is read */

FD_CLR (fd, & readfds);/* clear the client socket Descriptor and no longer "follow "*/

Printf ("removing client on fd % d/n", fd );

} Else {

Read (fd, & ch, 1 );

Sleep (5 );

Printf ("serving client on fd % d/n", fd );

Ch ++;

Write (fd, & ch, 1 );

}

}

}

}

}

}

 

 

 

Example 2

# Include <stdio. h>

# Include <stdlib. h>

# Include <unistd. h>

# Include <errno. h>

# Include <string. h>

# Include <sys/types. h>

# Include <sys/socket. h>

# Include <netinet/in. h>

# Include <arpa/inet. h>

# Define MYPORT 1234 // the port users will be ing

# Define BACKLOG 5 // how many pending connections queue will hold

# Define BUF_SIZE 200

Int fd_A [BACKLOG]; // accepted connection fd

Int conn_amount; // current connection amount

Void showclient ()

{

Int I;

Printf ("client amount: % d/n", conn_amount );

For (I = 0; I <BACKLOG; I ++)

{

Printf ("[% d]: % d", I, fd_A [I]);

}

Printf ("/n ");

}

Int main (void)

{

Int sock_fd, new_fd; // listen on sock_fd, new connection on new_fd

Struct sockaddr_in server_addr; // server address information

Struct sockaddr_in client_addr; // connector's address information

Socklen_t sin_size;

Int yes = 1;

Char buf [BUF_SIZE];

Int ret;

Int I;

If (sock_fd = socket (AF_INET, SOCK_STREAM, 0) =-1)

{

Perror ("socket ");

Exit (1 );

}

If (setsockopt (sock_fd, SOL_SOCKET, SO_REUSEADDR, & yes, sizeof (int) =-1)

{

Perror ("setsockopt ");

Exit (1 );

}

Server_addr.sin_family = AF_INET; // host byte order

Server_addr.sin_port = htons (MYPORT); // short, network byte order

Server_addr.sin_addr.s_addr = INADDR_ANY; // automatically fill with my IP

Memset (server_addr.sin_zero, '/0', sizeof (server_addr.sin_zero ));

If (bind (sock_fd, (struct sockaddr *) & server_addr, sizeof (server_addr) =-1)

{

Perror ("bind ");

Exit (1 );

}

If (listen (sock_fd, BACKLOG) =-1)

{

Perror ("listen ");

Exit (1 );

}

Printf ("listen port % d/n", MYPORT );

Fd_set fdsr;

Int maxsock;

Struct timeval TV;

Conn_amount = 0;

Sin_size = sizeof (client_addr );

Maxsock = sock_fd;

While (1)

{

// Initialize file descriptor set

FD_ZERO (& fdsr );

FD_SET (sock_fd, & fdsr );

// Timeout setting

TV. TV _sec = 30;

TV. TV _usec = 0;

// Add active connection to fd set

For (I = 0; I <BACKLOG; I ++)

{

If (fd_A [I]! = 0)

{

FD_SET (fd_A [I], & fdsr );

}

}

 

 

 

Ret = select (maxsock + 1, & fdsr, NULL, NULL, & TV );

If (ret <0)

{

Perror ("select ");

Break;

} Else if (ret = 0)

{

Printf ("timeout/n ");

Continue;

}

// Check every fd in the set

For (I = 0; I <conn_amount; I ++)

{

If (FD_ISSET (fd_A [I], & fdsr ))

{

Ret = recv (fd_A [I], buf, sizeof (buf), 0 );

If (ret <= 0)

{// Client close

Printf ("client [% d] close/n", I );

Close (fd_A [I]);

FD_CLR (fd_A [I], & fdsr );

Fd_A [I] = 0;

}

Else

{// Receive data

If (ret <BUF_SIZE)

Memset (& buf [ret], '/0', 1 );

Printf ("client [% d] send: % s/n", I, buf );

}

}

}

// Check whether a new connection comes

If (FD_ISSET (sock_fd, & fdsr ))

{

New_fd = accept (sock_fd, (struct sockaddr *) & client_addr, & sin_size );

If (new_fd <= 0)

{

Perror ("accept ");

Continue;

}

// Add to fd queue

If (conn_amount <BACKLOG)

{

Fd_A [conn_amount ++] = new_fd;

Printf ("new connection client [% d] % s: % d/n", conn_amount,

Inet_ntoa (client_addr.sin_addr), ntohs (client_addr.sin_port ));

If (new_fd> maxsock)

Maxsock = new_fd;

}

Else

{

Printf ("max connections arrive, exit/n ");

Send (new_fd, "bye", 4, 0 );

Close (new_fd );

Break;

}

}

Showclient ();

}

// Close other connections

For (I = 0; I <BACKLOG; I ++)

{

If (fd_A [I]! = 0)

{

Close (fd_A [I]);

}

}

Exit (0 );

}

 

Reprinted statement:This article from http://doc.chinaunix.net/linux/201007/713872.shtml

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.