最近在維護(hù)公司的一個(gè)socket服務(wù)端工具,該工具主要是提供兩個(gè)socket server服務(wù),對(duì)兩端連接的程序進(jìn)行數(shù)據(jù)的透明轉(zhuǎn)發(fā)。
網(wǎng)站建設(shè)公司,為您提供網(wǎng)站建設(shè),網(wǎng)站制作,網(wǎng)頁設(shè)計(jì)及定制網(wǎng)站建設(shè)服務(wù),專注于企業(yè)網(wǎng)站制作,高端網(wǎng)頁制作,對(duì)垃圾桶等多個(gè)行業(yè)擁有豐富的網(wǎng)站建設(shè)經(jīng)驗(yàn)的網(wǎng)站建設(shè)公司。專業(yè)網(wǎng)站設(shè)計(jì),網(wǎng)站優(yōu)化推廣哪家好,專業(yè)seo優(yōu)化優(yōu)化,H5建站,響應(yīng)式網(wǎng)站。程序運(yùn)行期間,遇到一個(gè)問題,程序的一端是GPRS設(shè)備,眾所周知,GPRS設(shè)備的網(wǎng)絡(luò)連接十分的不問題,由此會(huì)產(chǎn)生不少的“奇怪”問題。
實(shí)際過程中,程序運(yùn)行幾個(gè)小時(shí)后,無線端的socket server斷開就再也無法打開。找了很久都沒發(fā)現(xiàn)。
通過wireshark抓取通信報(bào)文,一般是在TCP的三次握手時(shí)出的問題。
常規(guī)的TCP三次握手,由TCP的標(biāo)識(shí)可簡(jiǎn)單看作:SYN-SYN ACK-ACK,實(shí)際遇到問題時(shí),標(biāo)識(shí)為:SYN-RST ACK。
可以明顯看出,服務(wù)端發(fā)出了重置的標(biāo)識(shí),用來積極的拒絕了客戶端的連接。
程序的server部分代碼,采用的常規(guī)的TCP異步編程方式,一下是MSDN代碼
// This server waits for a connection and then uses asynchronous operations to // accept the connection with initial data sent from the client. // Establish the local endpoint for the socket. IPHostEntry ipHostInfo = Dns.GetHostEntry(Dns.GetHostName()); IPAddress ipAddress = ipHostInfo.AddressList[0]; IPEndPoint localEndPoint = new IPEndPoint(ipAddress, 11000); // Create a TCP/IP socket. Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp ); // Bind the socket to the local endpoint, and listen for incoming connections. listener.Bind(localEndPoint); listener.Listen(100); while (true) { // Set the event to nonsignaled state. allDone.Reset(); // Start an asynchronous socket to listen for connections and receive data from the client. Console.WriteLine("Waiting for a connection..."); // Accept the connection and receive the first 10 bytes of data. // BeginAccept() creates the accepted socket. int receivedDataSize = 10; listener.BeginAccept(null, receivedDataSize, new AsyncCallback(AcceptReceiveDataCallback), listener); // Wait until a connection is made and processed before continuing. allDone.WaitOne(); } } public static void AcceptReceiveDataCallback(IAsyncResult ar) { // Get the socket that handles the client request. Socket listener = (Socket) ar.AsyncState; // End the operation and display the received data on the console. byte[] Buffer; int bytesTransferred; Socket handler = listener.EndAccept(out Buffer, out bytesTransferred, ar); //再次投遞接收,實(shí)現(xiàn)一直接收socket的操作 listener.BeginAccept(null, receivedDataSize, new AsyncCallback(AcceptReceiveDataCallback), listener); }
經(jīng)過問題的定位,可以判斷可能是程序的異步接收回調(diào)中出了問題,但實(shí)際添加調(diào)試信息后發(fā)現(xiàn),在程序出現(xiàn)端口無法打開后,再進(jìn)行回調(diào)函數(shù)操作,并無信息打出。
TCP異步編程,一般是成對(duì)的出現(xiàn)beginXXX...endXXX,再通過回調(diào)函數(shù)進(jìn)行具體處理。
如下為accept的回調(diào)函數(shù),代碼中使用了try..catch來捕獲異常,實(shí)際問題可能就出在這里,代碼如下:
public static void AcceptReceiveDataCallback(IAsyncResult ar) { // Get the socket that handles the client request. Socket listener = (Socket) ar.AsyncState; // End the operation and display the received data on the console. byte[] Buffer; int bytesTransferred; try{ Socket handler = listener.EndAccept(out Buffer, out bytesTransferred, ar); } catch(異常1 e){ ... return; } catch(異常2 e){ ... return; } //再次投遞接收,實(shí)現(xiàn)一直接收socket的操作 listener.BeginAccept(null, receivedDataSize, new AsyncCallback(AcceptReceiveDataCallback), listener); }
程序在實(shí)際出現(xiàn)端口不能打開之前曾經(jīng)進(jìn)入過“異常1”/“異常2”,判斷很可能是程序進(jìn)行了return,而無法再次投遞接收操作。
此時(shí)所有的端口打開操作,都會(huì)進(jìn)入socket.listen(backlog)的隊(duì)列中,當(dāng)accpet隊(duì)列中的內(nèi)容無法通過完整begin..end操作取出,隊(duì)列滿后socket的底層協(xié)議棧則會(huì)拒絕新的socket連入。
另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)scvps.cn,海內(nèi)外云服務(wù)器15元起步,三天無理由+7*72小時(shí)售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國服務(wù)器、虛擬主機(jī)、免備案服務(wù)器”等云主機(jī)租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡(jiǎn)單易用、服務(wù)可用性高、性價(jià)比高”等特點(diǎn)與優(yōu)勢(shì),專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場(chǎng)景需求。