最近在维护公司的一个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连入。

此处是个不明显的坑,花了好几天才发现,实际修改情况待检验。。。

一种C# TCP异步编程中遇到的问题的更多相关文章

  1. WPF工作笔记:本地化支持、主进程通知、两种最常用异步编程方式

    1.本地化支持 (1)重写控件默认的依赖属性LanguageProperty FrameworkElement.LanguageProperty.OverrideMetadata( typeof(Fr ...

  2. 【转】C# Async/Await 异步编程中的最佳做法

    Async/Await 异步编程中的最佳做法 Stephen Cleary 近日来,涌现了许多关于 Microsoft .NET Framework 4.5 中新增了对 async 和 await 支 ...

  3. C#异步编程中的最佳实践(做法)

    原文地址Stephen Cleary 写得很详细,尤其讲到了 GUI 上下文调用,在APS.NET中它会阻塞 GUI 线程,从而导致死锁.而控制台中却不存在这个问题. 比如开发过程中本地写控制台程序测 ...

  4. 【Linux网络编程】TCP网络编程中connect()、listen()和accept()三者之间的关系

    [Linux网络编程]TCP网络编程中connect().listen()和accept()三者之间的关系 基于 TCP 的网络编程开发分为服务器端和客户端两部分,常见的核心步骤和流程如下: conn ...

  5. 探究SynchronizationContext在.Net异步编程中的地位

    原文:探究SynchronizationContext在.Net异步编程中的地位 引言: 多线程编程/异步编程非常复杂,有很多概念和工具需要去学习,贴心的.NET提供Task线程包装类和await/a ...

  6. 你不知道的this—JS异步编程中的this

    Javascript小学生都知道了javascript中的函数调用时会 隐性的接收两个附加的参数:this和arguments.参数this在javascript编程中占据中非常重要的地位,它的值取决 ...

  7. 【Linux 网络编程】TCP网络编程中connect()、listen()和accept()三者之间的关系

    基于 TCP 的网络编程开发分为服务器端和客户端两部分,常见的核心步骤和流程如下: connect()函数:对于客户端的 connect() 函数,该函数的功能为客户端主动连接服务器,建立连接是通过三 ...

  8. 异步编程中使用帮助类来实现Thread.Start()的示例

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...

  9. 异步编程中的最佳做法(async await)

    阅读1:http://blog.csdn.net/nacl025/article/details/9163495 阅读2:http://www.cnblogs.com/x-xk/archive/201 ...

随机推荐

  1. ptrace x64 转

    #include <sys/ptrace.h> #include <sys/types.h> #include <sys/wait.h> #include < ...

  2. 设置EXCEL2010打开多个独立窗口

            最近发现一个奇怪的问题,发现office中的word和ppt在我使用笔记本分屏幕(双屏)的时候都可以将2份文档分别在2个窗口打开,但是在使用excel的时候却发现不行,最后研究发现原因 ...

  3. Ruby on Rails Tutorial 第六章 用户模型

    1.用户模型(1)数据库迁移Rails默认使用关系数据库存储数据,数据库中的表有数据行组成,每一行都有相应的列,对应数据属性.把列名命名为相应的名字后,ActiveRecord会自动把他们识别为用户对 ...

  4. Centos自动登录系统并自动打开VNC Server

    系统自动登录 修改配置文件 sudo vim /etc/gdm/custom.conf 增加配置 [daemon] AutomaticLogin=spark AutomaticLoginEnable= ...

  5. Linux命令之hwclock

    转载:http://codingstandards.iteye.com/blog/804830 用途说明 hwclock命令,与clock命令是同一个命令,主要用来查询和设置硬件时钟(query an ...

  6. UTF8 与 UTF16 编码

    Unicode 的发展,英文好的直接去 unicode.org 上去看吧,不好的可以移步到这里 看dengyunze的总结:<关于UTF8,UTF16,UTF32,UTF16-LE,UTF16- ...

  7. XML 格式转JSON 格式

    #import <Foundation/Foundation.h> #pragma GCC diagnostic push #pragma GCC diagnostic ignored & ...

  8. 写入文件txt

    FileStream fs = new FileStream(@"d:\service.txt", FileMode.OpenOrCreate, FileAccess.Write) ...

  9. IE8 innerHTML赋值时包含多级HTML标签时的解决方案

    var inhtml = ''; var font = document.createElement("font"); var a = document.createElement ...

  10. javaweb学习总结二十一(servlet开发入门、servlet生命周期以及调用过程)

    一:servlet开发入门 servlet是sun公司一门开发动态web资源的技术,下面编写一个servlet入门程序: 1:在tomcat服务器webapps目录下新建firstServlet目录, ...