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

Msquic客戶端詳解

這篇具有很好參考價值的文章主要介紹了Msquic客戶端詳解。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

Msquic用起來還是很方便很直觀的

因為微軟喜歡玩句柄 所以很多對象都由如下形式提供

Tips:關(guān)于微軟為啥喜歡句柄請自行百度

HQUIC Registration{};

?我們來看看github官網(wǎng) 微軟給出的對象有哪些 下圖來自Msquic github

Msquic客戶端詳解

?下面這段解釋來自微軟github?msquic/API.md at main · microsoft/msquic · GitHub 這里一起貼出

The API supports both server and client applications. All functionality is exposed primarily via a set of different objects:

Api?- The top level handle and function table for all other API calls.

Registration?– Manages the execution context for all child objects. An app may open multiple registrations but ideally should only open one.

Configuration?– Abstracts the configuration for a connection. This generally consists both of security related and common QUIC settings.

Listener?– Server side only, this object provides the interface for an app to accept incoming connections from clients. Once the connection has been accepted, it is independent of the listener. The app may create as many of these as necessary.

Connection?– Represents the actual QUIC connection state between the client and server. The app may create (and/or accept) as many of these as necessary.

Stream?– The layer at which application data is exchanged. Streams may be opened by either peer of a connection and may be unidirectional or bidirectional. For a single connection, as many streams as necessary may be created.

?Tips:App不是微軟的對象哦?他指的是你自己的應(yīng)用程序

那么如上圖所示 根據(jù)常識 咋們的客戶端代碼肯定是不需要Listener的 那么在代碼中需要用到的HQUIC對象就有

//頂層句柄對象
HQUIC Registration{};
//Configuration句柄對象
HQUIC Configuration{};
//Connection句柄對象
HQUIC Connection{};
//stream句柄對象
HQUIC Stream[MaxStreamSize]{};

整個Msquic的流程圖如下

Msquic客戶端詳解

?可以看到啊 非常的清晰 根據(jù)流程圖 下面是代碼 注釋同樣也是寫的非常詳細(xì)了 如果這都看不懂可以給我留言 我手把手教你

Tips:

CreatNewStream并不是Msquic的函數(shù) 而是我自己封裝的

主要操作包括 StreamOpen StreamStart 詳情看代碼吧文章來源地址http://www.zghlxwxcb.cn/news/detail-461967.html

