socket网络服务实战
一、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网络服务实战的更多相关文章
- 【linux高级程序设计】(第十三章)Linux Socket网络编程基础 4
网络调试工具 tcpdump 功能:打印指定网络接口中与布尔表达式匹配的报头信息 关键字: ①类型:host(默认).net.port host 210.27.48.2 //指明是一台主机 net 2 ...
- Socket网络编程(2)--服务端实现
中秋了,首先祝大家中秋快乐,闲着无事在家整一个socket的聊天程序,有点仿QQ界面,就是瞎折腾,不知道最后是不是能将所有功能实现. 如果你对socket不了解,请看这篇文章:http://www.c ...
- keepalived安装配置实战心得(实现高可用保证网络服务不间断)
keepalived安装配置实战心得(实现高可用保证网络服务不间断) 一.准备2台虚拟机 安装的系统是:centos-release-7-1.1503.el7.centos.2.8.x86_6 ...
- socket 网络编程高速入门(一)教你编写基于UDP/TCP的服务(client)通信
由于UNIX和Win的socket大同小异,为了方便和大众化,这里先介绍Winsock编程. socket 网络编程的难点在入门的时候就是对基本函数的了解和使用,由于这些函数的结构往往比較复杂,參数大 ...
- Socket网络编程-SocketServer
Socket网络编程-SocketServer 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.SocketServer概述 socket编程过于底层,编程虽然有套路,但是想要写 ...
- Socket网络编程-TCP编程
Socket网络编程-TCP编程 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.socket介绍 1>.TCP/IP协议 2>.跨网络的主机间通讯 在建立通信连接的 ...
- SSH远程管理服务实战
目录 SSH远程管理服务实战 1.SSH基本概述 2.SSH相关命令 3.Xshell连接不上虚拟机 4.scp命令 5.sftp命令 6.SSH验证方式 7.SSH场景实践 8.SH安全优化 9.交 ...
- Linux Socket 网络编程
Linux下的网络编程指的是socket套接字编程,入门比较简单.在学校里学过一些皮毛,平时就是自学玩,没有见识过真正的socket编程大程序,比较遗憾.总感觉每次看的时候都有收获,但是每次看完了之后 ...
- Python Socket 网络编程
Socket 是进程间通信的一种方式,它与其他进程间通信的一个主要不同是:它能实现不同主机间的进程间通信,我们网络上各种各样的服务大多都是基于 Socket 来完成通信的,例如我们每天浏览网页.QQ ...
随机推荐
- 基于 WebSocket 的 MQTT 移动推送方案
WebSphere MQ Telemetry Transport 简介 WebSphere MQ Telemetry Transport (MQTT) 是一项异步消息传输协议,是 IBM 在分析了他们 ...
- 机器学习:SVM(SVM 思想解决回归问题)
一.SVM 思想在解决回归问题上的体现 回归问题的本质:找到一条直线或者曲线,最大程度的拟合数据点: 怎么定义拟合,是不同回归算法的关键差异: 线性回归定义拟合方式:让所有数据点到直线的 MSE 的值 ...
- Modules:template
ylbtech-Modules: 1.返回顶部 1. 2. 2.返回顶部 3.返回顶部 4.返回顶部 5.返回顶部 6.返回顶部 7.返回顶部 8.返回顶部 9.返 ...
- Adobe Flash 无法正常使用
如果 Adobe Flash 无法正常使用,或者您看到以下错误消息,请尝试按照下文介绍的问题排查步骤操作. Adobe Flash 版本太旧,因此已被屏蔽无法加载插件该网页已屏蔽以下插件如果您使用的是 ...
- 使用like查询text类型字段
使用like查询text类型字段 public bool Exists(GetReadType GRT, ClientMessageGetRead TypeID, string MessageID, ...
- 问题:oracle long 与 clob;结果:long类型比clob到底差在什么地方?
long类型比clob到底差在什经常看到9i以上的文档,说以后 clob会逐步取代long,一直想不出, 而我在8.1.7上也测试2个字段好像 在存储上也看不出什么区别?么地方? 差别还是很大的, 比 ...
- GCD详细介绍
(1)是基于C语言的底层API (2)用Block定义任务,使用起来非常灵活便捷 (3)提供了更多的控制能力以及操作队列中所不能使用的底层函数 小结 说明:同步函数不具备开启线程的能力,无论是什么队列 ...
- mahout in Action2.2-给用户推荐图书(1)-直观分析和代码
This chapter covers What recommenders are, within Mahout A first look at a recommender in action ...
- struts2学习笔记(3)struts.xml的一些常用设置
在开发中通常需要用到多个配置文件,可以通过在web.xml中添加以下代码: <include file="login.xml"></include> 将sr ...
- 玩转Jquery
一 jquery简介 1 jquery是什么 jQuery由美国人John Resig创建,至今已吸引了来自世界各地的众多 javascript高手加入其team. jQuery是继prototype ...