一、epoll模型的构建

由于网络服务高并发的需求,一般socket网络模型都采用epoll模型,有关epoll模型的原理在相关论坛中有许多讲述,在此不做重复讲解,主要讲一讲epoll模型的封装实现。

EPoller类的具体实现如下代码所示:

class EPoller
{
public: int Create(int maxfd);
void JoinSocket(Socket* sock, unsigned int flag);
void DelSocket(CEpollSocket* sock);
int LoopForEvent(int timeout);
int EpollWait(int timeout);
protected:
int epoll_fd; //epoll文件描述符
epoll_event* p_events; //用于保存epoll_wait返回的事件
int max_fd; //最大监听的文件描述符数量 }; // 创建epoll模型
int EPoller::Create(int maxfd)
{
max_fd = maxfd ;
epoll_fd = epoll_create(maxfd); p_events = new epoll_event[maxfd];
memset(p_events, , sizeof(epoll_event) * maxfd);
return ;
} //将某个fd添加至监听的队列中,并利用flag设置监听的事件类型
//其中Socket为基类
int EPoller::JoinSocket(Socket* sock, unsigned int flag)
{
int fd = sock->GetSockHandle();
epoll_event event;
event.data.ptr = sock;
event.events = flag|EPOLLHUP|EPOLLERR; if (epoll_ctl(_epoll_fd, EPOLL_CTL_MOD , fd, &ev) < )
{
if (epoll_ctl(_epoll_fd, EPOLL_CTL_ADD , fd, &ev) < )
{
return -;
}
} return ;
} //删除指定的fd
int EPoller::DelSocket(Socket* sock)
{
int fd = sock->GetSockHandle();//利用Socket对象取得相应的文件句柄
if ( fd > )
{
epoll_event ev;
ev.data.ptr = sock;
ev.events = ;
if (epoll_ctl(_epoll_fd, EPOLL_CTL_DEL, fd, &ev) < )
{
return -;
} return ;
} return -;
} //等待监控的事件触发
int EPoller::EpollWait(int timeout)
{
int fd;
int nfds;
Socket* sock;
unsigned int flag; nfds = epoll_wait(epoll_fd, p_events, max_fd, timeout);
if (nfds < )
{
return -;
}
else if ( nfds == )
{
return ;
} for (int i=; i<nfds; i++)
{
sock = (Socket*)((p_events+i)->data.ptr);
if ( sock == NULL )
{
continue;
}
flag = (p_events+i)->events;
if (flag & EPOLLIN)
{
sock->Recv();
}
else if (flag & EPOLLOUT)
{
sock->Send();
}
else if (flag & EPOLLHUP)
{
sock->Close();
}
else if (flag & EPOLLERR)
{
sock->Error();
}
} return nfds ;
}
// 循环等待事件的触发
int EPoller::LoopForEvent(int timeout)
{
while(true)
{
int result = EpollWait(timeout);
if( result <= )
{
return result;
}
}
}

其中的Socket类型作为其他网络通信服务类的基类,主要为其他的socket网络通信类提供一个统一的入口,其结构定义如下:

class Socket
{
friend class EPoller;
public:
int GetSockHandle();
virtual int SendMsg(char* buffer, int length); protected:
virtual int Recv();
virtual int Send();
virtual int Close();
virtual int Error(); EPoller* epoller;
int fd; } int Socket::SendMsg(char* buff, int len)
{
  int ret;
  int send_len = 0;
  int _len = len;
  errno = 0;
  while(_len > 0)
  {
    ret = send(fd, (void*)(buff+send_len), _len, 0);
    if (ret <= 0)
    {
      if (errno == EINTR || errno == EAGAIN)
      {
        usleep(10);
        continue;
      }
      break;
    }
    send_len += ret;
    _len -= ret;
  }
  return send_len;
}

二、UDP网络通信的实现

//Udp创建socket的流程
int CreateUdpSocket()
{
// 1.创建socket
sock_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); // 2.设置非阻塞
fcntl(sock_fd, F_GETFL, );
fcntl(sock_fd, F_SETFL, val | O_NONBLOCK); // 3.绑定端口与ip
struct sockaddr_in addr;
string ip = "0.0.0.0";
addr.sin_family = AF_INET;
addr.sin_port = htons();
ip2uint(ip.c_str(), &(addr.sin_addr));
bind(sock_fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)); // 4.设置socket缓存大小
int recv_buf_size = ;
int send_buf_size = ;
setsockopt(sock_fd, SOL_SOCKET, SO_RCVBUF, (char *)&recv_buf_size, sizeof(recv_buf_size));
setsockopt(sock_fd, SOL_SOCKET, SO_SNDBUF, (char *)&send_buf_size, sizeof(send_buf_size));
return ;
} // 接收数据
if ((len = recvfrom(sock, buffer, len, , (struct sockaddr *)&addr, &addrlen)) < )
{
if (errno == EAGAIN || errno == EINTR)
{
len = ;
return ;
}
else
{
return -;
}
}