#include <iostream>
#include <fstream>
extern "C"
{
#include <msquic.h>
}
//驗證安全證書?
#define DontValidate 0
//擁有服務(wù)器的Ticket?
#define HasResumptionTicket 0
//流的最大數(shù)量
#define MaxStreamSize 5
//函數(shù)表
const QUIC_API_TABLE* MsQuic{};
//注冊配置 總體配置
const QUIC_REGISTRATION_CONFIG RegConfig = { "MsquicClient",QUIC_EXECUTION_PROFILE_LOW_LATENCY };
//頂層句柄對象
HQUIC Registration{};
//Configuration句柄對象
HQUIC Configuration{};
//Connection句柄對象
HQUIC Connection{};
//stream句柄對象
HQUIC Stream[MaxStreamSize]{};
//流的索引
uint32_t Stream_index{ 0 };
//應(yīng)用層協(xié)議選擇 客戶端服務(wù)端兩邊匹配即可
const QUIC_BUFFER Alpn = { sizeof("test") - 1,(uint8_t*)"test" };
//服務(wù)器IP和端口
const char* ServerIp = "127.0.0.1";
uint16_t ServerPort = 8808;
//這些參數(shù)不再做解釋 在ConnectionCallBack中已經(jīng)有解釋
_IRQL_requires_max_(DISPATCH_LEVEL)
_Function_class_(QUIC_STREAM_CALLBACK)
QUIC_STATUS
QUIC_API
ClientStreamCallback(
	_In_ HQUIC Stream,
	_In_opt_ void* Context,
	_Inout_ QUIC_STREAM_EVENT* Event
)
{
	UNREFERENCED_PARAMETER(Context);
	switch (Event->Type) {
	case QUIC_STREAM_EVENT_SEND_COMPLETE:
		//調(diào)用streamSend完成后觸發(fā)
		free(Event->SEND_COMPLETE.ClientContext);
		std::cout << "Data Send Complete" << std::endl;
		break;
	case QUIC_STREAM_EVENT_RECEIVE:
		std::cout << "Data Receive from server" << std::endl;
		//從對端收到數(shù)據(jù) 數(shù)據(jù)保存在聯(lián)合體中 打印數(shù)據(jù)
		for (uint32_t i = 0; i < Event->RECEIVE.BufferCount; i++)
		{
			std::cout << "Buffer" << i << "=" << std::endl;
			for (uint32_t j = 0; j < Event->RECEIVE.Buffers->Length; j++)
				std::cout << *((uint8_t*)(Event->RECEIVE.Buffers->Buffer + j)) << " ";
			std::cout << std::endl;
		}
		break;
	case QUIC_STREAM_EVENT_PEER_SEND_ABORTED:
		//對端終止
		std::cout << "Server Aborted" << std::endl;
		break;
	case QUIC_STREAM_EVENT_PEER_SEND_SHUTDOWN:
		// 對端終止
		std::cout << "Server Aborted" << std::endl;
		break;
	case QUIC_STREAM_EVENT_SHUTDOWN_COMPLETE:
		//客戶端服務(wù)端均中止
		std::cout << "Both ShutDown" << std::endl;
		if (!Event->SHUTDOWN_COMPLETE.AppCloseInProgress) {
			MsQuic->StreamClose(Stream);
		}
		break;
	default:
		break;
	}
	return QUIC_STATUS_SUCCESS;
}
QUIC_STATUS CreateNewStream(HQUIC Connection)
{
	QUIC_STATUS ret = QUIC_STATUS_SUCCESS;
	//Open與Start之后都沒發(fā)送任何數(shù)據(jù) 這里只是簡單的分配內(nèi)存注冊對象 因為是0RTT建連 所以要發(fā)送數(shù)據(jù)的時候才真正的開始發(fā)送數(shù)據(jù) 該函數(shù)與Connection同理 也是注冊回調(diào)
	ret = MsQuic->StreamOpen(Connection, QUIC_STREAM_OPEN_FLAG_NONE, ClientStreamCallback, NULL, &Stream[Stream_index]);
	if (QUIC_FAILED(ret))
	{
		std::cout << "StreamOpen failed" << std::endl;
		return ret;
	}
	//這一步也不會發(fā)送任何數(shù)據(jù) 可以設(shè)置在這一步通知對端 也可以不設(shè)置 默認(rèn)不通知 這里會分配流的標(biāo)識符 后續(xù)通過StreamSend來發(fā)送數(shù)據(jù)
	ret = MsQuic->StreamStart(Stream[Stream_index], QUIC_STREAM_START_FLAG_NONE);
	if (QUIC_FAILED(ret))
	{
		std::cout << "StreamStart failed" << std::endl;
		return ret;
	}
	//接下來發(fā)送數(shù)據(jù)
	QUIC_BUFFER SendBuffer{};
	SendBuffer.Length = 6;
	SendBuffer.Buffer = (uint8_t*)malloc(6);
	memcpy(SendBuffer.Buffer, "Hello", 6);
	if (HasResumptionTicket)
	{
		ret = MsQuic->StreamSend(Stream[Stream_index], &SendBuffer, 1, QUIC_SEND_FLAG_ALLOW_0_RTT, &SendBuffer);
		if (QUIC_FAILED(ret))
		{
			std::cout << "StreamSend failed" << std::endl;
			return ret;
		}
	}
	else
	{
		ret = MsQuic->StreamSend(Stream[Stream_index], &SendBuffer, 1, QUIC_SEND_FLAG_NONE, &SendBuffer);
		if (QUIC_FAILED(ret))
		{
			std::cout << "StreamSend failed" << std::endl;
			return ret;
		}
	}
	free(SendBuffer.Buffer);
	Stream_index++;
	return ret;
}
_IRQL_requires_max_(DISPATCH_LEVEL)//微軟獨有的玩意不用管 指定中斷級別 只有中斷級別比這個高的才有資格中斷他 不然一直占著CPU執(zhí)行
_Function_class_(QUIC_CONNECTION_CALLBACK)//解釋
QUIC_STATUS//返回值
QUIC_API//函數(shù)調(diào)用約定
ClientConnectionCallback(
	_In_ HQUIC Connection,//微軟傳給你的Connetion對象
	_In_opt_ void* Context,//自己傳的透傳指針
	_Inout_ QUIC_CONNECTION_EVENT* Event//微軟傳給你的事件對象
)
{
	QUIC_STATUS ret = QUIC_STATUS_SUCCESS;
	//(微軟推薦的做法)根據(jù)事件的類型寫回調(diào)
	//其實隨便寫啥都行
	switch (Event->Type)
	{
	case QUIC_CONNECTION_EVENT_CONNECTED:
	{
		std::cout << "Good!Connection complete" << std::endl;
		//連接成功后就可以創(chuàng)建stream流對象了
		ret = CreateNewStream(Connection);
		if (QUIC_FAILED(ret))
		{
			std::cout << "CreateNewStream failed" << std::endl;
			return ret;
		}
		break;
	}
	case QUIC_CONNECTION_EVENT_SHUTDOWN_INITIATED_BY_TRANSPORT:
	{
		//連接即將被關(guān)閉 有很多可能原因 需要自行判斷
		if (Event->SHUTDOWN_INITIATED_BY_TRANSPORT.Status == QUIC_STATUS_CONNECTION_IDLE)
		{
			//超時關(guān)閉
			std::cout << "TimeOut! The Connection will close immediately" << std::endl;
		}
		else
		{
			std::cout << "err! check the error code the code is" << Event->SHUTDOWN_INITIATED_BY_TRANSPORT.Status << std::endl;
		}
		break;
	}
	case QUIC_CONNECTION_EVENT_SHUTDOWN_INITIATED_BY_PEER:
	{
		//服務(wù)端關(guān)閉連接
		std::cout << "the server close the connection" << std::endl;
		break;
	}
	case QUIC_CONNECTION_EVENT_SHUTDOWN_COMPLETE:
	{
		//連接關(guān)閉完成
		std::cout << "the connection has been closed" << std::endl;
		break;
	}
	case QUIC_CONNECTION_EVENT_RESUMPTION_TICKET_RECEIVED:
	{
		//收到重連的ticket 用來進(jìn)行0RTT建連
		//下次再進(jìn)行建立連接的時候可以將這個ticket作為參數(shù)傳入
		//然后就可以不進(jìn)行任何握手進(jìn)行通信
		std::cout << "Resumption ticket received" << std::endl;
		std::fstream tmp("ResumptionTicket.txt", std::ios::trunc | std::ios::binary | std::ios::out);
		for (uint32_t i = 0; i < Event->RESUMPTION_TICKET_RECEIVED.ResumptionTicketLength; i++) {
			printf("%.2X", (uint8_t)Event->RESUMPTION_TICKET_RECEIVED.ResumptionTicket[i]);
			tmp << (uint8_t)Event->RESUMPTION_TICKET_RECEIVED.ResumptionTicket[i];
		}
		std::cout << std::endl;
		tmp.close();
		break;
	}
	default:
		break;
	}
	return QUIC_STATUS_SUCCESS;
}

