通常一般的異常程式能夠捕捉到,但是由於某端因為斷網、斷電而無法完成四次揮手時,tcp連線正常但是socket鏈路連線異常,在此情況下一般存在兩種解決方式:
心跳檢測機制
客戶端定時傳送心跳檢測包給服務端,服務端收到該心跳包後回乙個對應的心跳包,告知客戶端自己正常。如果在設定的時間期限裡沒收到服務端發回的心跳檢測包,那麼客戶端就主動斷開socket並且嘗試重新連線。
一般來說,服務端會與多個客戶端進行通訊,於是可以設定時間集合,當每次接收到客戶端發來的資訊(包括正常通訊資訊和心跳包)時就更新最後一次通訊時間,設定乙個定時器,定時檢測時間集合中超時的客戶端並且將其socket釋放掉。
心跳檢測機制在我的這篇部落格有過說明
keep-alive機制
網路異常斷開原因歸納起來主要有以下兩種:
1、客戶端程式異常。
對於這種情況,我們很好處理,因為客戶端程式異常退出會在服務端引發connectionreset的socket異常(就是winsock2中的10054異常)。只要在服務端處理這個異常就可以了。
2、網路鏈路異常。
如:網線拔出、交換機掉電、客戶端機器掉電。當出現這些情況的時候服務端不會出現任何異常。
如果服務端不能夠返回資訊到客戶端,那麼心跳檢測機制也就無用了。例如之前我所在的工廠產線上會有掃瞄槍掃瞄產品條碼,但是有時因為斷網就會導致tcp連線正常但是socket鏈路連線異常使得掃瞄槍無法正常工作,這種情況人為又無法發現,導致產線漏掃很多產品,導致生產滯後。
該掃瞄槍由硬體提供商開發,我無法修改掃瞄槍裡面設定的程式讓掃瞄槍返回狀態,於是心跳檢測機制在該場景下就無法應用。
這時就需要keepalive機制。
tcp有乙個連線檢測機制,就是如果在指定的時間內(一般為2個小時)沒有資料傳送,會給對端傳送乙個keep-alive資料報,使用的序列號是曾經發出的最後乙個報文的最後乙個位元組的序列號,對端如果收到這個資料,回送乙個tcp的ack,確認這個位元組已經收到,這樣就知道此連線沒有被斷開。如果一段時間沒有收到對方的響應,會進行重試,重試幾次後,向對端發乙個reset,然後將連線斷掉。
我們可以更改keepalive引數,縮短檢測時間,以下是keepalive方法(vb.net)
'onoff:是否啟用keep-alive
'keepalivetime:多長時間後開始第一次探測(單位:毫秒)
'keepaliveinterval:探測時間間隔(單位:毫秒)
private
function keepalive(
byval onoff as
integer
,byval keepalivetime as
integer
,byval keepaliveinterval as
integer)as
byte()
dim buffer()as
byte
=new
byte(12
) {}
bitconverter.getbytes(onoff).copyto(buffer,0)
bitconverter.getbytes(keepalivetime).copyto(buffer,4)
bitconverter.getbytes(keepaliveinterval).copyto(buffer,8)
return buffer
endfunction
在連線服務端後呼叫上述方法就啟動了keepalive
csocket.connect(saddress,
cint
(sport)
)'設定keepalive
csocket.iocontrol(iocontrolcode.keepalivevalues, keepalive(1,
10000
,2000),
nothing
)
結合keepalive機制和ping 服務端ip位址我們可以實現客戶端的自動重連(當然用心跳檢測機制也能夠做到重連),因為如果keepalive機制啟用,服務端又因為斷網導致鏈路層連線失敗,那麼在設定的時間到達後keepalive會自動將socket釋放,這樣客戶端的csocket.receive方法就會出現異常,於是我們就可以利用該異常實現重新連線。
'連線狀態
private isconnect as
boolean
=false
'重連計數器
private reconnect as
integer=0
'連線掃瞄器
private
sub connectfixscan(
)while isconnect =
false
dim m_ping as
newsystem.net.networkinformation.ping
dim m_pingreply as
system.net.networkinformation.pingreply = m_ping.send(saddress,
1000
)'設定為自己要ping的ip位址
'如果正常且未連線,連線掃瞄器
if m_pingreply.status
= net.networkinformation.ipstatus.success then
reconnect =
0 csocket =
new socket(addressfamily.internetwork, sockettype.stream
, protocoltype.tcp)
csocket.connect(saddress,
cint
(sport)
)'設定keepalive
csocket.iocontrol(iocontrolcode.keepalivevalues, keepalive(1,
10000
,2000),
nothing
) isconnect =
true
endif
'如果不正常且未連線,提示相關資訊
if m_pingreply.status
<> net.networkinformation.ipstatus.success then
if reconnect =
0then
writelog("未檢查到相關裝置,請檢查網路!在此期間程式將自動連線裝置,直至連線成功!")
invokeofshowmessage("未檢查到相關裝置,請檢查網路!在此期間程式將自動連線裝置,直至連線成功!")
elseif reconnect mod10=
0then
dim recontime as
integer=3
* reconnect
endif
reconnect = reconnect +
1 begininvoke(
new methodinvoker(
addressof
me.update)
) thread.sleep
(2000
)end
ifend
while
begininvoke(
new methodinvoker(
addressof
me.update)
) recethread =
new thread(
addressof receivemessage)
recethread.isbackground =
true
recethread.start(
)end
sub'建立委託重新進行連線掃瞄槍的方法
private
sub callconnectfixscancallback(
) invoke(
new connectfixscancallback(
addressof connectfixscan)
)end
subprivate
delegate
sub connectfixscancallback(
)'接收掃瞄器資訊
private
sub receivemessage(
)dim ireceive as
integer
while0=
0try
ireceive = csocket.receive(srecbuffer,
0, srecbuffer.length
, socketflags.none)
'做收到資料的邏輯處理
catch ex as socketexception
csocket.close()
isconnect =
false
invokeofshowmessage("通訊異常,程式將重新連線固定掃瞄器!")
'重連 callconnectfixscancallback(
) recethread.abort(
)end
trysystem.threading.thread.sleep
(1000
)'me.update()
begininvoke(
new methodinvoker(
addressof
me.update)
)end
while
endsub
重連時的判斷邏輯可以再優化一下,該思路進行重連是完全可行的 socket幾種解決方式
1.net的socket 思想 socketserver.js const net require net const server new net.createserver let clients let clientname 0 server.on connection client clien...
C 程序間通訊的幾種方式 Socket通訊
方式二 socket通訊 套接字 socket 是支援tcp ip協議 安全 和udp協議 快速 的網路通訊的基本操作單元。套接字包含進行網路通訊必須的五種資訊 連線使用的協議,本地主機的ip位址,本地程序的協議埠,遠地主機的ip位址,遠地程序的協議埠。為了滿足不同程式對通訊質量和效能的要求,一般的...
android ANR異常及其解決方式
anr定義 解決anr異常概述 考慮上面的anr定義,讓我們來研究一下為什麼它會在android應用程式裡發生和如何最佳構建應用程式來避免anr。android應用程式通常是執行在乙個單獨的執行緒 例如,main 裡。這意味著你的應用程式所做的事情如果在主線程裡占用了太長的時間的話,就會引發anr對...