最近在維護公司的一個socket服務端工具,該工具主要是提供兩個socket server服務,對兩端連接的程序進行數據的透明轉發。
程序運行期間,遇到一個問題,程序的一端是GPRS設備,眾所周知,GPRS設備的網絡連接十分的不問題,由此會產生不少的“奇怪”問題。
實際過程中,程序運行幾個小時后,無線端的socket server斷開就再也無法打開。找了很久都沒發現。
通過wireshark抓取通信報文,一般是在TCP的三次握手時出的問題。
常規的TCP三次握手,由TCP的標識可簡單看作:SYN-SYN ACK-ACK,實際遇到問題時,標識為:SYN-RST ACK。
可以明顯看出,服務端發出了重置的標識,用來積極的拒絕了客戶端的連接。
程序的server部分代碼,采用的常規的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); //再次投遞接收,實現一直接收socket的操作 listener.BeginAccept(null, receivedDataSize, new AsyncCallback(AcceptReceiveDataCallback), listener); }
經過問題的定位,可以判斷可能是程序的異步接收回調中出了問題,但實際添加調試信息后發現,在程序出現端口無法打開后,再進行回調函數操作,并無信息打出。
TCP異步編程,一般是成對的出現beginXXX...endXXX,再通過回調函數進行具體處理。
如下為accept的回調函數,代碼中使用了try..catch來捕獲異常,實際問題可能就出在這里,代碼如下:
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; } //再次投遞接收,實現一直接收socket的操作 listener.BeginAccept(null, receivedDataSize, new AsyncCallback(AcceptReceiveDataCallback), listener); }
程序在實際出現端口不能打開之前曾經進入過“異常1”/“異常2”,判斷很可能是程序進行了return,而無法再次投遞接收操作。
此時所有的端口打開操作,都會進入socket.listen(backlog)的隊列中,當accpet隊列中的內容無法通過完整begin..end操作取出,隊列滿后socket的底層協議棧則會拒絕新的socket連入。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。