select 在socket通信中的应用

//----------------------------------------------------

//AUTHOR: lanyang123456

//DATE: 2014-10-12

//----------------------------------------------------



代码实例如下:



/*
TCP
server_v2.0
use select


API
inet_aton()
inet_ntoa()

*/

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>


#define LENGTH_OF_LISTEN_QUEUE	20
#define SERVER_PORT	6666
#define MAXLINE 4096
#define MAX_FD_NUM	2

int main(int argc, char** argv)
{
	int    listenfd, connfd;
	struct sockaddr_in	servaddr;
	struct sockaddr_in	client_addr;
	socklen_t client_addr_len = sizeof(client_addr);
	char    recv_buff[4096]; 
	char    response[] = "recv well done.";
	int     recv_len;
	fd_set readfd;
	int	ret;
	int	fdset[MAX_FD_NUM] = {-1, -1};
	int	max_fd;
	int	i;

	if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1 ) {
    		printf("create socket error: %s(errno: %d)\n",strerror(errno),errno);
    		exit(0);
	}
	fdset[0] = listenfd;
	max_fd = listenfd;

	memset(&servaddr, 0, sizeof(servaddr));
	servaddr.sin_family = AF_INET;
	servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
	servaddr.sin_port = htons(SERVER_PORT);

	if (bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) == -1) {
    		printf("bind socket error: %s(errno: %d)\n",strerror(errno),errno);
    		exit(0);
	}

	if (listen(listenfd, LENGTH_OF_LISTEN_QUEUE) == -1) {
    		printf("listen socket error: %s(errno: %d)\n",strerror(errno),errno);
    		exit(0);
    	}

	printf("----------waiting for client's request---------\n");
	while (1) {

        	/*每次调用select前,都要重置监听的描述符*/  
		FD_ZERO(&readfd);
		for (i=0; i < MAX_FD_NUM; i++) {
			if (fdset[i] != -1) {
				FD_SET(fdset[i], &readfd);
			}	
		}

		ret = select(max_fd + 1, &readfd, NULL, NULL, NULL);//有数据时才返回
        	if (ret == -1) {  //错误情况
			if (errno == EINTR) {//signal interrupt
				continue;
			}
			else {
				perror("select error");
				exit(0);
			}
		}
        	else if (ret) {    //返回值大于0 有数据到来
            		if (FD_ISSET(listenfd, &readfd))
            		{
				if((connfd = accept(listenfd, (struct sockaddr *)&client_addr, &client_addr_len)) == -1) {
        				printf("accept socket error: %s(errno: %d)\n",strerror(errno),errno);
        				continue;
    				}
				printf("accept a new  connection from client: %s\n", inet_ntoa(client_addr.sin_addr));
				fdset[1] = connfd;
				max_fd = connfd;
            		} else if (FD_ISSET(connfd, &readfd)) {

				memset(recv_buff, 0, MAXLINE);
    				recv_len = recv(connfd, recv_buff, MAXLINE - 1, 0);
				if (recv_len <= 0) {
					printf("recv socket error: %s(errno: %d)\n",strerror(errno),errno);
					close(connfd);
					continue;
				}
    				recv_buff[recv_len] = '\0';
    				printf("recv msg %d byte from client: %s\n", recv_len, recv_buff);

    				if (send(connfd, response, strlen(response), 0) < 0) {
    					printf("send socket error: %s(errno: %d)\n", strerror(errno), errno);
    					close(connfd);
					continue;
    				}

    				//close(connfd);
				//fdset[1] = -1;
				//max_fd = listenfd;

			}
			
		}
        	else    //ret 为0,超时情况
        	{
            		printf("time out\n");
			//close(keybd_fd);//产生异常,查看结果
        	}

	}

	close(listenfd);
	exit(0);
}


client 端可参考

http://blog.csdn.net/lanyang123456/article/details/40024327


注意的地方:

当client connect 成功建立,然后关闭sockfd。此时server端已成功接到客户端的连接,处于select阻塞状态,当客户端关闭连接时,select监控的描述符会有数据到来,select返回, 接着会调用recv, 并且recv立刻返回,返回值为0.也就是说客户端断开连接,select有事件发生,recv会立刻返回。





参考

http://blog.csdn.net/dlutbrucezhang/article/details/8577810

http://blog.csdn.net/microtong/article/details/4989902

http://blog.csdn.net/klarclm/article/details/8825930

http://www.oschina.net/code/snippet_97047_675


你可能感兴趣的:(select 在socket通信中的应用)