select和poll以及epoll等的使用

1)select的源码案例
//fcntl函数的作用:可以用fcntl函数改变一个已打开的文件属性而不必重新open文件;
//什么叫IO多路复用,一个进程可以监视多个文件描述符,一旦某个描述符就绪(一般是读就绪或者写就绪),
//->则能够通知应用程序进行相应的读写操作;
//select用3个位图表示3个fdset的方式,poll使用一个pollfd的指针实现;
//io函数两种职责:操作IO和检测IO;
//基于事件网络模型 = 非阻塞IO + io多路复用;非阻塞IO的职责是只操作具体的IO,IO多路复用的职责是检测IO;
//检测功能放到内核中,包括(select poll epoll等)

#include <sys/types.h>
#include <sys/time.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <cstdlib>
#include<iostream>
#include<string.h>

using namespace std;
int main(void)
{
    fd_set fset;
    int fd = 0; //默认fd为输入,所以设置为0;
    int nread = 1024;
    int readNum = 0;
    char buffer[128];    
    FD_ZERO(&fset);
    FD_SET(fd,&fset);
    while(1)
    {        
        int ret = select(FD_SETSIZE,&fset,NULL,NULL,0);
        memset(buffer,0,sizeof(buffer));        
        switch(ret)
        {
            case -1:
                std::cerr<<"select error"<<std::endl;
            case 0:
                std::cout<<"select timeout"<<std::endl;
            default:
                if(FD_ISSET(fd,&fset))
                {
                    readNum = read(fd, buffer, nread); //必须读走,否则数据一直在缓存,造成select一直触发;
                    ioctl(fd, FIONREAD, &nread); //这句话必须有,否则不能在终端正确打印                      
                    if(readNum != 0)
                    {
                        // ioctl(fd, FIONREAD, &nread); //这句话不能在这里出现,否则不能正常打印;      
                        printf("receive num is: %d, recv msg is: %s",readNum,buffer);
                    }
                }
        }
    }
    return 0;
}

2)hash_map和map的【插入时间】运行时间比较,测试代码如下:

#include<iostream>
#include<map>
#include<string>
#include<vector>
#include<hash_map.h> //注意添加这个头文件
#include<time.h>
#include<unistd.h>

using namespace std;
 
typedef hash_map<int,int> h_map_t;
typedef map<int,int> map_t;

int main()
{   
    h_map_t m1;
    map_t m2;
    time_t rawtime;
    struct tm * timeinfo;
    int start,end;

    time(&rawtime);
    timeinfo = localtime(&rawtime);
    start =  timeinfo->tm_sec;
    for(uint64_t i = 0; i < 5000000; i++)
    {
       m1.emplace(i,i);
    }
    time(&rawtime);    
    timeinfo = localtime(&rawtime);
    end =  timeinfo->tm_sec; 
    cout<<"hash_map container using time is: "<<end-start<<endl;       

    time(&rawtime);
    timeinfo = localtime(&rawtime);
    start =  timeinfo->tm_sec;
    for(uint64_t i = 0; i < 10000000; i++)
    {
       m2.emplace(i,i);
    }
    time(&rawtime);    
    timeinfo = localtime(&rawtime);
    end =  timeinfo->tm_sec;    
    cout<<"map container using time is: "<<end-start<<endl;
    return 0;
}

//输出结果如下:
hash_map container using time is: 2 second
map container using time is: 12 second
//结论:数据量较小的时候,可以选择map; 数据量大,对插入时间要求高的时候选择hash_map;
3)std::promise与std::future

1)std::promise与std::future用法1
#include <iostream>
#include <vector>
#include <chrono>
 
#include "threadpool.h"
using namespace std;

void add(int a,int b, std::promise<int>& tmp_ret)
{
    int ret = a + b;
    tmp_ret.set_value(ret);
}
int main()
{
    std::promise<int> pro; //将promise作为一个参数,传递到线程当中去
    std::future<int> ret = pro.get_future();
    std::thread t(add,3,5,std::ref(pro)); 
    t.join();
    cout<<ret.get()<<endl;    
    return 0;
})std::promise与std::future用法2
//ret_future这里用的是引用类型
void add(int a,std::future<int>& ret_future, std::promise<int>& tmp_ret) 
{
    int ret = a + ret_future.get();
    tmp_ret.set_value(ret);
}
//主线程赋值,子线程获取
int main()
{
    std::promise<int> pro;
    std::future<int> ret = pro.get_future();

    std::promise<int> pro_in; 
    std::future<int> future_in = pro_in.get_future();

    std::thread t(add,3,std::ref(future_in),std::ref(pro)); 
    //do something 
    //...........
    //获取一个值,如下所示:
    pro_in.set_value(3);//假使这3是经过计算出来的,后经过赋值,把这个值传给子线程
    // future_in = pro_in.get_future();//不能有这句话,获取完,不能再获取了
    cout<<ret.get()<<endl;    
    t.join();
    return 0;
}

4)poll的使用案例