void Clientmain()
{
	QUIC_STATUS ret = QUIC_STATUS_SUCCESS;
	//打開庫和拿到函數(shù)表(拿到函數(shù)地址)
	ret = MsQuicOpen2(&MsQuic);
	if (QUIC_FAILED(ret))
	{
		std::cout << "open Msquic API table failed" << std::endl;
		return;
	}
	//創(chuàng)建打開頂層registration對象(所有操作必須先打開這個才能繼續(xù)) 別問 問就是微軟要求的
	ret = MsQuic->RegistrationOpen(&RegConfig, &Registration);
	if (QUIC_FAILED(ret))//這個QUIC_FAILED其實就是判斷是否小于0 微軟官方例子這么寫 我也沿用了
	{
		std::cout << "RegistrationOpen failed" << std::endl;
		return;
	}
	//設(shè)置QUIC各種參數(shù) 如0RTT建連等等
	QUIC_SETTINGS Settings{};
	//設(shè)置超時時間 單位ms 其他設(shè)置請參考成員變量
	Settings.IdleTimeoutMs = 1000;
	//設(shè)置好了之后要開啟該設(shè)置
	Settings.IsSet.IdleTimeoutMs = TRUE;
	//配置驗證安全證書等選項 客戶端不需要有證書 除非服務(wù)器要求 故設(shè)置為無
	QUIC_CREDENTIAL_CONFIG CredConfig{};
	CredConfig.Type = QUIC_CREDENTIAL_TYPE_NONE;
	CredConfig.Flags = QUIC_CREDENTIAL_FLAG_CLIENT;
	//當(dāng)你不想驗證服務(wù)器的安全證書時
	if (DontValidate)
	{
		CredConfig.Flags |= QUIC_CREDENTIAL_FLAG_NO_CERTIFICATE_VALIDATION;
	}
	//[Alpn]是你要使用的應(yīng)用層協(xié)議(客戶端和服務(wù)器必須相同 但是注意只是聲明 但實際上就算你填入了http msquic也不會幫你實現(xiàn)這個應(yīng)用層協(xié)議 只要兩邊匹配實際上你隨便填一個莫名其妙的協(xié)議也行)
	//打開Configuration句柄對象
	ret = MsQuic->ConfigurationOpen(Registration, &Alpn, 1, &Settings, sizeof(Settings), NULL, &Configuration);
	if (QUIC_FAILED(ret))
	{
		std::cout << "ConfigurationOpen failed" << std::endl;
		return;
	}
	//打開后還要單獨把我們剛剛設(shè)置好的安全證書選項填入(除非服務(wù)器特殊要求 不然quic使用的tls1.3版本是不需要客戶端擁有安全證書的)
	ret = MsQuic->ConfigurationLoadCredential(Configuration, &CredConfig);
	if (QUIC_FAILED(ret))
	{
		std::cout << "ConfigurationLoadCredential failed" << std::endl;
		return;
	}
	//Registraion和configuration都打開了 剩下就可以直接connect后然后保存stream對象了 注意Msquic要求你注冊回調(diào) 回調(diào)我寫在上面的 然后他內(nèi)部開線程去調(diào)用 內(nèi)部工作線程的數(shù)量在
	//絕大多數(shù)情況下保持默認(rèn)即可
	//第三個參數(shù)透傳指針
	ret = MsQuic->ConnectionOpen(Registration, ClientConnectionCallback, NULL, &Connection);
	if (QUIC_FAILED(ret))
	{
		std::cout << "ConfigurationLoadCredential failed" << std::endl;
		return;
	}
	//如果已經(jīng)建立過連接并且擁有了服務(wù)器的ticket 此處可以將ticket作為參數(shù)傳入 然后可以進(jìn)行0RTT建連 非??焖?	//詳情看調(diào)研測試報告
	if (HasResumptionTicket)
	{

		uint8_t ResumptionTicket[1024]{};//這里填入你之前收到的
		uint16_t RealLength{};//實際的Ticket長度
		ret = MsQuic->SetParam(Connection, QUIC_PARAM_CONN_RESUMPTION_TICKET, RealLength, ResumptionTicket);
		if (QUIC_FAILED(ret))
		{
			std::cout << "SetParam failed" << std::endl;
			return;
		}
	}
	//如果允許0-rtt 則直接0rtt建連 不用經(jīng)過下面的ConnectionStart
	if (HasResumptionTicket)
	{
		CreateNewStream(Connection);
	}
	else
	{
		//打開連接對象后 就可以直接連接了 客戶端主流程到此結(jié)束 邏輯非常清晰 接下來就是你之前注冊過的回調(diào)在起作用了 回調(diào)會把流創(chuàng)建好
		ret = MsQuic->ConnectionStart(Connection, Configuration, QUIC_ADDRESS_FAMILY_UNSPEC, ServerIp, ServerPort);
		if (QUIC_FAILED(ret))
		{
			std::cout << "ConnectionStart failed" << std::endl;
			return;
		}
	}

}

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

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

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

