select的缺点;poll ;poll的缺点;epoll

1.select的缺点:
    1.select监听的文件描述符集合是一个数组,有上限(1024个)
    2.select监听的文件描述符集合在应用层,内核层监听事件后需要传递给用户层带来资源开销
    3.select需要用户手动查找产生事件的文件描述符
    4.select只能工作在水平触发模式(低速模式)而无法工作在边沿触发模式(高速模式)

2.poll 
    int poll(struct pollfd *fds, nfds_t nfds, int timeout);
    功能:
        监听文件描述符集合,工作方式类似于select 
    参数:
        fds:文件描述符集合首地址
        nfds:文件描述符集合的数组的长度 
        timeout:超时时间,单位毫秒,-1表示永久等待
    返回值:
        成功返回产生事件文件描述符个数 
        失败返回-1 
        超时仍然没有产生的事件返回0 
    
    struct pollfd {
        int   fd;         /* file descriptor */
        short events;     /* requested events */
        short revents;    /* returned events */
    };

read.c

#include "head.h"

int main(void)
{
    int fd = 0;
    char tmpbuff[4096] = {0};
    struct pollfd fds[2];
    int nready = 0;

    mkfifo("/tmp/myfifo", 0777);
    fd = open("/tmp/myfifo", O_RDONLY);
    if (-1 == fd)
    {
        perror("fail to open");
        return -1;
    }

    fds[0].fd = fd;                     //要监听的文件描述符
    fds[0].events = POLLIN;             //要监听的事件

    fds[1].fd = 0;
    fds[1].events = POLLIN;

    while (1)
    {
        nready = poll(fds, 2, -1);
        if (-1 == nready)
        {
            perror("fail to poll");
            return -1;
        }

        if (fds[0].revents & POLLIN)
        {
            memset(tmpbuff, 0, sizeof(tmpbuff));
            read(fd, tmpbuff, sizeof(tmpbuff));
            printf("FIFO:%s\n", tmpbuff);
        }

        if (fds[1].revents & POLLIN)
        {
            memset(tmpbuff, 0, sizeof(tmpbuff));
            gets(tmpbuff);
            printf("STDIN:%s\n", tmpbuff);
        }
    }
    
    close(fd);

    return 0;
}


    1.poll的缺点:
        1.poll监听的文件描述符集合在应用层,内核层监听事件后需要传递给用户层带来资源开销
        2.poll需要用户手动查找产生事件的文件描述符
        3.poll只能工作在水平触发模式(低速模式)而无法工作在边沿触发模式(高速模式)

3.epoll
    1.epoll_create
      int epoll_create(int size);
      功能:
        在内核层创建一张epoll监听的事件表
      参数:
        size:监听的事件表大小
      返回值: 
        成功返回新的文件描述符
        失败返回-1

    2.epoll_ctl 
      int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
      功能:
        管理内核中epoll事件表
      参数:
        epfd:文件描述符 
        op: EPOLL_CTL_ADD   添加客户端 
            EPOLL_CTL_MOD   修改客户端 
            EPOLL_CTL_DEL   删除客户端
        fd:文件描述符 
        event:事件结构体
      返回值:
        成功返回0 
        失败返回-1

    typedef union epoll_data {
        void        *ptr;
        int          fd;
        uint32_t     u32;
        uint64_t     u64;
    } epoll_data_t;

    struct epoll_event {
        uint32_t     events;      /* Epoll events */
        epoll_data_t data;        /* User data variable */
    };  

    events:EPOLLIN  EPOLLOUT  EPOLLET  
    
    3.epoll_wait    
      int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);
      功能:
        监听epfd对应的事件表中是否有事件发生 
      参数: 
        epfd:文件描述符 
        events:存放产生事件的数组空间首地址
        maxevents:最多存放数组元素个数 
        timeout:超时时间,单位毫秒,-1表示永久等待
      返回值:
        成功返回实际发生事件的个数
        失败返回-1 
        超时仍然没有产生事件返回0

#include "head.h"

int main(void)
{   
    int epfd = 0;
    int fd = 0;
    int ret = 0;
    char tmpbuff[4096] = {0};
    struct epoll_event env;
    struct epoll_event retenv[2]; 
    int nready = 0;
    int i = 0;

    mkfifo("/tmp/myfifo", 0777);
    fd = open("/tmp/myfifo", O_RDONLY);
    if (-1 == fd)
    {
        perror("fail to open");
        return -1;
    }

    //创建一张内核监听的事件表
    epfd = epoll_create(2);
    if (-1 == epfd)
    {
        perror("fail to epoll_create");
        return -1;
    }

    //将fd文件描述符加入事件表中
    env.events = EPOLLIN;
    env.data.fd = fd;
    ret = epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &env);
    if (-1 == ret)
    {
        perror("fail to epoll_ctl");
        return -1;
    }

    //将0文件描述符加入事件表中
    env.events = EPOLLIN;
    env.data.fd = 0;
    ret = epoll_ctl(epfd, EPOLL_CTL_ADD, 0, &env);
    if (-1 == ret)
    {
        perror("fail to epoll_ctl");
        return -1;
    }

    while (1)
    {   
        nready = epoll_wait(epfd, retenv, 2, -1);
        if (-1 == nready)
        {
            perror("fail to epoll_wait");
            return -1;
        }

        for (i = 0; i < nready; i++)
        {
            if (retenv[i].data.fd == fd)
            {
                memset(tmpbuff, 0, sizeof(tmpbuff));
                read(fd, tmpbuff, sizeof(tmpbuff));
                printf("FIFO:%s\n", tmpbuff);
            }
            else if (retenv[i].data.fd == 0)
            {
                memset(tmpbuff, 0, sizeof(tmpbuff));
                gets(tmpbuff);
                printf("STDIN:%s\n", tmpbuff);
            }
        }   
    }
    
    close(epfd);

    return 0;
}


    epoll的优点:
        1.epoll没有文件描述符上限限制 
        2.epoll监听的事件表在内核层,内核监听事件不需要操作用户层空间提高效率
        3.epoll会获得产生事件的文件描述符,不需要用户查找
        4.epoll可以工作在边沿触发模式(高速模式),提高效率

