栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 系统运维 > 运维 > Linux

Linux c 多路IO转接服务器(poll函数使用)

Linux 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Linux c 多路IO转接服务器(poll函数使用)

文章目录
  • 1、poll函数
  • 2、代码
  • 3、socket常用函数出错处理封装

1、poll函数
int poll(struct pollfd* fds,nfds_t nfds,int timeout);
struct pollfd
{
    int fd; // 监听的文件描述符
    short events; // 待监听文件描述符的对应事件
            取值:POLLIN、POLLOUT、POLLERR
    short revents;  // 传入时0,如果满足对应事件的话,返回非0:POLLIN、POLLOUT、POLLERR
};
参数:
    fds 监听文件描述符数组
    nfds 监听数组的,实际有效监听个数
    timeout 超时时长,单位:毫秒
	    -1阻塞等待 
	    0立即返回,不堵塞进程
	    〉0 等待制定毫秒数,如当前系统时间精度不够毫秒,向上取值

返回值:
    >0 返回满足对应监听事件的文件描述符总个数
    0 没有满足监听条件的文件描述符
    -1 设置errno

底层实现是一样,只是在select使用基础上进行了一点封装
优点:
自定数组结构,可以将,监听事件集合和返回事件集合分离
拓展监听上限,超出1024限制
缺点:
不能跨平台
无法直接定位满足监听事件的文件描述符,需要for

2、代码
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#include "socket_wrap.h"

