QSocket 是 QDAC 開源組件的一個重要的組成部分,終於要開始開工了,為了方便大家了解 QSocket,對 QSocket 的總體設計的一些想法,我在這里給大家簡要的描述一下。
首先,QSocket 同 QDAC 的其它組成部分一樣,是跨平台的,這意味着你可以在不同的操作系統中,體驗 QSocket 為你帶來的良好體驗。
其次,QSocket 是 Delphi 的原生代碼,所以不會依賴於其它第三方庫(QDAC 自身的不算:-:)。
其三,QSocket 會基於各個操作系統自身,進行針對性的優化,換句話說,IOCP/KQueue/EPOLL 都將在里面看到它的身影。
老末,QSocket 將是一個基於異步的 IO 框架,雖然會有一些同步的方法,不過異步是核心,同步是封裝而已。
好了,現在進入總體的框架描述部分。
QSocket 的設計理念中包含以下幾個部分:
- IQTransport
Transport,顧名思議就是一個傳輸港。它來負責將數據傳送到目標,這里目標包括兩個含義:
首先是發送到目標,則 IQTransport 負責將數據傳遞給目標地址。但具體是否傳送成功,取決於 Transport 所使用的協議及實現;
其次是接收后派發到目標,則 IQTransport 負責將接收到的數據,傳遞給具體的處理函數,來完成對數據的處理。
通俗點講,IQTransport 就是一個港口,負責貨物的打包、裝運和分流,為此它提供了:- 用於指定本地要監聽的地址及端口的 Bindings 列表,也可以通過簡單的指定 LocalPort 來在所有地址的指定端口上監聽通訊(僅對TCP/UDP有效,其它協議該屬性可能無意義);
- 用於管理已經建立的連接的 Connections 列表;
- 用於廣播數據的 Broadcast 函數;
- 用於對要傳送的數據進行打包操作的編碼處理器 Codecs;
- 用於確定要將接收到的數據如果處理的派發器列表 Dispatchers;
- 其它由 IQTransport 的接口實現提供的其它屬性及方法
- IQRequest
Request,請求。在 QSocket 中,一次請求+回應構成一個請求。比如,我們向服務器端發送一個命令,此時就會生成一個請求,服務器返回處理結果,這個請求的處理就結束了。我們再向服務器發送后續的命令,就是新的請求了。有一個概念需要大家明白,請求未必有回應,所以有求必應在 QSocket 中並不是一個必然的概念。由於請求的發送及處理都需要時間,如果此處用同步等待的方法來編程,很明顯會降低整個系統的效率,所以,IQRequest 的接口實現了異步發送接口。IQRequest 提供的主要內容如下:- 請求 ID,一個無符號32位整數,它具體的意義,取決於具體的實現,一般用它來標記一次唯一的請求和其對應的回復;
- 優先級 Priority,一個枚舉類型,用於指定請求發送的優先級。如果你同時投遞了幾個請求,則優先級高的請求將會優先發送。但是,這個也取決於具體的實現。QSocket 本身會提供一個自己封裝的多會話並行發送協議,它允許在現有會話發送過程中插入高優先級的會話發送,以避免低優先級的長時間數據傳輸請求影響普通或緊急業務數據的傳送。不過這需要服務器端也要兼容 QSocket 的這個協議。在一般的場景實現中,阿門,忽略它吧,很少有協議支持它。
- 關聯的連接對象 Connection,這個不用說啥了。
- 記錄請求內容的 RequestData,在接收到請求后,要處理的數據都在里面了。
- 記錄回應內容的 ReplyData,在接到回應后,需要處理的數據都在里面了。
- 錯誤代碼 ErrorCode 和錯誤提示 ErrorMsg,這個就沒啥可說的了。
- 發送請求的函數 PostRequest 和 SendRequest,一個是異步,一個是同步。異步的需要提供一個回調函數,以便在得到結果時響應,如果不提供,則意味着忽略返回結果的處理。
- 發送回應的函數 PostReply。
- IQConnection
Connection,連接,這個搞網絡編程的都明白是啥,就不多說。需要注意一點,在 QSocket 中,UDP 協議也是有連接的,只不過這種連接是有限制的:
首先,由於 UDP 協議本身是無連接的,超過一段時間未收發數據,會被網關給斷掉,所以這個連接本身會內置一些輔助的連接保持功能(如無數據,每隔10秒會發送一個無載荷的空 UDP 數據包,以保持網關會話的有效性)。
其次,UDP 協議本身是不保證數據的准確到達的,所以基於 UDP 的連接本身同樣也不保證這一點。但 QSocket 會提供更高一級別的封裝,來保證 UDP 協議達到類似於 TCP 的有連接效果,同樣,這種封裝協議的代價就是服務器端也需要采用同樣的協議。
IQConnection 提供的主要內容如下:- 本地綁定的地址 LocalAddr;
- 遠程綁定的地址 RemoteAddr;
- 創建一個新請求的函數 NewRequest;
- 發送和接收數據的接口:Post/Send/Recv/Peek。
- IQDataCodec
Data Codec ,數據編碼和解碼接口。主要用於數據的加密、壓縮以及其它打包的處理工作。一次傳輸過程,可能要經過多個 IQDataCodec 進行流水線處理,所以它的工作是否正常,嚴重依賴於發送和接收端的設置是否一致,包括順序。比如,我們先壓縮后加密和先加密,后壓縮就是兩個不同的選擇。編碼的過程,是按照 IQDataCodec 的添加順序進行的,解碼的過程,則是按照添加順序的逆序執行的。
IQDataCodec 提供的主要內容如下:- 編碼函數 Encode
- 解碼函數 Decode
- 編解碼器名稱 Name
- IQCommand
Command,命令。它的主要作用是配合 IQCommandDispatcher,管理支持的請求命令的處理函數。一般來說,一個命令只應該有一個處理函數,不過 QSocket 支持一個命令交由多個函數來處理,它會在接收到請求后,傳遞給第一個處理函數,如果第一個處理函數未設置 AHandled 參數為 true,則會交給第二個函數處理,直到所有的處理函數都調用完成或者 AHandled 在某個處理函數中返回了 true,才會中止處理。這主要是方便一些通知類型的命令的處理。
IQCommand 提供的主要內容如下:- 命令 Id,是否有意義取決於具體的協議,這一般用於基於數值命令驅動的處理
- 命令路徑 NamePath,這一般用於字符類命令驅動的協議的處理
- 命令響應列表的管理函數及屬性:Add/Delete/Remove/Clear/Count/Handlers
- 命令處理函數 HandleCommand
- IQCommandDispatcher
Command Dispatcher,命令調度器。它負責將接收的請求中的內容進行解碼,取出其中的命令,然后查找注冊的 IQCommand,並調用相應的 IQCommand 的 HandleCommand 方法進行實際的處理。
IQCommandDispatcher 提供的主要內容如下:- 命令注冊及管理函數、屬性:Add/Delete/Remove/Clear/ByNamePath/ById/Count/Commands
- 判斷是否能夠派發指定的數據內容的函數:CanDispatch
- 執行實際派發的函數:Dispatch
- IQDataBuffer
Data Buffer,數據緩沖區實現。它支持四種不同的緩沖區,以便根據實際需要來創建不同類型的緩沖區(關於它實現的主要內容省略):- 內存緩沖區,直接使用 NewBuffer 就可以創建一個內在緩沖區對象;
- 文件緩沖區,直接使用 NewBuffer ,將要保存緩沖內容的文件名當做參數傳遞,就可以創建一個文件緩沖對象。這適用於文件或大型的數據請求的處理。
- 流緩沖區,直接使用 NewBuffer,將一個 TStream 類型的對象傳遞進去做為參數,就可以創建一個流緩沖對象,文件緩沖區實際上也是基於它實現的。
- 共享緩沖區,直接使用 ShareBuffer 函數,將一個已有的緩沖區接口做為參數傳入,就可以創建一個共享的流緩沖對象,通過 ShareBuffer 返回的 IQDataBuffer 可以獨立使用,共同訪問同一個源 IQDataBuffer 的數據。通過 ShareBuffer 訪問源數據的內容是線程安全的。
- IQSocketFactory
Factory,就是工廠了。這個工廠是一個不負責任的工廠,只負責生產出 Transport 和 Connection 對象,不負責售后。它的主要目的是簡化上層的各種東西的創建,如果我們要創建一個面向Tcp 連接,則我們可以調用 SocketFactory.NewCo6nnection(‘tcp://connection’) 得到一個 TCP 連接對象,或者我們直接調用 SocketFactory.NewConnection(‘tcp://connection?dst=192.168.0.1:980’) 來創建一個連接到 192.160.0.1 的 980 端口的連接對象。
IQSocketFactory 生產以下內容:- IQTransport,URI 的 host 部分為 transport,Scheme 部分則由相應的 IQTransport 實現自己約定。
- IQConnection,URI 的 host 部分為 connection,Scheme 部分同樣由相應的 IQConnection 實現自己約定。
- IQDataBuffer,URI 的 host 部分為 buffer,scheme 包括:mem/file 兩種,不支持流緩沖區和共享緩沖區
- IQCommandDispatcher,URI 的 host 部分為 dispatcher,Scheme 部分同樣由相應的 IQCommandDispatcher 實現自己約定。
- IQRequest,URI 的 host 部分為 request,一般更推薦調用 IQConnection 的 NewRequest 來實現。Scheme 部分同樣由相應的 IQRequest 實現自己約定。
- TQAddr
Addr(ess),地址的歸一化封裝。在 QSocket 中,各種協議的不同地址表達形式,都通過 TQAddr 進行封裝。它支持IPv4/IPv6/UnixDomain/NamePipe/FilePath類型的地址管理,主要提供的內容如下:- 類型轉換重載 Implicit,實現將 IPv4/IPv6 地址直接轉換為相應的 TQAddr 結構
- 生成相應類型的 TQAddr 結構的輔助函數:MakeIPv4/MakeIPv6/MakeAddr
- 生成 IPv4/IPv6 協議對應接口類型的 ToIPAddr
- 地址類型屬性:AddrType
- 完整地址文本表示:Text
- 僅地址的文本表示:AddrOnly
- 端口號:Port
- 其它屬性:AsIPv4/AsIPv6
上述這些部分構成了 QSocket 的核心,后面更復雜的是實現上面說的這一堆東西。其中,TQAddr 和 IQDataBuffer 的接口已經實現完成,但 QSocket 的萬里長征,這才是第一步,希望在開發和測試過程中,大家都多多參與。
附:QSocket 通訊過程示意圖
http://blog.qdac.cc/?p=4408