网络通信---epoll

#include "head.h"

/*功能:将传入的文件描述符进行非阻塞处理
 *newfd:需要处理发文件描述符
 *返回值:空
 */
void set_nonblock(int newfd)
{
    int flags = fcntl(newfd,F_GETFL);
    flags |= O_NONBLOCK;
    fcntl(newfd,F_SETFL,flags);
    printf("fcctl ok\n");
}

/*功能:将文件描述符功能进行修改
 *epollid:句柄描述符
 *newfd:需要更改事件的描述符
 *a:读或写
 *b:是否开启ET模式
 *返回值:空
 */
void mod_fd(int epollid,int newfd,bool a,bool b)
{
    struct epoll_event eve;
    bzero(&eve,sizeof(eve));
    eve.data.fd = newfd;
    if(a == true)
        eve.events = EPOLLIN;
    if(a == false)
        eve.events = EPOLLOUT;
    if(b == true)
        eve.events |= EPOLLET;
    epoll_ctl(epollid,EPOLL_CTL_MOD,newfd,&eve);
    set_nonblock(newfd);
}

/*功能:将文件描述符加入epoll句柄描述符中,由句柄描述符树管理,并将描述符置为可读,选择是否开启ET模式
 *epollid:句柄描述符
 *newfd:需要由句柄描述符统一管理的新描述符
 *a:true 或 false 开启ET模式
 *返回值:空
 */
void add_fd(int epollid,int newfd,bool a)
{
    struct epoll_event eve;
    bzero(&eve,sizeof(eve));
    eve.data.fd = newfd;
    eve.events = EPOLLIN;
    if(a == true)
    {
        eve.events |= EPOLLET;
    }
    epoll_ctl(epollid,EPOLL_CTL_ADD,newfd,&eve);
    set_nonblock(newfd);
}

/*功能:LT模式下的读写
 *epollid:句柄文件描述符
 *sockid:socket文件描述符
 *ret:正在发生的事件个数
 *eve:事件结构体地址
 *返回值:空
 */
void epoll_lt(int epollid,int sockid,int ret,struct epoll_event *eve)
{
    int i;
    struct sockaddr_in cli;
    bzero(&cli,sizeof(cli));
    int len = sizeof(struct sockaddr_in);

    for(i = 0;i < ret;i++)
    {
        int tmpid = eve[i].data.fd;
	printf("%d\n",eve[i].events);
	printf("tmpid--->%d\n",tmpid);
        if(tmpid == sockid)
        {
            int newfd = accept(sockid,(struct sockaddr *)&cli,&len);
			printf("newfd--->%d\n",newfd);
            if(newfd < 0)
                sys_error("accept failed");
            printf("client port:%d client ip:%s\n",ntohs(cli.sin_port),inet_ntoa(cli.sin_addr));
            add_fd(epollid,newfd,false);
        }
        else if(eve[i].events &EPOLLIN)
        {
            char buf[10];
            bzero(buf,10);
            int ret = read(tmpid,buf,10);
            if(ret < 0)
            {
                perror("read failed\n");
                close(tmpid);
                break;
            }
            if(ret == 0)
            {
                printf("client exit\n");
                close(tmpid);
                break;
            }
            printf("来自客户端:%s\n",buf);
        }
        else
        {
            printf("不可能走这里的\n");
        }
    }
}

/*功能:ET模式下的读写
 *epollid:句柄文件描述符
 *sockid:socket文件描述符
 *ret:正在发生的事件个数
 *eve:事件结构体地址
 *返回值:空
 */
void epoll_et(int epollid,int sockid,int ret,struct epoll_event *eve)
{
    int i;
    struct sockaddr_in cli;
    bzero(&cli,sizeof(cli));
    int len = sizeof(struct sockaddr_in);

    for(i = 0;i < ret;i++)
    {
        int tmpid = eve[i].data.fd;
		printf("%d\n",eve[i].events);
		printf("tmpid--->%d\n",tmpid);
        if(tmpid == sockid)
        {
            int newfd = accept(sockid,(struct sockaddr *)&cli,&len);
			printf("newfd--->%d\n",newfd);
            if(newfd < 0)
                sys_error("accept failed");
            printf("client port:%d client ip:%s\n",ntohs(cli.sin_port),inet_ntoa(cli.sin_addr));
            add_fd(epollid,newfd,true);
        }
        else if(eve[i].events & EPOLLIN)
        {
            while(1)
            {
                char buf[10];
                bzero(buf,10);
                int ret = read(tmpid,buf,10);
                if(ret < 0)
                {
                    if((errno == EAGAIN || errno == EWOULDBLOCK))
                    {
                        printf("read later\n");
                        break;
                    }
                    close(tmpid);
                    break;
                }
                if(ret == 0)
                {
                    close(tmpid);
                    break;
                }
                printf("来自客户端:%s\n",buf);
            }
            mod_fd(epollid,tmpid,false,true);
        }
        else if(eve[i].events & EPOLLOUT)
        {
            char cmd[10] = "hello";
            write(tmpid,cmd,strlen(cmd));
            mod_fd(epollid,tmpid,true,true);
        }
        else
        {
            printf("不可能走这里的\n");
        }
    }
}

/*功能:绑定传入的端口与ip返回一个socket的文件描述符
 *ip:ip地址
 *port:端口号
 *返回值:socket的文件描述符
 */
int server_init(char *ip,char *port)
{
    int sockid = socket(AF_INET,SOCK_STREAM,0);
    if(sockid < 0)
        sys_error("sock failed");

    struct sockaddr_in ser;
    bzero(&ser,sizeof(ser));
    ser.sin_family = AF_INET;
    ser.sin_port = htons(atoi(port));
    ser.sin_addr.s_addr = inet_addr(ip);

    int ret = bind(sockid,(struct sockaddr *)&ser,sizeof(ser));
    if(ret < 0)
        sys_error("bind failed");
    ret = listen(sockid,128);

    return sockid;
}

/*功能:主函数
 *argc:命令字符串个数
 *argv:命令字符串的地址
 *返回值:Int类型
 */
int main (int argc,char *argv[])
{
    if(argc != 3)
    {
        printf("usage:%s <iP> <port>\n",argv[0]);
        exit(1);
    }
    int sockid = server_init(argv[1],argv[2]);
	printf("sockid--->%d\n",sockid);

    struct epoll_event eve[MAX_EVE];
    bzero(eve,MAX_EVE);
    int epollid = epoll_create(5);
	printf("epollid--->%d\n",epollid);
    if(epollid < 0)
        sys_error("epoll_create failed");

    add_fd(epollid,sockid,true);
    printf("listen ok\n");
    while(1)
    {
        printf("******************\n");
        int ret = epoll_wait(epollid,eve,MAX_EVE,-1);
        printf("ret:%d\n",ret);
        if(ret < 0)
            sys_error("epoll_wait failed");
        epoll_et(epollid,sockid,ret,eve);
       // epoll_lt(epollid,sockid,ret,eve);
    }

    close(sockid);
    return 0; 
}
发布了38 篇原创文章 · 获赞 42 · 访问量 6万+

猜你喜欢

转载自blog.csdn.net/weixin_42471952/article/details/82668622