int main()
{
    int i,j,listenfd,connfd,sockfd,maxi;
    int nready;
    ssize_t n;
    char buf[80],str[INET_ADDRSTRLEN];
    socklen_t clien;
    struct pollfd client[1024];
    struct sockaddr_in cliaddr,serv_addr;
    listenfd = Socket(AF_INET,SOCK_STREAM,0);
    int opt = 1;
    setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));

    bzero(&serv_addr,sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    serv_addr.sin_port = htons(9999);
    Bind(listenfd,(struct sockaddr*)&serv_addr,sizeof(serv_addr));
    Listen(listenfd,128);

    client[0].fd = listenfd;    // 要监听的第一个文件描述符,存入client[0]
    client[0].events = POLLIN;  // listenfd 监听的普通事件

    for(i=1;i<1024;i++)
        client[i].fd = -1;    
    maxi = 0;
    while (1)
    {
        nready = poll(client,maxi+1,-1);
        if(client[0].revents & POLLIN)  // listenfd有读事件就绪
        {
            clien = sizeof(cliaddr);
            connfd = Accept(client[0].fd,(struct sockaddr*)&cliaddr,&clien);
            printf("客户端:%s:%dn",
            inet_ntop(AF_INET,&cliaddr.sin_addr.s_addr,str,sizeof(str)),
            ntohs(cliaddr.sin_port));
            
            for(i=1;i<1024;i++) // i没机会++,因为break跳出了
            {
                if(client[i].fd < 0)
                {
                    client[i].fd = connfd;
                    break;
                }
            }
            if(i == 1024)
            {   
                perr_exit("too many clients");
            }

            client[i].events = POLLIN;
            if(i>maxi)
                maxi = i;
            if(--nready == 0)
                continue;
        }
        for(i=1;i<=maxi;i++)
        {
            if((sockfd=client[i].fd)<0)
            {
                continue;
            }
            if(client[i].revents & POLLIN)
            {
                if((n=Read(sockfd,buf,sizeof(buf)))<0)
                {
                    if(errno== ECONNRESET)  // 收到RST标志
                    {
                        printf("client[%d] aborted connectionn",i);
                        Close(sockfd);
                        client[i].fd = -1;  //poll中不监控该文件描述符,直接置为-1即可,
                    }
                    else
                    {
                        perr_exit("read error");
                    }
                }else if(n==0)
                {
                    Close(sockfd);
                    client[i].fd = -1;
                    printf("client[%d] aborted connection退出n",i);
                }
                else
                {
                    for(j=0;j 
3、socket常用函数出错处理封装 

socket_wrap.h

#ifndef __WRAP_H_
#define __WRAP_H_

void perr_exit(const char* s);
int Accept(int fd,struct sockaddr* sa,socklen_t* salenptr);
int Bind(int fd,const struct sockaddr* sa,socklen_t salen);
int Connect(int fd,const struct sockaddr* sa,socklen_t salen);
int Listen(int fd,int backlog);
int Socket(int family,int type,int protocol);
ssize_t Read(int fd,void* ptr,size_t nbytes);
ssize_t Write(int fd,const void* ptr,size_t nbytes);
int Close(int fd);
ssize_t Readn(int fd,void* vptr,size_t n);
ssize_t Writen(int fd,const void* vptr,size_t n);
static ssize_t my_read(int fd,char* ptr);
ssize_t Readline(int fd,void* vptr,size_t maxlen);

#endif // !__WRAP_H_

socket_wrap.c

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include "socket_wrap.h"

void perr_exit(const char* s)
{
    perror(s);
    exit(1);
}

int Accept(int fd,struct sockaddr* sa,socklen_t* salenptr)
{
    int n;
again:
    if((n=accept(fd,sa,salenptr))<0)
    {
        if(errno == EConNABORTED || (errno==EINTR))
            goto again;
        else
            perr_exit("accept error");
    }
    return n;
}

int Bind(int fd,const struct sockaddr* sa,socklen_t salen)
{
    int n;
    if((n=bind(fd,sa,salen))<0)
    {
        perr_exit("bind error");
    }
    return n;
}

int Connect(int fd,const struct sockaddr* sa,socklen_t salen)
{
    int n;
    if((n=connect(fd,sa,salen))<0)
        perr_exit("connect error");
    return n;

}

int Listen(int fd,int backlog)
{
    int n;
    if((n=listen(fd,n))<0)
    {
        perr_exit("listen error");
    }
    return n;
}


int Socket(int family,int type,int protocol)
{
    int n;
    if((n=socket(family,type,protocol))<0)
        perr_exit("socket error");
    return n;
}

ssize_t Read(int fd,void* ptr,size_t nbytes)
{
    ssize_t n;
again:
    if((n=read(fd,ptr,nbytes))<0)
    {
        if(errno==EINTR)
            goto again;
        else
            return -1;
    }
    return n;
}

ssize_t Write(int fd,const void* ptr,size_t nbytes)
{
    ssize_t n;
    if((n=write(fd,ptr,nbytes))<0)
        perr_exit("write error");
    return n;
}

int Close(int fd)
{
    int n;
    if((n=close(fd))<0)
        perr_exit("close error");
    return n;
}

ssize_t Readn(int fd,void* vptr,size_t n)
{
    size_t nleft;   // unsigned int 剩余未读取字节数
    ssize_t nread; // int 实际读到的字节数
    char* ptr;
    ptr = vptr;
    nleft = n;
    while (nleft>0)
    {
        if((nread = read(fd,ptr,nleft))<0)
        {
            if(errno == EINTR)        
                nread = 0;
            else
             return -1;
        }
        else if(nread == 0)
            break;
        nleft -= nread;
        ptr+=nread;
    }
    return n-nread;
    
}

ssize_t Writen(int fd,const void* vptr,size_t n)
{
    size_t nleft;
    ssize_t nwritten;
    const char* ptr;
    ptr = vptr;
    nleft = n;
    while(nleft>0)
    {
        if((nwritten=write(fd,ptr,nleft))<=0)
        {
            if(nwritten<0 && errno==EINTR)
                nwritten = 0;
            else
                return -1;
        }
        nleft -= nwritten;
        ptr += nwritten;
    }
    return n;
}

static ssize_t my_read(int fd,char* ptr)
{
    static int read_cnt;
    static char* read_ptr;
    static char read_buf[100];
    if(read_cnt<=0)
    {
    again:
        if((read_cnt=read(fd,read_buf,sizeof(read_buf)))<0)
        {
            if(errno == EINTR)
                goto again;
            return -1;
        }
        else if(read_cnt == 0)
            return 0;
        read_ptr = read_buf;
    }
    read_cnt--;
    *ptr = *read_ptr++;
    return 1;
}

// 传出参数 vptr
ssize_t Readline(int fd,void* vptr,size_t maxlen)
{
    ssize_t n,rc;
    char c,*ptr;
    ptr = vptr;
    for(n=1;n
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/468629.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号