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;
}
2)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;
}