国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

實現(xiàn)c++輕量級別websocket協(xié)議客戶端

這篇具有很好參考價值的文章主要介紹了實現(xiàn)c++輕量級別websocket協(xié)議客戶端。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

1 websocket 輕量客戶端

因以前發(fā)過這個代碼,但是一直沒有整理,這次整理了一下,持續(xù)修改,主要是要使用在arm的linux上,發(fā)送接收的數(shù)據(jù)壓縮成圖片發(fā)送出去。

要達到輕量websocket 使用,必須要達到幾個方面才能足夠簡單,
1、不用加入其他的庫
2、只需要使用頭文件包含就可以
3、跨平臺
如果正常應(yīng)用,可以使用websocketpp等庫,問題就是比較麻煩,要使用boost或者asio庫,當然asio也是足夠簡單,頭文件包含,編譯通過要設(shè)置參數(shù),問題不大,不過不夠簡單

2 應(yīng)用場景

1 windows 使用
2 linux使用
3 linux arm 板子上使用
在arm上編譯的時候,就不用編譯那么多的庫文件了

3 原理

使用select模型 和原始操作系統(tǒng)的socket來直接編寫代碼,select模型比較簡單,非長時間阻塞模式,以下是webscoket協(xié)議字節(jié)示意圖
c++ websocket庫,c++,c++高級技巧,網(wǎng)絡(luò),c++,websocket,開發(fā)語言
本文函數(shù)根據(jù)上圖實現(xiàn)了websocket協(xié)議。定義的主要數(shù)據(jù)結(jié)構(gòu)如下所示,websocket協(xié)議里面包含兩種數(shù)據(jù),一種是二進制,一種是文本,是可以指定的

	struct wsheader_type {
		unsigned header_size;
		bool fin;
		bool mask;
		enum opcode_type {
			CONTINUATION = 0x0,
			TEXT_FRAME = 0x1,
			BINARY_FRAME = 0x2,
			CLOSE = 8,
			PING = 9,
			PONG = 0xa,
		} opcode;
		int N0;
		uint64_t N;
		uint8_t masking_key[4];
	};

websocket鏈接

websocket鏈接使用的是http協(xié)議,所不同的是必須做upgrade

static const char* desthttp = "GET /%s HTTP/1.1\r\n"
			"Host: %s:%d\r\n"
			"Upgrade: websocket\r\n"
			"Connection: Upgrade\r\n"
			"Origin: %s\r\n"
			"Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==\r\n"
			"Sec-WebSocket-Version: 13\r\n\r\n";

上面把http協(xié)議升級為websocket協(xié)議的內(nèi)容寫出,把客戶端的內(nèi)容填充過去發(fā)送到服務(wù)端就行,從下面代碼可以看出我們需要哪些內(nèi)容

char line[256];
int status;
int i;
sprintf(line, desthttp, path, host, port, origin.c_str());
::send(sockfd, line, (int)strlen(line), 0);

發(fā)送和接收

使用select來做異步的模式,發(fā)送的時候指定參數(shù)
很簡單,就如下所示

	fd_set wfds;
	timeval tv = { timeout / 1000, (timeout % 1000) * 1000 };
	FD_ZERO(&wfds);
	if (txbuf.size()) { FD_SET(sockfd, &wfds); }
	select((int)(sockfd + 1), NULL, &wfds, 0, timeout > 0 ? &tv : 0);

當然,如果要將socket置為非阻塞,開始的時候還是要設(shè)置的

#ifdef _WIN32
		u_long on = 1;
		ioctlsocket(sockfd, FIONBIO, &on);
#else
		fcntl(sockfd, F_SETFL, O_NONBLOCK);
#endif

下面是發(fā)送的函數(shù),參數(shù)為毫秒

