网络库功能介绍
网络库具有的功能
1.具备多线程
2.监听某个端口
3.连接远程服务器
4.保存并管理所有链接,外部与网络库操作通过链接ID
5.向某个连接发送数据
6.强制关闭某个链接
7.网络事件回掉:connect, receive, close
8.错误处理
网络库主要接口(文件:tcp_frame.h)
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;
};
网络库使用示例
1.EchoServer
服务器代码:
#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;
}
参考