epoll的简单实现

epoll实现简单服务器 /* *使用epoll实现服务器 */ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include &... 阅读详情

1.Network.h

#ifndef NETWORK_H
#define NETWORK_H
#include <iostream>
#include <sys/epoll.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
#include <map>
#define  MAX_COUNT          1000               //最大连接数
using namespace std;

enum IOOperType {
    TYPE_ACP,            //accept事件到达,有新连接请求
    TYPE_RECV,           //数据接收事件
};


struct DataPackage
{
    //接收缓存区
    char                      RecvBuffer[1024];
    //发送缓存区
    char                      SendBuffer[1024];
    //对端信息
    struct sockaddr           addr;
    //对端信息长度
    socklen_t                 length;
    //
    int                       socket;

    int                       EventType;
    DataPackage()
    {
        memset(RecvBuffer,0,sizeof(RecvBuffer));
        memset(SendBuffer,0,sizeof(SendBuffer));
        length=sizeof(sockaddr);
    }
    void ResetRecvBuffer()
    {
        memset(RecvBuffer,0,sizeof(RecvBuffer));
    }
    void ResetSendBuffer()
    {
        memset(SendBuffer,0,sizeof(SendBuffer));
    }
};
struct EpollEvent:public epoll_event
{
    EpollEvent(){}

    EpollEvent(DataPackage* pData)
    {
        data.ptr=(void*)pData;
    }
    ~EpollEvent()
    {

    }
    DataPackage* GetDataPackage()
    {
        return (DataPackage*)data.ptr;
    }
    void DeleteDataPackage()
    {
         delete (DataPackage*)data.ptr;
    }
};


class Network
{
private:
    int                         m_iListenSocket;                        //监听socket
    int                         m_iEpollCreateFd;                       //epoll的句柄
    EpollEvent                  m_sWait_event[MAX_COUNT];               //接收事件
    map<int,DataPackage*>       m_ConnectList;                          //用户连接列表
public:
    Network();
    virtual ~Network();
    //开始监听
    bool StartListen(unsigned short port, char*ip);
    //投递Accep
    bool DeliveryAccept();
    //投递Recv
    bool DeliveryRecv(DataPackage* pack);
    //断开连接
    bool Disconnect(EpollEvent* Wait_event);
protected:

private:
    //等待事件
    bool    WaitForTheEvent();
    //设置文件描述符为NonBlock
    bool    setNonBlock(int fd);
    //处理连接消息
    bool    HandleAccept();
    //处理接收消息
    bool    HandRecv(int i);
};

#endif // NETWORK_H

2.Network.cpp

#include "../include/Network.h"
#include<fcntl.h>
#include<unistd.h>
Network::Network()
{

}

