加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > Linux > 正文

利用select实现IO多路复用TCP服务端

发布时间:2020-12-13 22:29:01 所属栏目:Linux 来源:网络整理
导读:一、相关函数 1.??int?select (int?maxfdp,fd_set *readset,fd_set *writeset,fd_set *exceptset,struct?timeval *timeout); int maxfdp : 该参数是指集合中所有文件描述符的范围, 即所有文件描述符的最大值加1; fd_set *readset : 该参数是我们所关心的文

一、相关函数

  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(二、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 %dn,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 clientsn);
            }
            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;
}

?

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读