三、TCP网络通信的实现

//Tcp创建
bool CreateTcpServer()
{
//建立TCP套接字
sock_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); struct sockaddr_in svr_addr= {};
svr_addr.sin_port = htons(port);
svr_addr.sin_family = AF_INET;
inet_pton(AF_INET, ip.c_str(), &(svr_addr.sin_addr)); // 绑定ip地址
if(bind(sock_fd, (struct sockaddr*)&svr_addr, sizeof(struct sockaddr_in)) < ) // 设置socket属性
int recv_buf_size = * ;
int send_buf_size = * ;
if (setsockopt(_sock_fd, SOL_SOCKET, SO_RCVBUF, (char*)&recv_buf_size, sizeof(recv_buf_size)) < )
if(setsockopt(_sock_fd, SOL_SOCKET, SO_SNDBUF, (char*)&send_buf_size, sizeof(send_buf_size)) < )
int reuse=;
if(setsockopt(_sock_fd, SOL_SOCKET, SO_REUSEADDR, (char*)&reuse, sizeof(reuse)) < ) // 设置非阻塞
int val = fcntl(_sock_fd, F_GETFL, );
if(fcntl(_sock_fd, F_SETFL, val | O_NONBLOCK) == -) // 监听socket
if(listen(sock_fd,) < )
{
close(sock_fd);
sock_fd = -;
return false;
}
return true ;
}
// 一种hash值的生成算法
int string2hash(const char * str, const int& len, const int& hash_size)
{
int hashvalue = ;
for (int i = len-; i < len; ++i)
{
hashvalue = ((unsigned char)(*(str + i)) + hashvalue) % hash_size;
}
return hashvalue;
} //接收数据流程
int TCP_recv()
{
char recv_buff[];
int total_recv_len = ; int clientfd = accept(_sock_fd,(struct sockaddr *)NULL,(socklen_t*)NULL);
if (clientfd <= )
{
return -;
} //设置发送缓冲区和接收缓冲区大小
int send_buff_size = ;
int recv_buff_size = ;
int set_result = ;
set_result = setsockopt(clientfd, SOL_SOCKET, SO_RCVBUF, (char*)&recv_buff_size, sizeof(recv_buff_size));
set_result = setsockopt(clientfd, SOL_SOCKET, SO_SNDBUF, (char*)&send_buff_size, sizeof(send_buff_size)); int free_len = sizeof(recv_buff) - total_recv_len ;
if(free_len <= || total_recv_len >= )
{
//包太长了
return ;
} //接收数据
int recv_len = ;
do
{
recv_len = recv(sock_fd, &recv_buff[total_recv_len], free_len, );
}
while((recv_len < ) && (errno == EINTR)); if(recv_len <= )
{
// 对端连接关闭
if( recv_len == )
{
return ;
}
else if( errno == EAGAIN)
{
//暂时阻塞
return ;
}
else
{
return ;
}
} total_recv_len += recv_len;
// 解析命令
int offset = ParseCmd(recv_buff, total_recv_len);
if( == offset)
{
//未接收完
return ;
}
// 完成解析后,将已处理后的数据清空,使留下的未处理数据移到缓存区的起始位置。
else if( < offset)
{
//解析成功,单条命令
total_recv_len = total_recv_len - offset;
memmove(recv_buff, recv_buff + offset, total_recv_len);
} return ; } // 与服务端建立socket长连接的方法
int fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
int recv_buf_size = ;
int send_buf_size = ; setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (char *)&recv_buf_size, sizeof(recv_buf_size));
setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (char *)&send_buf_size, sizeof(send_buf_size)); struct sockaddr_in addr;
memset(&addr, , sizeof(struct sockaddr_in));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = inet_addr(ip.c_str()); int argc = fcntl(fd, F_GETFL, );
if (fcntl(fd, F_SETFL, argc | O_NONBLOCK) == -)
{
close(fd);
return false;
} int ret = connect(fd, (struct sockaddr *)&addr, sizeof(addr));
if ( > ret)
{
bool bConnected = false; struct pollfd conncet_client[];
int _nfd = ;
memset(&_conncet_client[], , sizeof(pollfd));
conncet_client[].fd = fd;
conncet_client[].events = POLLOUT; int can_write = ::poll(_conncet_client, _nfd, (int)());
if (can_write > && (_conncet_client[].revents & POLLOUT) > )
{
bConnected = true;
}
}

