如果你是偶然浏览到这里,请先看 C/S框架 st_asio_wrapper 开发教程(一)
源代码及例程下载地址:
git:https://github.com/youngwolf-project/st_asio_wrapper/。
QQ交流群:198941541
六:开发教程(服务端)
服务端直接#include ext/tcp.h,就可实现一个简单的服务端了,如下(还演示了一个echo服务器,代码未列出):
//configuration
#define ST_ASIO_SERVER_PORT 9527
#define ST_ASIO_REUSE_OBJECT //use objects pool
#define ST_ASIO_ENHANCED_STABILITY
//configuration
#include "../include/ext/tcp.h"
using namespace st_asio_wrapper;
using namespace st_asio_wrapper::tcp;
using namespace st_asio_wrapper::ext;
using namespace st_asio_wrapper::ext::tcp;
#define QUIT_COMMAND "quit"
#define RESTART_COMMAND "restart"
#define LIST_ALL_CLIENT "list_all_client"
#define LIST_STATUS "status"
int main(int argc, const char* argv[])
{
service_pump sp;
server server_(sp);
if (argc > 3)
server_.set_server_addr(atoi(argv[2]) + 100, argv[3]);
else if (argc > 2)
server_.set_server_addr(atoi(argv[2]) + 100);
else
server_.set_server_addr(ST_ASIO_SERVER_PORT + 100);
int thread_num = 1;
if (argc > 1)
thread_num = std::min(16, std::max(thread_num, atoi(argv[1])));
sp.start_service(thread_num);
while(sp.is_running())
{
std::string str;
std::cin >> str;
if (QUIT_COMMAND == str)
sp.stop_service();
else if (RESTART_COMMAND == str)
{
sp.stop_service();
sp.start_service(thread_num);
}
else if (LIST_STATUS == str)
printf("normal server, link #: " ST_ASIO_SF ", invalid links: " ST_ASIO_SF "\n", server_.size(), server_.invalid_object_size());
else
{
//broadcast series functions call pack_msg for each client respectively, because clients may used different protocols(so different type of packers, of course)
server_.broadcast_msg(str.data(), str.size() + 1, false);
//send \0 character too, because demo client used basic_buffer as its msg type, it will not append \0 character automatically as std::string does,
//so need \0 character when printing it.
}
}
return 0;
}
以上例子中,服务端从控制台接收数据,然后广播数据;当收到数据时,server会输出到控制台(st_asio_wrapper::socket实现);
其中server server_;这行申请了一个普通的服务端,它的功能仅仅是接受连接,发送接收消息等。一般来说,需要从server_socket_base继承一个自己的套接字类,从server继承一个服务类。为此,服务端demo还演示了一个echo服务器(代码未列出),它会把收到的任何数据发送回去(大家可以学着做一个echo客户端,但不要echo服务端与echo客户端一同工作,否则就死循环了。
start_service开启服务,stop_service结束服务(退出时必须明确调用),is_running判断服务的运行状态;如果想修改服务端地址,则在调用start_service之前调用set_server_addr函数;
stop_service之后,可再次调用start_service开启服务;
注意:server_base的del_socket一般用于服务端被动删除某条连接(即在错误发生的时候,比如在tcp::socket_base的on_recv_error和on_send_error里面调用,参看server_socket_base);服务端如果想主动关闭某条连接,建议调用这个socket的force_shutdown或者graceful_shutdown函数,它们的调用最终会促使on_recv_error的调用;
重写server_base的on_accept函数,根据你自己的策略确定是否接受客户端的连接,接受返回true;
server_base维护了一个链表(object_pool实现)用于保存所有的socket(这样带来几个好处:一、在广播消息的时候,很方便;二、可开启类似垃圾回收机制的自动清理已经关闭的连接的功能;三、可开启对象池功能),如果你想自己管理这些socket,可以在on_accept里面返回false,然后把它保存在自己的容器里面,并调用start(socket实现)以便开始接受数据(只调用一次即可);
当然,你还可以在返回true的同时,自己也保存一份socket(此时就不要再调用start了),这样做不会带来多少内存消耗,因为它是用智能指针包装的,复制一份只是增加一个引用计数。至于这样做有什么好处,如果你想不到,说明你不需要,当你有需求的时候,你自然而然就会知道有什么用了,我在这里只是告诉大家可以这样做,有个印象即可;