Network::~Network()
{
    map<int,DataPackage*> ::iterator it=m_ConnectList.begin();
    for(;it!=m_ConnectList.end();)
    {
        if(it->second!=NULL)
           {
               it=m_ConnectList.erase(it);
               delete it->second;
           }
        else
           it++;
    }
}
bool Network::StartListen(unsigned short port, char* ip)
{
    //创建一个监听socket
    m_iListenSocket=socket(AF_INET,SOCK_STREAM,0);
    struct sockaddr_in server_addr;
    server_addr.sin_family=AF_INET;
    inet_pton(AF_INET,ip,&(server_addr.sin_addr));
   // server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    server_addr.sin_port=htons(port);
    int opt=1;
    setsockopt(m_iListenSocket, SOL_SOCKET,SO_REUSEADDR, (const void *) &opt, sizeof(opt));
    //将socket与ip端口绑定
    bind(m_iListenSocket,(struct sockaddr*)&server_addr,sizeof(server_addr));
    //创建一个套接口并监听连接
    listen(m_iListenSocket,100);
    //创建一个epoll句柄
    m_iEpollCreateFd=epoll_create(10);
    if(-1==m_iEpollCreateFd)
    {
        perror("创建文件描述符失败");
        return false;
    }
    //投递accept
    if(!DeliveryAccept())
        return false;

    WaitForTheEvent();
    return true;
}
//设置文件描述符为非阻塞
bool Network::setNonBlock(int fd)
{
   int flags = fcntl(fd, F_GETFL, 0);
   flags |= O_NONBLOCK;
   if(-1 == fcntl(fd, F_SETFL, flags))
   {
       return false;
   }
    return true;
}
bool Network::WaitForTheEvent()
{
    while(true)
    {
        //等待事件通知
       int clRet=epoll_wait(m_iEpollCreateFd,m_sWait_event,1,-1);
       for(int i=0;i<clRet;i++)
       {
           DataPackage* pack=m_sWait_event[i].GetDataPackage();
           switch(pack->EventType)
           {
           case  TYPE_ACP:
                {
                    HandleAccept();
                    break;
                }
           case TYPE_RECV:
                {
                    HandRecv(i);
                    break;
                }
           default:
                {
                   printf("m_sWait_event error\n");
                   break;
                }
           }
       }
    }
}
//投递Accep
bool Network::DeliveryAccept()
{
    //将socket绑定一个事件
    DataPackage* pack=new DataPackage;
    EpollEvent AcceptEvent(pack);
    pack->socket=m_iListenSocket;
    pack->EventType=TYPE_ACP;
    //设置为可读并且是边缘触发
    AcceptEvent.events=EPOLLIN|EPOLLET;
    //注册一个监听事件
    int clRet=epoll_ctl(m_iEpollCreateFd,EPOLL_CTL_ADD,pack->socket,&AcceptEvent);
    if(-1==clRet)
    {
        perror("注册监听事件类型失败");
        return false;
        AcceptEvent.DeleteDataPackage();
    }
    return true;
}
//投递Recv
bool Network::DeliveryRecv(DataPackage* pack)
{
    EpollEvent pData(pack);
    pData.events=EPOLLIN|EPOLLET;
    pack->EventType=TYPE_RECV;
    //注册一个事件
    int clRet=epoll_ctl(m_iEpollCreateFd,EPOLL_CTL_ADD,pack->socket,&pData);

    if( pack->socket<=0||-1==clRet||!setNonBlock( pack->socket))
    {
        perror("accept error:");
        close(pack->socket);
        pData.DeleteDataPackage();
        return false;
    }
    return true;
}
bool Network::Disconnect(EpollEvent* Wait_event)
{
    DataPackage * pack=Wait_event->GetDataPackage();
    int clRet=epoll_ctl(m_iEpollCreateFd,EPOLL_CTL_DEL,pack->socket,Wait_event);
    if(-1==clRet)
    {
         perror("Disconnect error:");
         return false;
    }
    printf("客户端下线\n");
    close(pack->socket);

    map<int,DataPackage*> ::iterator it=m_ConnectList.find(pack->socket);
    if(it!=m_ConnectList.end())
       m_ConnectList.erase(it);

    Wait_event->DeleteDataPackage();
    return true;
}
bool Network::HandleAccept()
{
    DataPackage* pack=new DataPackage;
    pack->socket=accept(m_iListenSocket,&pack->addr,&pack->length);
    //投递一个recv
    if(DeliveryRecv(pack))
    {
      //存入连接列表
      m_ConnectList.insert(make_pair(pack->socket,pack));
      return true;
    }

    return false;
}
bool Network::HandRecv(int i)
{
    DataPackage * pack=m_sWait_event[i].GetDataPackage();
    pack->ResetRecvBuffer();
    int len=recv(pack->socket,pack->RecvBuffer,sizeof(pack->RecvBuffer),0);
    if(len<=0)
    {
       return Disconnect(&m_sWait_event[i]);
    }
    else
    {
        printf("data:%s\n",pack->RecvBuffer);
    }
    return true;
}

C语言epoll方式实现简单socket实例 server.c #include #include #include #include #include #include #include #include #include #include #include #include #define MAX_FD_NUM 3 void setnonblock(int fd) { int flag = fcntl 阅读详情

相关推荐

epoll实现简单socket通信

epoll是常用的socket通信方式,相比于select和poll来说,效率提升了不止一点半点 其一:select中socket描述符(文件描述符)集的数据结构为数组,poll的文件描述符集数据结构为链表,无论数组还是链表,它们都是线性结构,当遍历时,也只能线性遍历;而epoll文件描述符集采用的红黑树(平衡二叉树的一个变体)的数据结构,红黑树的遍历则相比于线性遍历,效率要高很多。 其二:select和poll对文件描述符集先要拷贝到内核区,内核修改后再拷贝至用户区,要经过2次...

lj779323436的博客 1862

epoll实现消息服务器

epoll高效处理消息,通过epoll的level出发模式实现

【项目收获】epoll实现一个简单的聊天室

客户端功能 a.支持用户输入聊天消息 b.显示其他用户输入的信息 c.使用fork创建两个进程 子进程有两个功能: 等待用户输入聊天信息 将聊天信息写到管道(pipe),并发送给父进程 父进程有两个功能 使用epoll机制接受服务端发来的信息,并显示给用户,使用户看到其他用户的聊天信息 将子进程发给的聊天信息从管道(pipe)中读取, 并发送...

o小菜的博客 1085

epoll用法详解与编程实例

epoll中三个函数中的相关参数到底应该怎么使用?这篇epoll用法详解与编程实例文章将告诉你。

weixin_43354152的博客 4101

epoll原理及服务器代码实现

具有更好的性能和可伸缩性,特别适用于需要处理大量并发连接的场景,比如网络编程中的服务器。是 Linux 下用于实现高性能事件通知机制的系统调用。

leimeili的博客 658

服务器编程】EPOLL的LT和ET模式的区别和理解

【前言】 epoll模型是服务器编程的高性能框架,比select 和 poll模型高效很多,当然还有其它的模型,如kqueue等,具体linux发行版提供不同的模型,一般都支持epoll吧。 【理解】 epoll提供两种工作模式:LT 和 ET。 LT模式是epoll默认的工作方式,相当于一个效率很高的poll模型;而ET是高效的工作方式。 LT 和 ET本质的区别是:

依然那霖哥 2万+

linux网络编程 - epoll内核实现代码分析

linux网络编程epoll内核实现代码分析

arm7star的博客 1271

如何使用epoll?一个完整的C用例

网络服务器传统上是使用每个连接单独的进程或线程实现的。对于需要同时处理大量客户端的高性能应用程序,这种方法将无法正常工作,因为诸如资源使用和上下文切换时间等因素会影响一次处理多个客户端的能力。一种替代方法是在单个线程中执行非阻塞I / O,以及一些准备通知方法,它可以告诉您何时可以在套接字上读取或写入更多数据。本文介绍了Linuxepoll(7)工具,它是Linux中最好的准备通知工具。我们将在C

Amrf的博客 1136

C++封装一个Epoll类,实现epoll简单使用

#include <iostream> #include <vector> #include <sys/epoll.h> #include "tcpsocket.hpp" class Epoll { private: int _epfd; public: bool Init() { //创...

giturtle's blog 3486

Linuxepoll实现简单http服务器

Linuxepoll实现简单http服务器 main.c #include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h> #include <unistd.h> #include <stdlib.h> #in...

weixin_30664051的博客 277

linux epoll ET,LT和用epoll实现简单服务器

LT(Level_triggered 水平触发): 当被监控的文件描述符上有可读写事件发生时,epoll_wait()会通知处理程序去读写。如果这次没有把数据一次性全部读写完(如读写缓冲区太小), 那么下次调用epoll_wait()时,它还会通知你在上没读写完的文件描述符上继续读写,当然如果你一直不去读写,它会一直通知你!!!如果系统中有大量你不需要读写的就绪文件描述符, 而它们每次都返回这...

陌上花开缓缓归以的博客 287

epoll实现简单echo服务器

好久没写过博客了,之前写博客纯属是为了记录,防止再遇到同样的问题一时想不起来,可以查查博客。然后发现印象笔记好像挺好用,然后就懒得写博客了。。。 最近感觉心态变了,写博客当自己学习过程的分享吧。 这篇博客内容不深,甚至是烂大街的东西,纯属是表达一下我学习的思路,希望可以给和我一样的新手一些学习的思路,写的不好的也请勿喷,谢谢epoll的概念,还有什么与select、poll等的区别,优缺点,请自

官工耍大刀 775

linuxEpoll实现简单的C/S通信

linuxEpoll实现简单的C/S通信 epoll的优点: 1.支持一个进程打开大数目的socket描述符(FD)     select 最不能忍受的是一个进程所打开的FD是有一定限制的,由FD_SETSIZE设置,默认值是2048。对于那些需要支持的上万连接数目的IM服务器来说显然太少了。这时候你一是可以选择修改这个宏然后重新编译内核,不过资料也同时指出这样会带来网

人生代码,代码人生。。。 1204

epoll 实现简单聊天程序代码示例

epoll 实现简单聊天程序代码示例c代码实现,可以运行提示:以下是本篇文章正文内容,下面案例可供参考epoll 实现简单聊天程序c代码示例,stdin输入发送到cli端,代码可以运行,仅供参考。

qq_37077309的博客 825

epoll文件服务器,基于epoll实现的一个简单的web服务器

详解1EPOLLIN:文件描述符可以读EPOLLOUT:文件描述符可以写EPOLLPRI:文件描述符有紧急的数据可写EPOLLERR:文件描述符发生错误EPOLLHUP:文件描述符被挂起EPOLLET: 文件描述符有事件发生所用到的函数:1、int epoll_create(int size)该函数生成一个epoll专用的文件描述符,其中的参数是指定生成描述符的最大范围(在我们做网络开发中应该是可...

weixin_36285931的博客 800

python socket epoll_python 实现一个简单tcp epoll socket

python 实现一个epollserver#!/usr/bin/env python#-*- coding:utf-8 -*-import socketimport selectimport Queue#创建socket对象serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)#设置IP地址复用serversocket.s...

weixin_39938746的博客 230

简单说说线程池与epoll模型的实现

(1)server/main.cpp/main 进入主函数,先创建一个主线程,阻塞等待其结束,转到workThread。 int main(int argc, char **argv) { ... int ret = pthread_create(&workPid, NULL, workThread, NULL); pthread_join(workPid, NULL); ... } (2)server/main.cpp/workThread global:进程级的全局变量,用于net。

pourtheworld的博客 529

epoll实现简单服务器

回顾I/O复用之epoll epoll相比于select、poll还是有很多优点,在此重温一下epoll 如有错误,欢迎指正 #define _GNU_SOURCE_ //使用EPOLLRDHUP的代价 #include<stdio.h> #include<stdlib.h> #include<string.h> #include<unistd.h> #include<assert.h> #include<sys/types.h>

weixin_44843710的博客 324
上一篇: websocket+iocp的实现
下一篇: 模仿COM架构+源码
IT小狼狗
博客等级 码龄11年 57粉丝 22原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值