socket网络服务实战的更多相关文章

  1. 【linux高级程序设计】(第十三章)Linux Socket网络编程基础 4

    网络调试工具 tcpdump 功能:打印指定网络接口中与布尔表达式匹配的报头信息 关键字: ①类型:host(默认).net.port host 210.27.48.2 //指明是一台主机 net 2 ...

  2. Socket网络编程(2)--服务端实现

    中秋了,首先祝大家中秋快乐,闲着无事在家整一个socket的聊天程序,有点仿QQ界面,就是瞎折腾,不知道最后是不是能将所有功能实现. 如果你对socket不了解,请看这篇文章:http://www.c ...

  3. keepalived安装配置实战心得(实现高可用保证网络服务不间断)

    keepalived安装配置实战心得(实现高可用保证网络服务不间断) 一.准备2台虚拟机     安装的系统是:centos-release-7-1.1503.el7.centos.2.8.x86_6 ...

  4. socket 网络编程高速入门(一)教你编写基于UDP/TCP的服务(client)通信

    由于UNIX和Win的socket大同小异,为了方便和大众化,这里先介绍Winsock编程. socket 网络编程的难点在入门的时候就是对基本函数的了解和使用,由于这些函数的结构往往比較复杂,參数大 ...

  5. Socket网络编程-SocketServer

    Socket网络编程-SocketServer 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.SocketServer概述 socket编程过于底层,编程虽然有套路,但是想要写 ...

  6. Socket网络编程-TCP编程

    Socket网络编程-TCP编程 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.socket介绍 1>.TCP/IP协议 2>.跨网络的主机间通讯 在建立通信连接的 ...

  7. SSH远程管理服务实战

    目录 SSH远程管理服务实战 1.SSH基本概述 2.SSH相关命令 3.Xshell连接不上虚拟机 4.scp命令 5.sftp命令 6.SSH验证方式 7.SSH场景实践 8.SH安全优化 9.交 ...

  8. Linux Socket 网络编程

    Linux下的网络编程指的是socket套接字编程,入门比较简单.在学校里学过一些皮毛,平时就是自学玩,没有见识过真正的socket编程大程序,比较遗憾.总感觉每次看的时候都有收获,但是每次看完了之后 ...

  9. Python Socket 网络编程

    Socket 是进程间通信的一种方式,它与其他进程间通信的一个主要不同是:它能实现不同主机间的进程间通信,我们网络上各种各样的服务大多都是基于 Socket 来完成通信的,例如我们每天浏览网页.QQ ...

随机推荐

  1. 基于 WebSocket 的 MQTT 移动推送方案

    WebSphere MQ Telemetry Transport 简介 WebSphere MQ Telemetry Transport (MQTT) 是一项异步消息传输协议,是 IBM 在分析了他们 ...

  2. 机器学习:SVM(SVM 思想解决回归问题)

    一.SVM 思想在解决回归问题上的体现 回归问题的本质:找到一条直线或者曲线,最大程度的拟合数据点: 怎么定义拟合,是不同回归算法的关键差异: 线性回归定义拟合方式:让所有数据点到直线的 MSE 的值 ...

  3. Modules:template

    ylbtech-Modules: 1.返回顶部 1.   2. 2.返回顶部   3.返回顶部   4.返回顶部   5.返回顶部     6.返回顶部   7.返回顶部   8.返回顶部   9.返 ...

  4. Adobe Flash 无法正常使用

    如果 Adobe Flash 无法正常使用,或者您看到以下错误消息,请尝试按照下文介绍的问题排查步骤操作. Adobe Flash 版本太旧,因此已被屏蔽无法加载插件该网页已屏蔽以下插件如果您使用的是 ...

  5. 使用like查询text类型字段

    使用like查询text类型字段 public bool Exists(GetReadType GRT, ClientMessageGetRead TypeID, string MessageID, ...

  6. 问题:oracle long 与 clob;结果:long类型比clob到底差在什么地方?

    long类型比clob到底差在什经常看到9i以上的文档,说以后 clob会逐步取代long,一直想不出, 而我在8.1.7上也测试2个字段好像 在存储上也看不出什么区别?么地方? 差别还是很大的, 比 ...

  7. GCD详细介绍

    (1)是基于C语言的底层API (2)用Block定义任务,使用起来非常灵活便捷 (3)提供了更多的控制能力以及操作队列中所不能使用的底层函数 小结 说明:同步函数不具备开启线程的能力,无论是什么队列 ...

  8. mahout in Action2.2-给用户推荐图书(1)-直观分析和代码

    This chapter covers  What recommenders are, within Mahout  A first look at a recommender in action ...

  9. struts2学习笔记(3)struts.xml的一些常用设置

    在开发中通常需要用到多个配置文件,可以通过在web.xml中添加以下代码: <include file="login.xml"></include> 将sr ...

  10. 玩转Jquery

    一 jquery简介 1 jquery是什么 jQuery由美国人John Resig创建,至今已吸引了来自世界各地的众多 javascript高手加入其team. jQuery是继prototype ...