1. 程式人生 > >Boost.Asio C++ 網路程式設計之七:基於TCP的同步客戶端

Boost.Asio C++ 網路程式設計之七:基於TCP的同步客戶端

      從本篇開始,我們會深入學習怎樣使用Boost.Asio建立更加複雜的客戶端和服務端應用。你可以執行並測試它們,而且在理解之後,你可以把它們做為框架來構造自己的應用。
在接下來的例子中:
1.客戶端使用一個使用者名稱(無密碼)登入到服務端
2.所有的連線由客戶端建立,當客戶端請求時服務端迴應
3.所有的請求和回覆都以換行符結尾(’\n’)
4.對於5秒鐘沒有ping操作的客戶端,服務端會自動斷開其連線
客戶端可以傳送如下請求:
1.獲得所有已連線客戶端的列表
2.客戶端可以ping,當它ping時,服務端返回ping ok或者pingclient_list_chaned
為了更有趣一點,我們增加了一些難度:
1.每個客戶端登入6個使用者連線,比如Johon,James,Lucy,Tracy,Frank和Abby

2.每個客戶端連線隨機地ping服務端(隨機7秒;這樣的話,服務端會時不時關閉一個連線)

基於TCP的同步客戶端

1.流程圖


2.實現

#ifdef WIN32
#define _WIN32_WINNT 0x0501
#include <stdio.h>
#endif

#include <boost/thread.hpp>
#include <boost/bind.hpp>
#include <boost/asio.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
using namespace boost::asio;
io_service service;

/** simple connection to server:
- logs in just with username (no password)
- all connections are initiated by the client: client asks, server answers
- server disconnects any client that hasn't pinged for 5 seconds

Possible requests:
- gets a list of all connected clients
- ping: the server answers either with "ping ok" or "ping client_list_changed"
*/
struct talk_to_svr {
	talk_to_svr(const std::string & username)
		: sock_(service), started_(true), username_(username) {}
	void connect(ip::tcp::endpoint ep) {
		sock_.connect(ep);
	}
	void loop() {
		// read answer to our login
		write("login " + username_ + "\n");
		read_answer();
		while (started_) {
			// 迴圈傳送ping請求
			write_request();
			read_answer();
			int millis = rand() % 7000;
			std::cout << username_ << " postpone ping "
				<< millis << " ms" << std::endl;
			boost::this_thread::sleep(boost::posix_time::millisec(millis));
		}
	}
	std::string username() const { return username_; }
private:
	void write_request() {
		write("ping\n");
	}
	void read_answer() {
		already_read_ = 0;
		read(sock_, buffer(buff_),
			boost::bind(&talk_to_svr::read_complete, this, _1, _2));
		process_msg();
	}
	void process_msg() {
		std::string msg(buff_, already_read_);
		if (msg.find("login ") == 0) on_login();
		else if (msg.find("ping") == 0) on_ping(msg);
		else if (msg.find("clients ") == 0) on_clients(msg);
		else std::cerr << "invalid msg " << msg << std::endl;
	}

	void on_login() {
		std::cout << username_ << " logged in" << std::endl;
		do_ask_clients();
	}
	void on_ping(const std::string & msg) {
		std::istringstream in(msg);
		std::string answer;
		in >> answer >> answer;
		if (answer == "client_list_changed")
			do_ask_clients();
	}
	void on_clients(const std::string & msg) {
		std::string clients = msg.substr(8);
		std::cout << username_ << ", new client list:" << clients;
	}
	// 獲得所有已連線客戶端的列表
	void do_ask_clients() {
		write("ask_clients\n");
		read_answer();
	}

	void write(const std::string & msg) {
		sock_.write_some(buffer(msg));
	}
	size_t read_complete(const boost::system::error_code & err, size_t bytes) {
		if (err) return 0;
		already_read_ = bytes;
		bool found = std::find(buff_, buff_ + bytes, '\n') < buff_ + bytes;
		return found ? 0 : 1;
	}

private:
	ip::tcp::socket sock_;
	enum { max_msg = 1024 };
	int already_read_;
	char buff_[max_msg];
	bool started_;
	std::string username_;
};

