本文已参与「新人创作礼」活动,一起开启掘金创作之路。
poll
参考文章:blog.csdn.net/lianghe_wor…
头文件 #include <poll.h>
select() 和 poll() 系统调用的本质一样,poll() 的机制与 select() 类似,与 select() 在本质上没有多大差别,管理多个描述符也是进行轮询,根据描述符的状态进行处理,但是 poll() 没有最大文件描述符数量的限制(但是数量过大后性能也是会下降)。 poll() 和 select() 同样存在一个缺点就是,包含大量文件描述符的数组被整体复制于用户态和内核的地址空间之间,而不论这些文件描述符是否就绪,它的开销随着文件描述符数量的增加而线性增大。
select用三个结构来记录信息,而poll只用一个结构
#include <errno.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <pthread.h>
#include <poll.h>
#define MAXLNE 4096
#define POLL_SIZE 1024
int main(int argc, char **argv)
{
int listenfd, connfd, n;
struct sockaddr_in servaddr;
char buff[MAXLNE];
if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
printf("create socket error: %s(errno: %d)\n", strerror(errno), errno);
return 0;
}
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(9999);
if (bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) == -1)
{
printf("bind socket error: %s(errno: %d)\n", strerror(errno), errno);
return 0;
}
if (listen(listenfd, 10) == -1)
{
printf("listen socket error: %s(errno: %d)\n", strerror(errno), errno);
return 0;
}
struct pollfd fds[POLL_SIZE] = {0};
fds[listenfd].fd = listenfd;
fds[listenfd].events = POLLIN;
int max_fd = listenfd;
while (1)
{
int nready = poll(fds, max_fd + 1, -1);
if (fds[listenfd].revents & POLLIN)
{
struct sockaddr_in client;
socklen_t len = sizeof(client);
if ((connfd = accept(listenfd, (struct sockaddr *)&client, &len)) == -1)
{
printf("accept socket error: %s(errno: %d)\n", strerror(errno), errno);
return 0;
}
fds[connfd].fd = connfd;
fds[connfd].events = POLLIN;
if (connfd > max_fd)
max_fd = connfd;
if (--nready == 0)
continue;
}
int i = 0;
for (i = listenfd + 1; i <= max_fd; i++)
{
if (fds[i].revents & POLLIN)
{
n = recv(i, buff, MAXLNE, 0);
if (n > 0)
{
buff[n] = '\0';
printf("recv msg from client: %s\n", buff);
send(i, buff, n, 0);
}
else if (n == 0)
{
fds[i].fd = -1;
close(i);
}
if (--nready == 0)
break;
}
}
}
close(listenfd);
return 0;
}
epoll
参考文章:cloud.tencent.com/developer/a…
2.6的版本以前,linux只能用来做嵌入式,随着epoll的出现,linux才被用作服务器,一些框架的底层离不开epoll,服务器核心的点,就是24小时无间断的死循环while(1),
select 和 poll都是我们主动去搜寻事件,而epoll是由它来告诉我们那里来了事件
头文件:#include <sys/epoll.h>
epoll_create : 只有一个参数,填大于0就可以 ,之前是用数组存储,现在是用链表,但是为了兼容之前的代码,所以把这个形参留下来了。
epoll_ctl --> add、delete、modify
创建一栋楼:epoll_create
添加一个住户:epoll_ctl --> add
删除一个住户:epoll_ctl --> delete
修改一个住户:epoll_ctl -->modify
快递员装快递的盒子: struct epoll_event events[POLL_SIZE] = {0};
楼下有一个蜂巢
快递员多久来取一次快递:epoll_wait
快递员取完快递后交给应用层
recv完直接send的写法:
#include <errno.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/epoll.h>
#define MAXLNE 4096
#define POLL_SIZE 1024
int main(int argc, char **argv)
{
int listenfd, connfd, n;
struct sockaddr_in servaddr;
char buff[MAXLNE];
if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
printf("create socket error: %s(errno: %d)\n", strerror(errno), errno);
return 0;
}
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(9999);
if (bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) == -1)
{
printf("bind socket error: %s(errno: %d)\n", strerror(errno), errno);
return 0;
}
if (listen(listenfd, 10) == -1)
{
printf("listen socket error: %s(errno: %d)\n", strerror(errno), errno);
return 0;
}
int epfd = epoll_create(1);
struct epoll_event events[POLL_SIZE] = {0}; //快递员盒子的大小
struct epoll_event ev;
ev.events = EPOLLIN;
ev.data.fd = listenfd;
epoll_ctl(epfd, EPOLL_CTL_ADD, listenfd, &ev);
while (1)
{
//快递员取快递,-1表示有了快递才去取
int nready = epoll_wait(epfd, events, POLL_SIZE, -1);
if (nready == -1)
{
continue;
}
int i = 0;
for (i = 0; i < nready; i++)
{
int clientfd = events[i].data.fd;
if (clientfd == listenfd)
{
//对listenfd进行处理
struct sockaddr_in client;
socklen_t len = sizeof(client);
if ((connfd = accept(listenfd, (struct sockaddr *)&client, &len)) == -1)
{
printf("accept socket error: %s(errno: %d)\n", strerror(errno), errno);
return 0;
}
ev.events = EPOLLIN;
ev.data.fd = connfd;
epoll_ctl(epfd, EPOLL_CTL_ADD, connfd, &ev);
}
else if (events[i].events & EPOLLIN)
{
//对所有的connfd进行处理
n = recv(clientfd, buff, MAXLNE, 0);
if (n > 0)
{
buff[n] = '\0';
printf("recv msg from client: %s\n", buff);
send(clientfd, buff, n, 0);
}
else if (n == 0)
{
ev.events = EPOLLIN;
ev.data.fd = clientfd;
epoll_ctl(epfd, EPOLL_CTL_DEL, clientfd, &ev);
close(clientfd);
}
}
}
}
close(listenfd);
return 0;
}