1.编写客户端和服务端实现基于UDP的聊天室:
    客户端:
        1.允许用户输入昵称
        2.可以向服务端发送登录消息
        3.可以向服务器发送退出消息
        4.可以向服务器发送聊天消息

    服务端: 
        1.接收所有客户端的登录消息
        2.接收所有客户端的退出消息
        3.能够转发所有客户端的聊天消息

2.实现一个基于TCP的单词查询系统:
    dict.txt文件 

    1.编写客户端允许注册、注销、登录到服务器中
    2.登录成功后,客户端可以发送给服务器一个单词,并获得单词的含义
    3.客户端允许向服务器发送获得历史单词信息

    1.服务器响应注册、注销、登录一系列功能
    2.服务器响应客户端单词查询和历史搜索单词功能
    3.服务器需要支持TCP并发模型,支持多用户的并发请求

//服务端代码
#include "head.h"
 
int main(int argc, char const *argv[])
{
    struct sockaddr_in seraddr;
    bzero(&seraddr, sizeof(seraddr));
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if(-1 == sockfd)
    {
        perror("fail to socket");
        return -1;
    }
 
    seraddr.sin_family = AF_INET;
    seraddr.sin_port = htons(50000);
    seraddr.sin_addr.s_addr = INADDR_ANY;
    
    int bret = bind(sockfd, (SA)&seraddr, sizeof(seraddr));
    if(-1 == bret)
    {
        perror("fail to bind");
        return -1;
    }
    int lret = listen(sockfd, 10);
    if(-1 == lret)
    {
        perror("fail to listen");
        return -1;
    }
    int serfd = accept(sockfd, NULL, NULL);
    if(-1 == serfd)
    {
        perror("fail to accept");
        return -1;
    }
 
    FILE *fp = fopen("dict.txt", "r");
    if(fp == NULL)
    {
        perror("fail to fopen");
        return -1;
    }
 
    char word[128] = {0};
    char summar[1024] = {0};
    
    while(1)
    {
        memset(word, 0, sizeof(word));
        fseek(fp, 0, SEEK_SET);
        recv(serfd, word, sizeof(word), 0);
        printf("%s\n", word);
        if(!strcmp(word, "#quit"))
        {
            break;
        }
        while(1)
        {
            memset(summar, 0, sizeof(summar));
            char *psum = summar;
            char *pret = fgets(summar, sizeof(summar), fp);
            if(!strncmp(word, summar, strlen(word)))
            {
                psum += strlen(word);
                while(*psum == ' ')
                {
                    psum++;
                }
                send(serfd, psum, strlen(psum), 0);
                break;
            }
            if(NULL == pret)
            {
                char fail[64] = "please enter a correct word, or you can quit!\n";
                send(serfd, fail, strlen(fail), 0);
                break;
            }
        }
    }
 
    fclose(fp);
    close(sockfd);
    close(serfd);
    return 0;
}
//客户端代码
#include "head.h"
 
int main(int argc, char const *argv[])
{
    struct sockaddr_in seraddr;
    bzero(&seraddr, sizeof(seraddr));
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if(-1 == sockfd)
    {
        perror("fail to socket");
        return -1;
    }
 
    seraddr.sin_family = AF_INET;
    seraddr.sin_port = htons(50000);
    seraddr.sin_addr.s_addr = inet_addr("192.168.0.185");
    int conn = connect(sockfd, (SA)&seraddr, sizeof(seraddr));
    if(-1 == conn)
    {
        perror("fail to connect");
        return -1;
    }
 
    char word[128] = {0};
    char mean[1024] = {0};
    while(1)
    {
        memset(word, 0, sizeof(word));
        memset(mean, 0, sizeof(mean));
        printf("enter a word:");
        scanf("%s", word);
        if(!strcmp(word, "#quit"))
        {
            break;
        }
        send(sockfd, word, strlen(word), 0);
        recv(sockfd, mean, sizeof(mean), 0);
        printf("%s", mean);
    }
 
    close(sockfd);
    return 0;
}
//头文件
#ifndef _HEAD_H_
#define _HEAD_H_
 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <netinet/ip.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
 
#endif

  • 6
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值