ip::tcp::endpoint ep(ip::address::from_string("127.0.0.1"), 8001);
void run_client(const std::string & client_name) {
	talk_to_svr client(client_name);
	try {
		client.connect(ep);
		client.loop();
	}
	catch (boost::system::system_error & err) {
		// 捕獲socket斷開原因
		std::cout << "client terminated " << client.username()
			<< "——" << err.what() << std::endl;
	}
}

int main(int argc, char* argv[]) {
	boost::thread_group threads;
	char* names[] = { "John", "James", "Lucy", "Tracy", "Frank", "Abby", 0 };
	for (char ** name = names; *name; ++name) {
		threads.create_thread(boost::bind(run_client, *name));
		boost::this_thread::sleep(boost::posix_time::millisec(100));
	}
	threads.join_all();
	system("pause");
}

相關推薦

Boost.Asio C++ 網路程式設計基於TCP同步客戶

      從本篇開始,我們會深入學習怎樣使用Boost.Asio建立更加複雜的客戶端和服務端應用。你可以執行並測試它們,而且在理解之後,你可以把它們做為框架來構造自己的應用。在接下來的例子中:1.客戶

Boost.Asio C++ 網路程式設計基於TCP的非同步服務

       這個流程圖是相當複雜的:從Boost.Asio出來你可以看到4個箭頭指向on_accept,on_read,on_write和on_check_ping。這也就意味著你永遠不知道哪個非同步呼叫是下一個完成的呼叫,但是你可以確定的是它是這4個操作中的一個。基於TC

Boost.Asio C++ 網路程式設計基於TCP的非同步客戶

       現在,是比較有趣(也比較難)的非同步實現! 當檢視流程圖時,你需要知道Boost.Asio代表由Boost.Asio執行的一個非同步呼叫。例如do_read(),Boost.Asio和on_read()代表了從do_read()到on_read()的邏輯流程,

Boost.Asio C++ 網路程式設計同步和非同步

       首先,非同步程式設計和同步程式設計是截然不同的。在同步程式設計中,所有的操作都是順序執行的,比如從socket中讀取(請求),然後寫入(迴應)到socket中。每一個操作都是阻塞的。因為操作是阻塞的,所以為了不影響主程式,當在socket上讀寫時,通常會建立一個

Boost.Asio C++ 網路程式設計TCP回顯客戶/服務

       回顯就是服務端將接收到的任何內容回發給客戶端顯示,然後關閉客戶端的連線。這個服務端可以處理任何數量的客戶端。每個客戶端連線之後傳送一個訊息,服務端接收到訊息後把它傳送回去。在那之後,服務端關閉連線。具體流程如下圖所示。        對於TCP而言,我們需要

Boost.Asio c++ 網路程式設計翻譯(30)[完結]

本地socket是一種只能被執行在主機上的應用訪問的socket。你可以使用本地socket來實現簡單的程序間通訊。你可以用客戶端或者服務端的方式來連線兩端。對於本地socket,端點時一個檔案,比如/tmp/whatever。很酷的一件事情是你可以給指定的檔案賦予許可權,從而禁止機器上指定的使用者在檔案上建

Boost.Asio c++ 網路程式設計翻譯(6)

io_service類 你應該已經發現大部分使用Boost.Asio編寫的程式碼都會使用幾個ios_service的例項。ios_service是這個庫裡面最重要的類;它負責和作業系統打交道,等待所有非同步操作的結束,然後為每一個非同步操作呼叫完成處理程式。 如果你選擇用同

linux網路程式設計用多執行緒實現客戶到服務的通訊(基於udp)

1、開啟一個執行緒接受資料,主執行緒傳送資料的程式碼 #include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #includ

