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 ...
随机推荐
- 5 Things You Should Know About the New Maxwell GPU Architecture
The introduction this week of NVIDIA’s first-generation “Maxwell” GPUs is a very exciting moment for ...
- case编写的httpd简单启停脚本
case编写的httpd简单启停脚本 #!/bin/bash HTTPD="/etc/init.d/httpd" . /etc/init.d/functions case &quo ...
- winrm service
今天看脚本忽然发现一个服务,叫winRM服务,这是个PowerShell的远程管理.开启它可以很大程度的方便用PowerShell操控! 下面是我找到的一些资料: 在Linux中,我们可以使用安全的S ...
- hihoCoder#1079(线段树+坐标离散化)
时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 小Hi和小Ho在回国之后,重新过起了朝7晚5的学生生活,当然了,他们还是在一直学习着各种算法~ 这天小Hi和小Ho所在的学 ...
- postgresql 数据库,模式,表空间的关系
数据库与模式模式(schema)是对数据库(database)逻辑分割在数据库创建的同时,就已经默认为数据库创建了一个模式--public,这也是该数据库的默认模式.所有为此数据库创建的对象(表.函数 ...
- Redis 集群之 Redis-Cluster
Redis集群官方推荐方案 Redis-Cluster 集群 redis cluster 通过分片实࣫容量扩展 通过主从复制实࣫节点的高可用 节点之间互相通信 每个节点都维护整个集群的节点信息 red ...
- 反向索引(Inverted Index)
转自:http://zhangyu8374.iteye.com/blog/86307 反向索引是一种索引结构,它存储了单词与单词自身在一个或多个文档中所在位置之间的映射.反向索引通常利用关联数组实现. ...
- vsftp部署和优化错误
ftp登录失败 vim /etc/vsftpd/vsftpd.conf 添加虚拟机配置的时候有空行,删除空行解决
- js闭包(二)
一.何谓“闭包”? 所谓“闭包(Closure)”,指的是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分. 描述的如此学术的官方解释,相信很少人能够 ...
- 2018多校第九场1004(HDU 6415) DP
本以为是个找规律的题一直没找出来... 题目:给你一个n*m的矩阵和1-n*m个数,问有多少种情况满足纳什均衡的点只有一个.纳什均衡点是指这个元素在所在行和所在列都是最大的. 思路:吉老师直播的思路: ...