//參數(shù)是毫秒
void pollSend(int timeout)
	{
		if (v_state == CLOSED) {
			if (timeout > 0) {
				timeval tv = { timeout / 1000, (timeout % 1000) * 1000 };
				select(0, NULL, NULL, NULL, &tv);
			}
			return;
		}
		if (timeout != 0) {
			fd_set wfds;
			timeval tv = { timeout / 1000, (timeout % 1000) * 1000 };
			FD_ZERO(&wfds);

			if (txbuf.size()) { FD_SET(sockfd, &wfds); }
			select((int)(sockfd + 1), NULL, &wfds, 0, timeout > 0 ? &tv : 0);
		}
		while (txbuf.size()) {
			int ret = ::send(sockfd, (char*)&txbuf[0], (int)txbuf.size(), 0);
			if (ret < 0 && (socketerrno == SOCKET_EWOULDBLOCK || socketerrno == SOCKET_EAGAIN_EINPROGRESS)) {
				break;
			}
			else if (ret <= 0) {
				closesocket(sockfd);
				v_state = CLOSED;
				fputs(ret < 0 ? "Connection error!\n" : "Connection closed!\n", stderr);
				break;
			}
			else {
				txbuf.erase(txbuf.begin(), txbuf.begin() + ret);
			}
		}
		if (!txbuf.size() && v_state == CLOSING) {
			closesocket(sockfd);
			v_state = CLOSED;
		}
	}

下面是接收函數(shù)

void pollRecv(int timeout)
	{
		if (v_state == CLOSED) {
			if (timeout > 0) {
				timeval tv = { timeout / 1000, (timeout % 1000) * 1000 };
				select(0, NULL, NULL, NULL, &tv);
			}
			return;
		}
		if (timeout != 0) {
			fd_set rfds;
			//fd_set wfds;
			timeval tv = { timeout / 1000, (timeout % 1000) * 1000 };
			FD_ZERO(&rfds);
			FD_SET(sockfd, &rfds);
		
			select((int)(sockfd + 1), &rfds, NULL, 0, timeout > 0 ? &tv : 0);
			if (!FD_ISSET(sockfd, &rfds))
			{
				printf("out of here ,no data\n");
				return;
			}
		}
		while (true) {
			// FD_ISSET(0, &rfds) will be true
			int N = (int)rxbuf.size();
			ssize_t ret;
			//錢波 64K 一個IP包長
			rxbuf.resize(N + 64000);
			ret = recv(sockfd, (char*)&rxbuf[0] + N, 64000, 0);
			if (ret < 0 && (socketerrno == SOCKET_EWOULDBLOCK || socketerrno == SOCKET_EAGAIN_EINPROGRESS)) {
				rxbuf.resize(N);
				break;
			}
			else if (ret <= 0) {
				rxbuf.resize(N);
				closesocket(sockfd);
				v_state = CLOSED;
				fputs(ret < 0 ? "Connection error!\n" : "Connection closed!\n", stderr);
				break;
			}
			else {//接收到的數(shù)據(jù)
				rxbuf.resize(N + ret);
			}
		}
	}

可以看出,我們使用select 僅僅是不阻塞,簡單使用FD_ISSET宏去判決是否有數(shù)據(jù)達到,如果我們沒有收到數(shù)據(jù),我們就直接返回。

為了簡單使用程序,我們封裝一個class來使用接收和發(fā)送

class c_ws_class //:public TThreadRunable
{
	thread v_thread;
	std::mutex v_mutex;
	std::condition_variable v_cond;
	WebSocket v_ws;
	int v_stop = 1;
	string v_url;
	callback_message_recv v_recv = NULL;
	//已經(jīng)
	//bool v_is_working = false;
public:

	static int InitSock()
	{
#ifdef _WIN32
		INT rc;
		WSADATA wsaData;

		rc = WSAStartup(MAKEWORD(2, 2), &wsaData);
		if (rc) {
			printf("WSAStartup Failed.\n");
			return -1;
		}
#endif
		return 0;
	}


	static void UnInitSock()
	{
		WSACleanup();
	}


	c_ws_class()
	{}
	~c_ws_class()
	{
		v_ws.close();
	}
	
public:


	void set_url(const char * url)
	{
		v_url = url;
	}
	int connect()
	{
		if (v_url.empty())
			return -1;
		return v_ws.connect(v_url);
	}
	void Start(callback_message_recv recv)
	{
		//because we will connect all over the time, so v_stop is zero
		v_stop = 0;
		v_ws.initSize(0, 0);
		v_recv = recv;
		v_thread = std::thread(std::bind(&c_ws_class::Run, this));
	}

	bool send(const char * str)
	{
		if (str != NULL)
		{
			if (v_ws.getReadyState() != CLOSED)
			{
				v_ws.send(str);
				v_ws.pollSend(10);
				return true;
			}
			return false;
		}
		return false;
	}

