乙個Socket通訊案例

2021-09-24 13:49:41 字數 3143 閱讀 8800

公司產品客戶端需要通過socket和c++後台互動,大概是這麼乙個流程:

通過配置檔案,解析伺服器的位址和埠;

開啟socket通道,建立和伺服器的長鏈結;

和伺服器通訊,傳送指令和接收指令等;

應用退出,關閉連線。

問題在這裡,和伺服器通訊,拿到乙個完整的訊息後,通過解析指令的引數,進行不同的處理,現有的**,把所有的邏輯**大部分寫在了乙個switch**塊裡面,乙個函式七八百行,中間參雜了各種ui的操作整個人都感覺不好了…

分析這個問題,其實和以前做過的藍芽通訊是一樣的,就是服務端傳送乙個資料過來,如byte(也可能是直接解析byte得到乙個json字串)。客戶端通過socket接收,先解析判斷,等接收乙個完資料,整再傳送乙個訊息給客戶端上層,並把資料帶過去。上層拿到完整的資料,先根據協議,解析出是具體哪個指令,引數等。然後根據具體指令,執行對應的業務。這就是乙個套路,對於socket,藍芽是乙個道理的,其實就是對訊息的乙個分發處理。

現有**的實現是把所有**放在乙個switch**塊中(其實連dosomething都沒有):

int cmd;

// 這個就是後台發過來的具體哪個指令的引數

message msg;

// 指令帶的引數

switch

(cmd)

這種寫法,也不是不行,能執行,當時也就在業務不多的時候適用,如果後台定義的指令幾十上百個呢?所有的業務全部耦合在一起,如果需求改動,說不定就牽一髮而動全身了,最重要的一點就是,這種沒有設計的**,乙個函式長達七八百行,難看懂難維護。

這種大函式的做法可以肯定是不對的,第一,耦合性強,所有業務**和功能**揉在一起;第二,可維護性太低,大函式,業務複雜,除錯困難,除了寫這段**的人熟悉,一旦換人接手,就是乙個大坑;第三,可擴充套件性不強,如果需求改動或者增加乙個指令,就得改這一段**。要解決這一類問題,就得從降低耦合性,提高可維護性和可擴充套件性三個方向著手。所以,如何做呢?通過抽象,將訊息接收和訊息傳送分離開來,先定義基類,再每個命令定義乙個類,最後寫乙個統一管理的類。為了復用,可以使用乙個訊息池技術,如此達到接耦,提高可擴充套件和可維護性。簡單分解為三個部分:

訊息池接收伺服器指令管理

本地傳送指令管理

這個是從一篇寫自定義訊息佇列的文章中看到而得到啟發(物件池),後台發過來的訊息,其實是乙個高度抽象的協議(protobuf,json等),解析過後得到一般格式固定,假設定義為message。為了提高效率和減少記憶體開銷,可以使用物件池技術進行復用。

message

public

class

message

messagepool
public

class

messagepool

extends

objectpool

public

messagepool

(int capacity)

@override

protected message[

]createobjpool

(int capacity)

@override

protected message createnewobj()

}

objectpool
public

abstract

class

objectpool

ipooledobject

>

protected

abstract t[

]createobjpool

(int capacity)

;protected

abstract t createnewobj()

;public

final t get()

else

return obj;

}private t findfreeobj()

}return command;

}public

final

void

recycleobj

(t ms)}}

}

message是對協議的乙個抽象,messagepool是為了提高效率的優化。在客戶端收到訊息後,客戶端需要對訊息進行處理。為了提高可擴充套件性,和接耦,通過抽象進行統一管理。

icommand

public

inte***ce

icommand

extends

runnable

public

abstract

class

abscommand

implements

icommand

public

abstract

void

execute()

;public abscommand setmsg

(message message)

protected

void

executeasync()

protected

void

executemainthread()

protected

void

schedule

(long delay)

}

cmddispatcher
public

class

cmddispatcher

private hashmap

mcommands =

newhashmap

<

>()

;private

cmddispatcher()

private

void

registerallcommands()

private

void

registercommand

(abscommand command)

public

void

execute

(message message)

}}

傳送socket指令和接收socket指令相似,按照同乙個套路來寫即可,因為時間關係,沒有寫。

Socket通訊案例

socket通訊案例 服務端 region 服務端 int port 1234 string host 127.0.0.1 ipaddress ip ipaddress.parse host ipendpoint ipe new ipendpoint ip,port socket ssocket n...

Socket通訊成功案例

socket通訊案例 region 服務端 int port 1234 string host 127.0.0.1 ipaddress ip ipaddress.parse host ipendpoint ipe new ipendpoint ip,port socket ssocket new s...

乙個簡單的Socket通訊例子

睡眠一段時間再傳送訊息 sleep start private static void sleep catch interruptedexception e public class server catch ioexception e public void start private void ...