//----------------------------------------------------
//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