	void sendBinary(uint8_t *data, int len)
	{
		if (v_ws.getReadyState() != CLOSED)
		{
			v_ws.sendBinary(data, len);
			v_ws.pollSend(5);
		}
	}
	void Stop()
	{
		v_stop = 1;
	}
	int isStop()
	{
		return v_stop;
	}
	void Join()
	{
		if (v_thread.joinable())
			v_thread.join();
	}
	void Run()
	{
		
		while (v_stop == 0) {
			//WebSocket::pointer wsp = &*ws; // <-- because a unique_ptr cannot be copied into a lambda
			if (v_stop == 1)
				break;
			if (v_ws.getReadyState() == CLOSED)
			{
				//斷線重連
				if (connect() != 0)
				{
					for (int i = 0; i < 20; i++)
					{
						std::this_thread::sleep_for(std::chrono::milliseconds(100));
						if (v_stop == 1)
							break;
					}
				}
			}
			else
			{
				v_ws.pollRecv(10);
				v_ws.dispatch(v_recv);
			}

		}
		v_ws.close();
		//std::cout << "server exit" << endl;
		v_stop = 1;
	}

	void WaitForSignal()
	{
		std::unique_lock<std::mutex> ul(v_mutex);
		v_cond.wait(ul);
	}
	void Notify()
	{
		v_cond.notify_one();
	}
};

以上為封裝的外層線程代碼,里面同時也封裝了斷線重連。

我們常常使用python或者使用nodejs來做測試,這里使用nodejs寫一個簡單的服務(wù)器程序,接收到數(shù)據(jù)以后發(fā)回。

const WebSocket = require('ws');

const wss = new WebSocket.Server({ port: 8000 });

wss.on('connection', function connection(ws) {
  ws.on('message', function incoming(message) {
    console.log('received: %s', message);
    ws.send('recv:'+message);
  });//當收到消息時,在控制臺打印出來,并回復(fù)一條信息
});

測試結(jié)果

服務(wù)端nodejs顯示
c++ websocket庫,c++,c++高級技巧,網(wǎng)絡(luò),c++,websocket,開發(fā)語言
客戶端鏈接后顯示
c++ websocket庫,c++,c++高級技巧,網(wǎng)絡(luò),c++,websocket,開發(fā)語言

整個的頭文件代碼和測試代碼在gitee上面
gitee地址文章來源地址http://www.zghlxwxcb.cn/news/detail-524103.html

