多线程游戏服务器开发(2)-编写网络库
来源:互联网 发布:平面设计软件知乎 编辑:程序博客网 时间:2024/06/16 08:49
网络库功能介绍
网络库具有的功能
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 端口*/voidlisten(const std::string& ip, const std::string& port, module_id moduleid);/*** 连接某个端口* @ip ip地址或者域名* @port 端口* @moduleid 模块标识符,一般情况下网络库是作为某个模块的一部分 参考 broker的实现。*网络事件会以消息(message)的形式,插入到模块的消息队列中.*/voidconnect(const std::string& ip, const std::string& port, module_id moduleid);/*** 向某个链接发送数据* @sockid 连接标识* @data 数据*/voidsend(socket_id sockid, const buffer_ptr& data);/*** 关闭一个链接* @sockid 连接标识* @state 给链接设置一个状态,表明为什么关闭(例如 超时,发送非法数据)*/voidclose_socket(socket_id sockid, ESocketState state);/*** 启动网络库*/voidrun();/*** 停止网络库*/voidstop();/*** 获取错误码*/intgetErrorCode();/*** 获取错误信息*/std::stringgetErrorMessage();/*** 设置管理链接的超时检测* @timeout 超时时间 ,单位 ms* @checkInterval 超时检测间隔,单位 ms*/voidsetTimeout(uint32_t timeout, uint32_t checkInterval);protected:/*** 投递异步accept,接受网络连接*/voidpostAccept();/*** 超时检测线程函数*/voidcheckTimeOut(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//获取网络连接IDauto 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:{//获取网络连接IDauto 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;}
示例地址:点击打开链接
2 0
- 多线程游戏服务器开发(2)-编写网络库
- 多线程游戏服务器开发(1)-简介
- MMORPG大型游戏设计与开发(服务器 游戏场景 多线程)
- vc socket 多线程 (记录一次自己调用window 底层API编写 vc socket 多线程的服务器网络程序)
- 多进程多线程服务器(tcp_server)编写
- 多线程游戏服务器技术开发
- Python游戏服务器开发日记(二)绕过GIL启动多线程Python环境
- c++ 编写自己的小型游戏开发库(续)
- Go游戏服务器开发的一些思考(八):Docker桥接网络及固定IP
- 【Qt5开发及实例】33、多线程网络时间服务器
- iOS多线程与网络开发之发送接收服务器信息
- Java编写网络打字游戏
- 编写简单多线程web服务器
- 多进程多线程服务器编写
- c++多线程编写网络聊天室程序(socket)
- c++多线程编写网络聊天室程序(socket)
- 游戏服务器开发法则(一)
- 游戏服务器开发法则(二)
- Android画一条虚线
- performSelector 那点事
- GreenDao的简单使用说明(五)多表n:m
- C#中的排序
- tableviewcell 2级折叠
- 多线程游戏服务器开发(2)-编写网络库
- 排序——希尔排序
- private public protected slots的区别
- Dynamics CRM 导出系统中实体的属性字段到EXCEL
- 查看系统版本信息
- Newtonsoft.Json序列化字符串-格式化和时间格式问题
- 接口的意义
- Quartz 框架快速入门(四)
- 西蒙iphone-OpenGL ES 教程-04 : 颜色及纹理