标签:
1.具备多线程
2.监听某个端口
3.连接远程服务器
4.保存并管理所有链接,外部与网络库操作通过链接ID
5.向某个连接发送数据
6.强制关闭某个链接
7.网络事件回掉:connect, receive, close
8.错误处理
class tcp_frame { public: /** * tcp_frame 构造函数 * @handler 网络事件回掉(connect, recevie, close) * @net_thread_num 网络线程数量 * 注意:如果开启了多个网络线程,那么handler 回掉函数是非线程安全的。参见 * broker::on_net_message ,里面使用了加锁队列 */ tcp_frame(const net_message_hander& handler, uint8_t net_thread_num = 1); ~tcp_frame(); /** * 监听某个端口 * @listenAddress ip地址或者域名 * @listenPort 端口 */ void listen(const std::string& ip, const std::string& port, module_id moduleid); /** * 连接某个端口 * @ip ip地址或者域名 * @port 端口 * @moduleid 模块标识符,一般情况下网络库是作为某个模块的一部分 参考 broker的实现。 * 网络事件会以消息(message)的形式,插入到模块的消息队列中. */ void connect(const std::string& ip, const std::string& port, module_id moduleid); /** * 向某个链接发送数据 * @sockid 连接标识 * @data 数据 */ void send(socket_id sockid, const buffer_ptr& data); /** * 关闭一个链接 * @sockid 连接标识 * @state 给链接设置一个状态,表明为什么关闭(例如 超时,发送非法数据) */ void close_socket(socket_id sockid, ESocketState state); /** * 启动网络库 */ void run(); /** * 停止网络库 */ void stop(); /** * 获取错误码 */ int getErrorCode(); /** * 获取错误信息 */ std::string getErrorMessage(); /** * 设置管理链接的超时检测 * @timeout 超时时间 ,单位 ms * @checkInterval 超时检测间隔,单位 ms */ void setTimeout(uint32_t timeout, uint32_t checkInterval); protected: /** * 投递异步accept,接受网络连接 */ void postAccept(); /** * 超时检测线程函数 */ void checkTimeOut(uint32_t interval); protected: struct Imp; std::shared_ptr<Imp> _Imp; net_message_hander _hander; };
#pragma once #include <common/noncopyable.hpp> #include <tcp_frame.h> #include <message.h> #include <buffer_reader.h> #include <string> #include <iostream> #include <functional> using namespace moon; class EchoServer :noncopyable { public: EchoServer() { } ~EchoServer() { if (m_Net != nullptr) { //关闭网络线程 m_Net->stop(); } } void Start() { auto handler = std::bind(&EchoServer::OnNetMessage, this, std::placeholders::_1); m_Net = std::make_shared<tcp_frame>(handler,2);//2条网络线程 //监听本机的 11111 端口,由于此处只是用网络库,不关心模块,模块ID为0 即可 m_Net->listen("127.0.0.1", "11111", module_id::create(0)); //启动网络线程 m_Net->run(); //正常情况下 应该阻塞主线程,防止主线程退出。由于稍后客户端会运行在主线程内,不再阻塞主线程 } private: void OnNetMessage(const message& msg) { switch (msg.get_type()) { case EMessageType::SocketConnect: { //连接,消息内容默认为远程主机地址 buffer_reader br(msg.data(), msg.size()); std::string addr; br >> addr; std::cout <<"SERVER:client connect "<<addr<< std::endl; break; } case EMessageType::SocketData: { //收到数据,message 保存有发送者和接收者的ID. //如果是网络消息,那么发送者为网络连接ID //获取网络连接ID auto sockID = msg.get_socket_id(); buffer_reader br(msg.data(), msg.size()); //获取发来的信息 std::string clientMsg; br >> clientMsg; //把信息发送回去 (echoMsg是智能指针,方便多线程之间内存管理) auto echoMsg = buffer::create(clientMsg.size() + 1); (*echoMsg) << clientMsg; m_Net->send(sockID, echoMsg); std::cout << "SERVER:echo msg " << clientMsg << std::endl; break; } case EMessageType::SocketClose: { //断开 buffer_reader br(msg.data(), msg.size()); std::string addr; br >> addr; std::cout << "SERVER:client close " << addr << std::endl; break; } default: break; } } private: std::shared_ptr<tcp_frame> m_Net; };
#pragma once #include <common/noncopyable.hpp> #include <tcp_frame.h> #include <message.h> #include <buffer_reader.h> #include <string> #include <iostream> #include <functional> using namespace moon; class EchoClient { public: void Start() { auto handler = std::bind(&EchoClient::OnNetMessage, this, std::placeholders::_1); m_Net = std::make_shared<tcp_frame>(handler, 1);//1条网络线程 //连接本机的 11111 端口,由于此处只是用网络库,不关心模块,模块ID为0 即可 auto id = m_Net->sync_connect("127.0.0.1", "11111", module_id::create(0)); if (id.value == 0) { std::cout << "CLIENT : connect server failed" << std::endl; return; } //启动网络线程 m_Net->run(); std::string str; std::cin >> str; while (str != "exit") { std::cout << "CLIENT:send msg " <<str<< std::endl; auto msg = buffer::create(str.size() + 1); (*msg) << str; m_Net->send(id, msg); std::cin >> str; } m_Net->stop(); } private: void OnNetMessage(const message& msg) { switch (msg.get_type()) { case EMessageType::SocketConnect: { buffer_reader br(msg.data(), msg.size()); std::string addr; br >> addr; std::cout << "CLIENT:connect server:" << addr << std::endl; break; } case EMessageType::SocketData: { //获取网络连接ID auto sockID = msg.get_socket_id(); buffer_reader br(msg.data(), msg.size()); //获取发来的信息 std::string clientMsg; br >> clientMsg; std::cout << "CLIENT:recv msg " << clientMsg << std::endl; break; break; } case EMessageType::SocketClose: { //断开,消息内容默认为客户端地址 buffer_reader br(msg.data(), msg.size()); std::string addr; br >> addr; std::cout << "CLIENT:server close " << addr << std::endl; break; } default: break; } } private: std::shared_ptr<tcp_frame> m_Net; };
使用示例
#include "EchoClient.hpp" #include "EchoServer.hpp" int main() { EchoServer svr; svr.Start(); EchoClient cl; cl.Start(); return 0; }
标签:
原文地址:http://blog.csdn.net/greatchina01/article/details/51982860