基于epoll模型的server/client
程序员文章站
2022-03-14 12:13:19
...
对于epoll来说,当产生epoll调用时,不单是进行了epoll调用。在调用epoll_create()的时候创建了epoll模型,epoll模型分为三部分,红黑树,就绪队列,回调机制。
红黑树,注册epoll事件就是将事件添加至红黑树中,并将想关心的事件也添加进去,该红黑树以文件描述符作为key值;
就绪队列,就绪队列里存放是就绪的文件描述符,当文件描述符就绪时会将其拷贝至就绪队列;
回调机制:底层的一种机制
epoll_ctl()则是对红黑树中文件描述符的操作,可以添加,可以修改,也可以删除。
epoll_wait就是将所有的就绪的文件描述符从内核事件表(相当于就绪队列)中拿出来并放到它的第二个参数的数组中。所以数组中存放的的就会是所有已就绪的文件描述符,而没有其他。极大的提高了查询就绪文件描述符的效率。
////////////////////////////////////////client.c/////////////////////////////////////
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/socket.h>
#include<string.h>
#include<netinet/in.h>
int main(int argc,char* argv[])
{
if(argc!=2)
{
printf("Usage :./select_client [port]");
return 1;
}
//
struct sockaddr_in client;
client.sin_port = htons(atoi(argv[1]));
client.sin_family = AF_INET;
client.sin_addr.s_addr = htonl(INADDR_ANY);
//创建套接字
int sock = socket(AF_INET,SOCK_STREAM,0);
if(sock<0)
{
perror("socket");
return 1;
}
//连接服务器
if(connect(sock,(struct sockaddr*)&client,sizeof(client))<0)
{
perror("connect");
return 1;
}
for(;;)
{
//输入消息并刷新缓冲区
printf("client >");
fflush(stdout);
//将消息读到buf里
char buf[1024] = {0};
read(0,buf,sizeof(buf)-1);
//将消息写给文件描述符
if(write(sock,buf,strlen(buf))<0){
perror("write");
continue;
}
//将服务器返回的消息写到buf里
int ret = read(sock,buf,sizeof(buf)-1);
if(ret<0){
perror("read");
continue;
}
if(ret==0)
{
printf("server close\n");
break;
}
printf("server:%s\n",buf);
}
close(sock);
return 0;
}
/////////////////////////////
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/epoll.h>
#include<sys/types.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<string.h>
int startup(int port)
{
int sock = socket(AF_INET,SOCK_STREAM,0);
if(sock<0)
{
perror("socket");
exit(3);
}
int opt = 1;
setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));
struct sockaddr_in local;
local.sin_family = AF_INET;
local.sin_addr.s_addr = htonl(INADDR_ANY);
local.sin_port = htons(port);
if(bind(sock,(struct sockaddr*)&local,sizeof(local))<0)
{
perror("bind");
exit(4);
}
if(listen(sock,5)<0)
{
perror("listen");
exit(5);
}
return sock;
}
void handler_events(int epfd,struct epoll_event revs[],int num,int listen_sock)
{
int i = 0;
struct epoll_event ev;
for(;i<num;i++)
{
int fd = revs[i].data.fd;
if(fd==listen_sock && (revs[i].events & EPOLLIN)){
struct sockaddr_in client;
socklen_t len = sizeof(client);
int new_sock = accept(fd,(struct sockaddr*)&client,&len);
if(new_sock<0)
{
perror("accept");
continue;
}
//获得新连接不能直接读,否则会造成阻塞
printf("get new link\n");
ev.events = EPOLLIN;
ev.data.fd = new_sock;
epoll_ctl(epfd,EPOLL_CTL_ADD,new_sock,&ev);//将获得的新连接添加到epoll模型中
continue;
}
if(revs[i].events & EPOLLIN){
char buf[10240];
ssize_t s = read(fd,buf,sizeof(buf)-1);
if(s>0){
buf[s]=0;
printf("%s",buf);
ev.events = EPOLLOUT;
ev.data.fd = fd;
epoll_ctl(epfd,EPOLL_CTL_MOD,fd,&ev);
}
else if(s==0){
printf("client quit");//客户端退出
close(fd);//关闭文件描述符
epoll_ctl(epfd,EPOLL_CTL_DEL,fd,NULL);//将文件描述符从epoll模型中去掉
}
}
else{
perror("read");
close(fd);//关闭文件描述符
epoll_ctl(epfd,EPOLL_CTL_DEL,fd,NULL);//将文件描述符从epoll模型中去掉
}
continue;
}
if(revs[i].events & EPOLLOUT){
const char* echo = "HTTP/1.1 200 OK\r\n\r\n<html>hello epoll !</html>\n";
write(fd,echo,strlen(echo));
//写完之后
close(fd);//关闭文件描述符
epoll_ctl(epfd,EPOLL_CTL_DEL,fd,NULL);//将文件描述符从epoll模型中去掉
}
}
}
//eopll_server 8080
int main(int argc,char* argv[])
{
if(argc!=2)
{
printf("Usage:%s port\n",argv[0]);
return 1;
}
int epfd = epoll_create(256);//绝对是3
if(epfd<0)
{
perror("epoll_create");
return 2;
}
int listen_sock = startup(atoi(argv[1]));
struct epoll_event ev;
ev.events = EPOLLIN;
ev.data.fd = listen_sock;//把listen_sock托管起来
epoll_ctl(epfd,EPOLL_CTL_ADD,listen_sock,&ev);
struct epoll_event revs[128];
int n = sizeof(revs)/sizeof(revs[0]);
int timeout = 1000;
int num = 0;
for(;;){
switch((num = epoll_wait(epfd,revs,n,timeout))){
case -1:
perror("epoll_wait");
break;
case 0:
printf("timeout\n");
break;
default:
handler_events(epfd,revs,num,listen_sock);
break;
}
}
close(epfd);
close(listen_sock);
return 0;
}
推荐阅读
-
无法找到产品Microsoft SQL Server Native Client的安装程序包的解决方法Sqlncli.msi
-
基于keras训练的h5模型进行批量预测
-
基于Sql Server通用分页存储过程的解决方法
-
python实现的udp协议Server和Client代码实例
-
基于SQL Server OS的任务调度机制详解
-
基于SQL Server中如何比较两个表的各组数据 图解说明
-
基于SQL Server中char,nchar,varchar,nvarchar的使用区别
-
PHP封装的数据库模型Model类完整示例【基于PDO】
-
基于Python的SQL Server数据库实现对象同步轻量级
-
基于windows server 2016和sqlserver 2016 AlwaysOn的群集配置