C/S框架 st_asio_wrapper 開發教程(2019.10.17更新)(二)

如果你是偶然瀏覽到這裏,請先看 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了),這樣做不會帶來多少內存消耗,因爲它是用智能指針包裝的,複製一份只是增加一個引用計數。至於這樣做有什麼好處,如果你想不到,說明你不需要,當你有需求的時候,你自然而然就會知道有什麼用了,我在這裏只是告訴大家可以這樣做,有個印象即可;
 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章