相關(guān)文章

  • kafka客戶端應(yīng)用參數(shù)詳解

    kafka客戶端應(yīng)用參數(shù)詳解

    Kafka提供了非常簡單的客戶端API。只需要引入一個Maven依賴即可: 1、消息發(fā)送者主流程? 然后可以使用Kafka提供的Producer類,快速發(fā)送消息。 ? 整體來說,構(gòu)建Producer分為三個步驟: 設(shè)置Producer核心屬性 ?:Producer可選的屬性都可以由ProducerConfig類管理。比如ProducerConfig.BOOTST

    2024年02月07日
    瀏覽(26)
  • Git客戶端Sourcetree工具安裝使用詳解&命令

    Git客戶端Sourcetree工具安裝使用詳解&命令

    目錄 一、Git工作流程 二、Git安裝 三、Sourcetree工具安裝 四、Sourcetree配置 五、Sourcetree配置SSH 六、GIT常用命令 1、獲取安裝程序 a、官網(wǎng)地址:https://git-scm.com/downloads b、網(wǎng)盤地址:百度網(wǎng)盤 請輸入提取碼? ? xc5d 2、雙擊按照默認(rèn)配置安裝即可,安裝目錄:D:softwareGit、安裝完

    2024年02月07日
    瀏覽(26)
  • 【HDFS】ResponseProcessor線程詳解以及客戶端backoff反壓

    ResponseProcessor如何處理datanode側(cè)發(fā)過來的packet ack的 客戶端側(cè)backoff邏輯。 ResponseProcessor:主要功能是處理來自datanode的響應(yīng)。當(dāng)一個packet的響應(yīng)到達(dá)時,會把這個packet從ackQueue里移除。

    2024年02月11日
    瀏覽(35)
  • NFS服務(wù)器簡介、在Linux上搭建NFS服務(wù)器和客戶端,使用autofs進(jìn)行NFS客戶端自動掛載和卸載詳解

    NFS服務(wù)器簡介、在Linux上搭建NFS服務(wù)器和客戶端,使用autofs進(jìn)行NFS客戶端自動掛載和卸載詳解

    目錄 一.NFS服務(wù)器簡介 1.含義簡介: 2.工作原理簡介: 3.RPC服務(wù)與NFS服務(wù)配合使用 二.NFS配置文件參數(shù)命令介紹 1.主配置文件/etc/exports 2.日志文件/var/lib/nfs/ 3.showmount命令 三.主配置文件/etc/exports掛載寫法 1.配置nfs服務(wù)端和客戶端 2.windows客戶端掛載測試 3.權(quán)限介紹 (1)rw/ro,服

    2024年02月04日
    瀏覽(32)
  • 【C++】TCP通信服務(wù)端與客戶端代碼實現(xiàn)及詳解

    【C++】TCP通信服務(wù)端與客戶端代碼實現(xiàn)及詳解

    上述代碼使用Winsock庫實現(xiàn)了簡單的TCP服務(wù)器,它監(jiān)聽指定端口并與客戶端進(jìn)行通信。下面對代碼進(jìn)行詳細(xì)分析: #pragma comment(lib, \\\"ws2_32.lib\\\") 是一個特殊的 編譯器指令 ,用于告訴編譯器在鏈接階段將 ws2_32.lib 庫文件添加到最終的可執(zhí)行文件中。無需在編譯命令行或IDE中顯式指

    2024年02月03日
    瀏覽(21)
  • <Linux>《OpenSSH 客戶端配置文件ssh_config詳解》

    除非另有說明,對于每個參數(shù),將使用第一個獲得的值。配置文件包含由 Host 規(guī)范分隔的部分,該部分僅應(yīng)用于與規(guī)范中給出的模式之一匹配的主機(jī)。匹配的主機(jī)名通常是命令行中給出的名稱(請參閱 CanonicalizeHostname 選項以了解異常情況)。 由于使用了每個參數(shù)的第一個獲得的

    2024年02月07日
    瀏覽(27)
  • 利用idea生成webservice客戶端--詳解步驟--(wsdl文件的使用)

    利用idea生成webservice客戶端--詳解步驟--(wsdl文件的使用)

    目錄 一、idea安裝webservice 1.點擊左上file,選中settings?編輯 2.下載Web Service 3.給此項目添加webservice 4.添加webservice的依賴 二、利用idea根據(jù)wsdl文件自動生成webService客戶端代碼(然后比照著生成的測試類進(jìn)行接口或方法的調(diào)用) 1.打開tools - WebServices - Generate Java Code From Wsdl,按照圖中

    2024年02月08日
    瀏覽(19)
  • Ubuntu配置NFS客戶端和服務(wù)端詳解——手把手配置

    Ubuntu配置NFS客戶端和服務(wù)端詳解——手把手配置

    如果您想實現(xiàn)遠(yuǎn)程訪問并修改 ROS 主機(jī)中 Ubuntu 上的文件,可以通過 NFS掛載的方式。虛擬機(jī)上的 Ubuntu 系統(tǒng)可以通過 NFS 的方式來訪問 ROS 主機(jī)中Ubuntu 系統(tǒng)的文件,NFS 分為服務(wù)器掛載和客戶端訪問。這里虛擬機(jī)上的 Ubuntu作為客戶端,ROS 主機(jī)上的 Ubuntu 作為服務(wù)端,虛擬機(jī)的

    2024年02月01日
    瀏覽(18)
  • Spring 教程—REST 客戶端詳解(WebClient 、RestTemplate、HTTP 接口)

    Spring框架為調(diào)用REST端點提供了以下選擇: WebClient?- 非阻塞、響應(yīng)式客戶端和 fluent API。 RestTemplate?- 帶有模板方法API的同步客戶端。 HTTP 接口?- 注解式接口,并生成動態(tài)代理實現(xiàn)。 WebClient ?是一個非阻塞的、響應(yīng)式的客戶端,用于執(zhí)行HTTP請求。它在5.0中引入,提供了? Re

    2024年02月07日
    瀏覽(51)
  • NFS服務(wù)器簡介、在Linux上搭建NFS服務(wù)器和客戶端,Linux上使用auto(autofs)進(jìn)行NFS客戶端自動掛載和卸載詳解

    NFS服務(wù)器簡介、在Linux上搭建NFS服務(wù)器和客戶端,Linux上使用auto(autofs)進(jìn)行NFS客戶端自動掛載和卸載詳解

    目錄 一.NFS服務(wù)器簡介 1.含義簡介: 2.工作原理簡介: 3.RPC服務(wù)與NFS服務(wù)配合使用 二.NFS配置文件參數(shù)命令介紹 1.主配置文件/etc/exports 2.日志文件/var/lib/nfs/ 3.showmount命令 三.主配置文件/etc/exports掛載寫法 1.配置nfs服務(wù)端和客戶端 2.windows客戶端掛載測試 3.權(quán)限介紹 (1)rw/ro,服

    2024年02月04日
    瀏覽(26)

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

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

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

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

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包