一、相关函数
1. int select(int maxfdp,fd_set *readset,fd_set *writeset,fd_set *exceptset,struct timeval *timeout);
int maxfdp: 该参数是指集合中所有文件描述符的范围, 即所有文件描述符的最大值加1;
fd_set *readset: 该参数是我们所关心的文件是否可读的文件描述符的集合, 如果这个集合中有个文件可读了,那select返回一个大于0的数,表示有文件可读了
fd_set *writeset:......可写......
fd_set *exceptset: ......异常发生......
timeval *timeout:该参数是select的超时参数,这个参数使select处于三种状态:(1)timeout传入NULL,则select一直等到文件状态有变化时才返回,这段时间一直处于阻塞状态。(2):timeout 传入0,则select会立即返回(非阻塞),如果文件状态有变化则返回一个大于0的值没有变化则返回0;(3)timeout传入一个大于0的数,则select在timeout时间内阻塞,一旦文件状态有变化就会返回,超时后不管怎样都会返回值同样是文件状态右边话就返回一个大于0的值,无变化则返回0;
timeval的结构:
struct timeval{ long tv_sec; /*秒 */ long tv_usec; 微秒 */ }
select返回一个小于0的数则说明出错。
2.fd_set
fd_set类型变量每一位代表了一个描述符。我们也可以认为它只是一个由很多二进制位构成的数组,如下图所示:
操作fd_set的宏有:
#include <sys/select.h> int FD_ZERO(int fd,fd_set *fdset); int FD_CLR(int FD_SET(fd_set); int FD_ISSET(文件描述符集后,必须用FD_ZERO将所有位置零。之后将我们所感兴趣的描述符所对应的位置位
二、TCP服务端代码
#include <string.h> #include <stdio.h> #include <stdlib.h> #include <netinet/in.h> #include <arpa/inet.h> #include <ctype.h> #include "wrap.h" #define MAXLINE 80 #define SERV_PORT 8001 int main(int argc,char **argv) { int i,maxi,maxfd,listenfd,connfd,sockfd; nready,client[FD_SETSIZE]; ssize_t n; fd_set rset,allset; char buf[MAXLINE]; str[INET_ADDRSTRLEN]; socklen_t cliaddr_len; sockaddr_in cliaddr,servaddr; listenfd = Socket(AF_INET,SOCK_STREAM,0); bzero(&servaddr,1)">sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl(INADDR_ANY); servaddr.sin_port = htons(SERV_PORT); Bind(listenfd,(struct sockaddr *)&servaddr,1)">(servaddr)); Listen(listenfd,20); maxfd = listenfd; maxi = -1; for (i = 0; i < FD_SETSIZE; i++) client[i] = -1; -1 indicates available entry FD_ZERO(&allset); FD_SET(listenfd,&allset); for ( ; ; ) { rset = allset; structure assignment nready = select(maxfd+1,&rset,NULL,NULL); if (nready < ) perr_exit(select error"); if (FD_ISSET(listenfd,&rset)) { new client connection cliaddr_len = (cliaddr); connfd = Accept(listenfd,(struct sockaddr *)&cliaddr,1)">cliaddr_len); printf(received from %s at PORT %d\n,inet_ntop(AF_INET,&cliaddr.sin_addr,str,1)">(str)),ntohs(cliaddr.sin_port)); ) if (client[i] < ) { client[i] = connfd; save descriptor */ break; } if (i == FD_SETSIZE) { fputs(too many clients\n); } FD_SET(connfd,&allset); add new descriptor to set */ if (connfd > maxfd) maxfd = connfd; for select if (i > maxi) maxi = i; max index in client[] array if (--nready == continue; no more readable descriptors } 0; i <= maxi; i++) { check all clients 714 for data if ( (sockfd = client[i]) < continue; if (FD_ISSET(sockfd,1)">rset)) { if ( (n = Read(sockfd,buf,MAXLINE)) == ) { Close(sockfd); FD_CLR(sockfd,1)">allset); client[i] = -; } else { j; for (j = 0; j < n; j++) buf[j] = toupper(buf[j]); Write(sockfd,n); } ) break; } } } }
备:封装原始linux函数wrap.c:
#include <stdlib.h> #include <errno.h> #include <sys/socket.h> #include < #include <unistd.h> void perr_exit(const char *s) { perror(s); exit(); } int Accept(struct sockaddr *sa,socklen_t *salenptr) { n; again: if ((n = accept(fd,sa,salenptr)) < ) { if ((errno == ECONNABORTED) || (errno == EINTR)) goto again; perr_exit(accept error); } return n; } void Bind(struct sockaddr *sa,socklen_t salen) { if (bind(fd,salen) < ) perr_exit(bind errorvoid Connect(if (connect(fd,1)">connent errorvoid Listen( backlog) { if (listen(fd,backlog) < ) perr_exit(listen errorint Socket(int family,1)">int type,1)"> protocol) { n; if ((n = socket(family,type,protocol)) < socket error); n; } ssize_t Read(void *ptr,size_t nbytes) { ssize_t n; again: if ((n = read(fd,ptr,nbytes)) < if (errno == EINTR) else return -; } n; } ssize_t Write(if ((n = write(fd,nbytes)) == -void Close( fd) { if (close(fd) == -close error); } ssize_t Readn(vptr,size_t n) { size_t nleft; ssize_t nread; ptr; ptr = vptr; nleft =while (nleft > if ((nread = read(fd,nleft)) < EINTR) nread = else ; } else if (nread == ; } nleft -= nread; ptr += nread; } return n - nleft; } ssize_t Writen(if ((nwritten = write(fd,nleft)) <= if (nwritten < 0 && errno == EINTR) nwritten = ; } nleft -= nwritten; ptr += nwritten; } static ssize_t my_read(ptr) { static read_cnt; read_ptr; char read_buf[100]; if (read_cnt <= ) { again: if ((read_cnt = read(fd,read_buf,1)">sizeof(read_buf))) < EINTR) again; if (read_cnt == ) return ; read_ptr = read_buf; } read_cnt--; *ptr = *read_ptr++; } ssize_t Readline(char c,* vptr; for (n = 1; n < maxlen; n++if ((rc = my_read(fd,&c)) == ) { *ptr++ = c; if (c == '\n') if (rc == ) { *ptr = return n - { ; } } *ptr = n; }