TCP/IP網路程式設計》筆記5-基於TCP的伺服器客戶2

概述 上一節已經給出了服務端和客戶端的實現,為何還有這第二節? a. 上一節中的回聲客戶端是有問題的 問題的來源是tcp的傳輸特性:TCP傳輸的無邊界性。這樣造成了兩個後果,第一. client端呼叫write後並無法保證資料立即傳遞,可能發生

Python3 與 C# 網路程式設計網路基礎篇

最新版本檢視:https://www.cnblogs.com/dotnetcrazy/p/9919202.html 入門篇 官方文件:https://docs.python.org/3/library/ipc.html(程序間通訊和網路) 例項程式碼:https://github.com/lotapp/

網路程式設計——層模型與TCP三段握手與四次斷開

轉載請註明出處:https://blog.csdn.net/l1028386804/article/details/83046311 一、C/S架構 客戶端/服務端架構 二、OSI七層架構 七層模型,亦稱OSI(Open System Interconnection)參考模型,是

洞悉C++網路程式設計tcp/ip和socket api

原文地址:https://blog.csdn.net/libaineu2004/article/details/79020403 TCP(Transmission Control Protocol) 傳輸控制協議 三次握手 TCP是主機對主機層的傳輸控制協議,提供可靠的連線服務,採用三次

c++ 網路程式設計socket

windows 10 structures sockaddr, sockaddr_in sockaddr 和 sockaddr_in 同樣都是為了處理網路通訊的地址,包含了地址類別(familty),地址(ip),埠資訊。 sockaddr是給機器用的,

Linux-C網路程式設計epoll函式

上文中說到如果從100的不同的地方取外賣,那麼epoll相當於一部手機,當外賣到達後,送貨員可以通知你,從而達到每去必得,少走很多路。 它是如何實現這些作用的呢? epoll的功能 epoll是select/poll的強化版,同是多路複用的函式,epoll

C++網路程式設計select

select函式決定一個或者多個套接字(socket)的狀態,如果需要的話,等待執行非同步I/O。 int select(               __in        int    nfds,               __inout    fd_set *readfds,            

C# 網路程式設計基於SMTP傳送電子郵件

        本文主要講述基於C#網路程式設計的傳送郵件的程式設計,郵件傳送功能是基於郵件協議的,常見的電子郵件協議有SMTP(簡單郵件傳輸協議)、POP3(郵局協議)、IMAP(Internet郵件訪問協議),文章主要參考周存傑的《C#網路程式設計例項教程》.這也是最後

C#網路程式設計---TCP協議的同步通訊(二)

上一篇學習日記C#網路程式設計之--TCP協議(一)中以服務端接受客戶端的請求連線結尾 既然服務端已經與客戶端建立了連線,那麼溝通通道已經打通,載滿資料的小火車就可以彼此傳送和接收了。現在讓我們來看看資料的傳送與接收 先把服務端與客戶端的連線程式碼敲出來 服務端 IPAddress ip = new IP

C# 網路程式設計webBrowser亂碼問題及解決知識

       在使用PHP+MySQL編寫網頁時,曾近就因為顯示中文亂碼”口口口???”困擾我很長時間,沒想到在C#製作瀏覽器或獲取XML頁面時也經常會遇到顯示中文亂碼的問題,可想而知怎樣解決編碼問題

Linux 下 C 網路程式設計 多執行緒通訊 例項

簡單示例,有不對的地方,歡迎指點。 伺服器端 /* ============================================================================ Name : sockThreadServer

linux c/c++網路程式設計—select模型

1.select 模型是一個比較傳統的非同步IO模型,我們知道的著名的apache就是基於select模型,而我之前工作過的搜狐暢遊的天龍八部,還有幾款遊戲都是基於select模型。 對於select模型,大多都是說他的缺點,實際上我的觀點有點不一樣,select模型的跨平