//poll的实现案例:
#include <iostream>
#include <unistd.h>
#include <poll.h>
int main()
{
    struct pollfd rfds;
    rfds.fd = 0;           //希望内核帮我们关注0号文件描述符上的【事件】
    //如果rfds.events |= POLLIN就一直返回有事件,不清楚为啥?    
    rfds.events = POLLIN; //希望内核关注0号文件描述符上的【读事件】
    rfds.revents = 0;      //这个参数用于内核通知我们有事件就绪了,让我们赶紧来取
    while (1)
    {
        int n = poll(&rfds, 1, -1); // 阻塞等待
        // int n=poll(&rfds,1,0);//非阻塞轮询
        // int n=poll(&rfds,1,1000);//每隔一秒看一眼
        std::cout << "ret : "<<n << std::endl; // 返回值的理解
        switch (n)
        {
        case 0:
            std::cout << "time out..." << std::endl;
            break;

        case -1:
            std::cout << "poll error" << std::endl;
            break;

        default:
            if (rfds.revents & POLLIN)
            {
                std::cout <<"有事件来了 "<< "fd is: "<< rfds.fd << ":"<< "事件已经就绪" << std::endl;
                char buffer[128];
                ssize_t s = read(rfds.fd, buffer, sizeof(buffer) - 1);
                if (s > 0)
                {
                    buffer[s] = 0;
                    std::cout << "recv msg: " << buffer << std::endl;
                }
            }
            break;
        }
    }

    return 0;
}

5)epoll的使用案例:

#include <sys/epoll.h>
#include <sys/fcntl.h>
#include<iostream>
#include<unistd.h>
using namespace std;

int main()
{
    int epfd = -1;
    struct epoll_event epEvent;

    if( (epfd = epoll_create(10)) == -1 ) 
    {
        cout<< "epoll_create fail" <<endl;
    }
    else
    {
        //将标准输入文件描述符(STDIN_FILENO = 0)加入epoll事件中
        epEvent.data.fd = STDIN_FILENO;
        epEvent.events=EPOLLIN;
        if(epoll_ctl(epfd,EPOLL_CTL_ADD,STDIN_FILENO,&epEvent)==-1)
        {
            cout<< "eplll_ctl fail---" <<endl; 
            return -1;
        }
        else
        {
            cout<< "eplll_ctl ok------" <<endl;             
        }    
    }
    while(1)
    {
       int ret = epoll_wait(epfd,&epEvent,10,-1); //无限等待
       if(ret == -1)
       {
            if(errno==EINTR)
            {
                continue;//epoll_wait超时
            }        
       }
       else
       {
            if(epEvent.events & EPOLLIN)
            {
                std::cout <<"有事件来了 "<< "fd is: "<< STDIN_FILENO << ":"<< "事件已经就绪" << std::endl;
                char buffer[128];
                ssize_t s = read(STDIN_FILENO, buffer, sizeof(buffer) - 1);
                if (s > 0)
                {
                    buffer[s] = 0;
                    std::cout << "recv msg: " << buffer << std::endl;
                }                
            }
       }
    }
    return 0;
}

6)client测试源码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
 
#define MAXLINE 80
#define SERV_PORT 8080

int main(int argc, char* argv[]){
   struct sockaddr_in servaddr;
   char buf[MAXLINE];
   int sockfd, n;
   char *str;
   if (argc !=2){
       fputs("usage: ./client messsage\n", stderr);
       exit(1);
   }
   str = argv[1];
   sockfd = socket(AF_INET, SOCK_STREAM, 0);
 
   bzero(&servaddr, sizeof(servaddr));
   servaddr.sin_family = AF_INET;
   inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr);
   servaddr.sin_port = htons(SERV_PORT);
 
   connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
   write(sockfd, str, strlen(str));
 
   n = read(sockfd, buf, MAXLINE);
   printf("Response from server:\n");
   write(STDOUT_FILENO, buf, n);
 
   close(sockfd);
   return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C语言是一种广泛使用的编程语言,它具有高效、灵活、可移植性强等特点,被广泛应用于操作系统、嵌入式系统、数据库、编译器等领域的开发。C语言的基本语法包括变量、数据类型、运算符、控制结构(如if语句、循环语句等)、函数、指针等。在编写C程序时,需要注意变量的声明和定义、指针的使用、内存的分配与释放等问题。C语言中常用的数据结构包括: 1. 数组:一种存储同类型数据的结构,可以进行索引访问和修改。 2. 链表:一种存储不同类型数据的结构,每个节点包含数据和指向下一个节点的指针。 3. 栈:一种后进先出(LIFO)的数据结构,可以通过压入(push)和弹出(pop)操作进行数据的存储和取出。 4. 队列:一种先进先出(FIFO)的数据结构,可以通过入队(enqueue)和出队(dequeue)操作进行数据的存储和取出。 5. 树:一种存储具有父子关系的数据结构,可以通过中序遍历、前序遍历和后序遍历等方式进行数据的访问和修改。 6. 图:一种存储具有节点和边关系的数据结构,可以通过广度优先搜索、深度优先搜索等方式进行数据的访问和修改。 这些数据结构在C语言中都有相应的实现方式,可以应用于各种不同的场景。C语言中的各种数据结构都有其优缺点,下面列举一些常见的数据结构的优缺点: 数组: 优点:访问和修改元素的速度非常快,适用于需要频繁读取和修改数据的场合。 缺点:数组的长度是固定的,不适合存储大小不固定的动态数据,另外数组在内存中是连续分配的,当数组较大时可能会导致内存碎片化。 链表: 优点:可以方便地插入和删除元素,适用于需要频繁插入和删除数据的场合。 缺点:访问和修改元素的速度相对较慢,因为需要遍历链表找到指定的节点。 栈: 优点:后进先出(LIFO)的特性使得栈在处理递归和括号匹配等问题时非常方便。 缺点:栈的空间有限,当数据量较大时可能会导致栈溢出。 队列: 优点:先进先出(FIFO)的特性使得

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值