到了這里,關(guān)于實現(xiàn)c++輕量級別websocket協(xié)議客戶端的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔相關(guān)法律責任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

  • c++: websocket 客戶端與服務(wù)端之間的連接交互

    目錄 socket 頭文件 延遲時間 通信協(xié)議地址 TCP/IP 服務(wù)端 客戶端 編程步驟 服務(wù)端 客戶端 編程步驟 1. 初始化 WSAStartup 2. 創(chuàng)建 socket 2.1 協(xié)議族 2.2 socket 類型 2.3 協(xié)議 3. 綁定 bind (服務(wù)端) 4. 監(jiān)聽 listen(服務(wù)端) 5. 請求連接 connect(客戶端) 6. 接收請求 accept(服務(wù)端) 7. 發(fā)送

    2024年02月14日
    瀏覽(49)
  • C++下輕量化websocket客戶端庫——easywsclient的使用

    C++下輕量化websocket客戶端庫——easywsclient的使用

    1.1 WebSocket介紹 WebSocket 是 HTML5 開始提供的一種在單個 TCP 連接上進行全雙工通訊的協(xié)議。 WebSocket 使得客戶端和服務(wù)器之間的數(shù)據(jù)交換變得更加簡單,允許服務(wù)端主動向客戶端推送數(shù)據(jù)。在 WebSocket API 中,瀏覽器和服務(wù)器只需要完成一次握手,兩者之間就直接可以創(chuàng)建持久性

    2024年02月12日
    瀏覽(34)
  • websocket客戶端實現(xiàn)(java)

    其中,headers 參數(shù)是一個鍵值對,表示需要設(shè)置的請求頭。在構(gòu)造函數(shù)中,我們首先創(chuàng)建了一個 ClientEndpointConfig.Configurator 對象,重寫了其中的 beforeRequest() 方法,用于在請求之前設(shè)置請求頭。然后,我們使用 ClientEndpointConfig.Builder.create() 方法創(chuàng)建一個 ClientEndpointConfig 對象,并

    2024年02月15日
    瀏覽(26)
  • Java實現(xiàn)websocket客戶端

    常規(guī)情況下,大多數(shù)時候Java后臺作為websocket服務(wù)端,實現(xiàn)方式也比較簡單,網(wǎng)上很多案例代碼。但是很多時候項目中服務(wù)與服務(wù)之間也需要使用websocket通信,此時項目就需要實現(xiàn)客戶端功能。 步驟一:導(dǎo)入依賴: 步驟二:實現(xiàn)WebSocketClient抽象類: 該類中和websocket服務(wù)端接口

    2024年02月16日
    瀏覽(86)
  • SpringBoot+WebSocket實現(xiàn)服務(wù)端、客戶端

    SpringBoot+WebSocket實現(xiàn)服務(wù)端、客戶端

    小編最近一直在使用springboot框架開發(fā)項目,畢竟現(xiàn)在很多公司都在采用此框架,之后小編也會陸續(xù)寫關(guān)于springboot開發(fā)常用功能的文章。 什么場景下會要使用到websocket的呢? websocket主要功能就是實現(xiàn)網(wǎng)絡(luò)通訊,比如說最經(jīng)典的客服聊天窗口、您有新的消息通知,或者是項目與

    2024年02月13日
    瀏覽(25)
  • JAVA使用WebSocket實現(xiàn)多客戶端請求

    工作前提:兩個服務(wù)之間實現(xiàn)聊天通訊,因為介于兩個服務(wù),兩個客戶端 方案1:多個服務(wù)端,多個客戶端,使用redis把用戶數(shù)據(jù)ip進行存儲,交互拿到redis數(shù)據(jù)進行推送 方案2: 一個服務(wù)端,多個客戶端,拿到客戶端的id和需要推送的id進行拼接存儲 此文章使用的是方案2 1. 引

    2024年02月11日
    瀏覽(17)
  • WebSocket 實現(xiàn)長連接及通過WebSocket獲取客戶端IP

    WebSocket 是一種支持雙向通訊的網(wǎng)絡(luò)通信協(xié)議。 實現(xiàn)過程: 1 添加ServerEndpointExporter配置bean 2 實現(xiàn)過程 需求是通過WebSocket,建立長連接,并獲取當前在線的人數(shù)。通過Websocket 不斷發(fā)送消息,建立長連接,給Session續(xù)命。我是通過MAC地址,區(qū)分不同的設(shè)備,因為我的需求中需要一

    2024年02月09日
    瀏覽(31)
  • cpp-httplib: 輕量級、高性能的C++ HTTP/HTTPS客戶端和服務(wù)器庫

    cpp-httplib 是一個輕量級且高效的 C++ HTTP/HTTPS 客戶端和服務(wù)器庫。它由 Hideaki Sone(yhirose)開發(fā),并在 MIT 許可下發(fā)布。該項目的主要目標是提供一種簡單易用的方式,在 C++ 應(yīng)用程序中實現(xiàn) HTTP 和 HTTPS 功能。 項目倉庫地址:https://gitcode.com/yhirose/cpp-httplib cpp-httplib 可用于以下場

    2024年04月09日
    瀏覽(88)
  • Java實現(xiàn)WebSocket客戶端和服務(wù)端(簡單版)

    Java實現(xiàn)WebSocket客戶端和服務(wù)端(簡單版)

    天行健,君子以自強不息;地勢坤,君子以厚德載物。 每個人都有惰性,但不斷學習是好好生活的根本,共勉! 文章均為學習整理筆記,分享記錄為主,如有錯誤請指正,共同學習進步。 寫在前面: WebSocket是一種在單個TCP連接上進行全雙工通信的協(xié)議。 WebSocket通信協(xié)議于

    2024年02月08日
    瀏覽(35)
  • SpringBoot集成WebSocket實現(xiàn)客戶端與服務(wù)端通信

    SpringBoot集成WebSocket實現(xiàn)客戶端與服務(wù)端通信

    話不多說,直接上代碼看效果! 一、服務(wù)端: 1、引用依賴 2、添加配置文件 WebSocketConfig 3、編寫WebSocket服務(wù)端接收、發(fā)送功能 ? 聲明接口代碼: ? 實現(xiàn)類代碼: 4、如果不需要實現(xiàn)客戶端功能,此處可選擇前端調(diào)用,奉上代碼 二、客戶端: 1、引用依賴 2、自定義WebSocket客

    2024年01月23日
    瀏覽(24)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包