我的程序在单位测试似乎没什么问题但是具体用在中控室,我用的是异步方式!!服务器用路由器端口映射到,我具体用的机器。端口是7910。服务器端程序一直启动着。可户端主动连接服务器端!
可户端程序没问题,是下面的。
但是有的时候路由器会不好用(陆游器质量不好),断时间内测试过,服务器从不好用那段时间到好用那段时间,服务器端程序没什么问题!但长不好用的那段时间长了,在连服务器端程序似乎就不触发事件了(或者连接不好用了),服务器端程序 是一直启动的!服务停止在启动也不行!我现在不确定 我的程序在一个稳定的网络是否也出现这种情况,不过一般情况下是没有问题的,我在的时候一般没问题,有时候第2天一来就出现以上情况!请高手指教,代码如下
/// <summary>
/// 客户端建立连接事件
/// </summary>
public event  NetEvent ClientConn; /// <summary>
/// 客户端关闭事件
/// </summary>
public event  NetEvent ClientClose;
/// <summary>
/// 客户端连接处理函数
/// </summary>
/// <param name="iar">欲建立服务器连接的Socket对象</param>
protected virtual void AcceptConn(IAsyncResult iar)
{
//如果服务器停止了服务,就不能再接收新的客户端
if( !_isRun)
{
return;
} //接受一个客户端的连接请求
Socket oldserver = ( Socket ) iar.AsyncState; Socket client = oldserver.EndAccept(iar); //检查是否达到最大的允许的客户端数目
if( _clientCount == _maxClient )
{
//服务器已满,发出通知
if( ServerFull != null )
{
ServerFull(this, new NetEventArgs( new Session(client)));
}
    
}
else
{
    
Session newSession = new Session( client );
_sessionTable.Add(newSession.ID, newSession);
     //客户端引用计数+1
_clientCount ++;
//开始接受来自该客户端的数据
client.BeginReceive( _recvDataBuffer,0 , _recvDataBuffer.Length, SocketFlags.None,
new AsyncCallback(ReceiveData), client);
//新的客户段连接,发出通知
if( ClientConn != null )
{
ClientConn(this, new NetEventArgs(newSession ) );
}
} //继续接受客户端
_svrSock.BeginAccept(new AsyncCallback( AcceptConn ), _svrSock);
}

解决方案 »

  1.   

    public virtual void Start()
    {
    if( _isRun )
    {
    throw (new ApplicationException("TcpSvr已经在运行."));
    }
     
    _sessionTable = new Hashtable(55);
     
    _recvDataBuffer = new byte[DefaultBufferSize]; //初始化socket
    _svrSock = new Socket( AddressFamily.InterNetwork, 
    SocketType.Stream, ProtocolType.Tcp );  //IPAddress ip = IPAddress.Parse("192.168.0.2");
    //IPEndPoint iep = new IPEndPoint( ip, 7910);
    //绑定端口 
    IPEndPoint iep = new IPEndPoint( IPAddress.Any, _port); 
    _svrSock.Bind(iep);  //开始监听
    _svrSock.Listen(55); //设置异步方法接受客户端连接
    _svrSock.BeginAccept(new AsyncCallback( AcceptConn ), _svrSock); _isRun = true; }

    /// <summary>
    /// 服务器程序的事件参数,包含了激发该事件的会话对象
    /// </summary>
    public class NetEventArgs:EventArgs
    { #region 字段 /// <summary>
    /// 客户端与服务器之间的会话
    /// </summary>
    private Session _client; #endregion  #region 构造函数
    /// <summary>
    /// 构造函数
    /// </summary>
    /// <param name="client">客户端会话</param>
    public NetEventArgs(Session client)
    {
    if( null == client)
    {
    throw(new ArgumentNullException());
    } _client = client;
    }
    #endregion  #region 属性
      
    /// <summary>
    /// 获得激发该事件的会话对象
    /// </summary>
    public Session Client
    {
    get
    {
    return _client;
    }
       
    } #endregion 
      
    }
      

  2.   

    前台
    svr.ServerFull += new NetEvent(this.ServerFull);
    svr.ClientConn += new NetEvent(this.ClientConn);
    //客户端关闭
    svr.ClientClose += new NetEvent(this.ClientClose); //接收到数据

    svr.RecvData += new NetEvent(this.RecvData);
      

  3.   

    我的意思是,运行一段时间后,为什么可户端连接服务器端,不触发事件了,或者连不上了!(中间陆游器可能不好用一段时间,好用了后依然连不上(不触发事件),(网断了10分钟在连没问题)),
    我没在 AcceptConn 里设置断点。因为我一般碰不找这样的时候,只有晚上走,第2天来才能碰到!
      

  4.   

    如果路由器长时间不好的话,socket是会断开的吧,只是可能由于TCP协议的缺陷,可能两边都认为socket还是正常的
      

  5.   

    如果路由器长时间不好的话,socket是会断开的吧,只是可能由于TCP协议的缺陷,可能两边都认为socket还是正常的但是,恢复正常了后,我又重新停止服务,然后在从新运行 Start()从新启动服务,可户端连接服务器端还是触发不了事件。但是重新启动程序,一切都正常了。请问这是怎么回事??我的程序似乎没问题啊。仔细看了
      

  6.   

    一个稳定的可连续运行的TCPIP程序不是那么好写的,
    很多超时及出错检查与恢复是必需的。像你这种情况,可以考虑当服务器长时间无客户连接时,自动重新初始化。
      

  7.   

    重新初始化 倒没实验过,但 重新启动服务 是连不上的,除非重新启动程序,中间发生了什么事,就是陆游器的问题了。感觉TCP IP似乎本身就不太完善!不过具体是什么问题不得而知啊
      

  8.   

    看看netstat,有的情况网络中断socket是没法自动判断出来,比如在windows里“禁用”一个连接,看TCP连接就还是established。类似这种情况就不能依赖网络事件,自己做心跳检测吧。
      

  9.   

    按照楼主所说,拔掉路由器服务没有异常,所以与连接的维持可能无关。
    权宜之计:另外写个客户端程序用计划任务或者定时服务部署到服务器上,定时调用服务,发生异常时则使用WMI,或者System.Diagnostics.Process "net stop ;net start",重启服务
      

  10.   

    那时候连都连不上,还谈什么心跳??所有的客户端都连不上了,心跳主要目的是用来区别ID的。所以得用时间判断某个ID号,是否在线。
      

  11.   

    摘要:本文介绍了Excel对象、C#中的受管代码和非受管代码,并介绍了COM组件在.NET环境中的使用。
    关键词:受管代码;非受管代码;Excel对象;动态连接库  
    0  引言
    Excel是微软公司办公自动化套件中的一个软件,他主要是用来处理电子表格。Excel以其功能强大,界面友好等受到了许多用户的欢迎。在设计应用系统时,对于不同的用户,他们对于打印的需求是不一样的,如果要使得程序中的打印功能适用于每一个用户,可以想象程序设计是十分复杂的。由于Excel表格的功能强大,又由于几乎每一台机器都安装了它,如果把程序处理的结果放到Excel表格中,这样每一个用户就可以根据自己的需要在Excel中定制自己的打印。这样不仅使得程序设计简单,而且又满足了诸多用户的要求,更加实用了。那么用Visual  C#如何调用Excel,如何又把数据存放到Excel表格中?本文就来探讨上述问题的解决办法。
    1  Excel对象
      微软的Excel对象模型包括了128个不同的对象,从矩形,文本框等简单的对象到透视表,图表等复杂的对象.下面我们简单介绍一下其中最重要,也是用得最多的四个对象。
    (1)  Application对象。Application对象处于Excel对象层次结构的顶层,表示Excel自身的运行环境。  (2)  Workbook对象。Workbook对象直接地处于Application对象的下层,表示一个Excel工作薄文件。
    (3)  Worksheet对象。Worksheet对象包含于Workbook对象,表示一个Excel工作表。
    (4)  Range对象。Range对象包含于Worksheet对象,表示Excel工作表中的一个或多个单元格。
    2  C#中的受管代码和非受管代码  
    在.NET公用语言框架内运行的程序为受管代码。受管代码在程序中所有类型都受到严格检查,没有指针,对内存的管理完全由运行系统控制。受控状态下,编写程序更为容易,且更少出错,我们可以花更多的时间在解决实际问题上而不是在计算机语言问题上。相对而言,那些在.NET框架外运行的程序为非受管代码。比如:COM组件、ActiveX组件、Win32  API函数、指针运算等。C#编程中在某些特定情况下,需要运用非受管代码,例如,要利用一个成熟的COM组件,或者调用一个API函数,或者用指针去编写实时/高效程序等。
    3  Visual  C#中调用Excel的COM组件
    一个.NET组件事实上是一个.NET下的DLL,它包含的不仅是运行程序本身,更重要的是包含这个DLL的描述信息(Meta  Data,即元数据),而一个COM组件是用其类库(TLB)储存其描述信息。这些COM组件都是非受管代码,要在Visual  C#中使用这些非受管代码的COM组件,就必须把他们转换成受管代码的.NET组件。所以在用Visual  C#调用Excel表格之前,必须完成从COM组件的非受管代码到受管代码的类库的转换。
    3.1  将Excel的COM组件转换为.NET组件
    在项目中打开Add  Reference对话框,选择COM栏,之后在COM列表中找到“Microsoft  Excel  9.0  Object  Library”(Office  2000),然后将其加入到项目的References中即可。Visual  C#.NET会自动产生相应的.NET组件文件,以后即可正常使用。
    这个转换形成.NET组件不能单独使用,它不过是以前的COM组件的一个外层包装,在.NET中可以通过这个外层包装去发现原来的COM组件并调用其相应的界面函数。所以它必须与原来的COM组件一起起作用。
    3.2  Visual  C#打开Excel表格
    事实上,在C#中使用一个经转换的COM组件和使用任何一个其它.NET组件完全一样。可以用new关键字创建一个经转换的COM组件,然后再像使用任何一个其它C#对象一样使用这个组件对象。
    在转换后的.NET组件中定义了一个命名空间Excel,在此命名空间中封装了一个类Application,这个类和启动Excel表格有非常重要的关系,在Visual  C#中,只需要下列三行代码就可以完成打开Excel表格的工作,具体如下:Excel.Application  excel  =  new  Excel.Application  ();//引用Excel对象
    excel.Application.Workbooks.Add  (  true  );//引用Excel工作簿
    excel.Visible  =  true  ;//使Excel可视  但此时的Excel表格是一个空的表格,没有任何内容,下面就来介绍如何往Excel表格中输入数据。
    3.3  往Excel表格中输入数据
      在命名空间"Excel"中,还定义了一个类"Cell",这个类所代表的就是Excel表格中的一个单元格。通过给"Cell"赋值,从而实现往Excel表格中输入相应的数据,下列代码功能是打开Excel表格,并且往表格输入一些数据。
    Excel.Application  excel  =  new  Excel.Application  ()  ;
    excel.Application.Workbooks.Add  (  true  )  ;
    excel.Cells[  1  ,  1  ]  =  "First  Row  First  Column"  ;
    excel.Cells[  1  ,  2  ]  =  "First  Row  Second  Column"  ;
    excel.Cells[  2  ,  1  ]  =  "Second  Row  First  Column"  ;
    excel.Cells[  2  ,  2  ]  =  "Second  Row  Second  Column"  ;
    excel.Visible  =  true  ;  
    3.4  实例
    下面实例在C#中连接Oracle数据库(Name),从表(TableName)中读取数据,并写入Excel.
    string  cnString="Provider=msdaora.1;Data  source=Name;  ";
    cnString=cnString+"user  id=UserName;password=Password";
    try
    {
    OleDbConnection  cn=new  OleDbConnection  (cnString);
    cn.Open  ();
    try
    {
    string  s="select  *  from  Name.TableName";
    OleDbCommand  cmd=new  OleDbCommand  (s,cn);
    OleDbDataReader  dr=cmd.ExecuteReader  ();
    Excel.Application  xlApp  =  new  Excel.Application();
    if(xlApp==null){MessageBox.Show  ("Can’t  open  Excel!");return;}
    xlApp.Application  .Workbooks  .Add  (true);
    int  row=2,fieldcount;
    fieldcount=dr.FieldCount  ;
    for(int  col=0;col<fieldcount;col++)  
    xlApp.Cells  [1,col+1]=dr.GetName(col);while  (dr.Read  ())
    {
    for(int  col=0;col<fieldcount;col++)  
    xlApp.Cells  [row,col+1]=dr.GetValue(col).ToString();
    row++;
    }
    xlApp.Visible  =true;
    xlApp=null;
    }
    catch(Exception  ex  ){MessageBox.Show  (ex.Message  );}
    finally  {cn.Close();}
    }
    catch(Exception  ex){MessageBox.Show  (ex.Message  );}
    }
    }
    3.5安装一个使用COM组件的.NET程序
    如果要将这样的程序安装运行在另一台机器上,那么除了安装运行程序外,还做三件事。
    首先,是安装.NET运行系统。因为任何一个.NET程序都不能离开.NET运行系统去独立运行。
    其次,所调用的COM组件必须要安装在目标机器上。本例中大多数目标机器上都装有Microsoft  Office的Excel,一般不会有这个问题。但如果是另一个用户自定义的COM组件,那么这个COM组件在运行.NET程序之前必须先安装好。
    最后,转换后的.NET组件DLL文件要安装在目标机器上。因为.NET组件不需要在Windows  Registry中注册,所以最简单的方法是将.NET组件DLL文件拷贝到运行程序目录下。如果此.NET组件被多个.NET程序共享,可以将其安装在.NET公用组件区中,从而可被任何一个.NET组件使用。只有当一个.NET组件参与了事务处理时,才需要将它注册为一个COM+组件。因为.NET仍然用传统的COM+机制来处理事务的提交、回滚等。
    4  小结
    通过以上讨论,我们知道了在C#中,如何使用Excel的COM组件。需要注意的是,Excel对象包含的许多内容我们没有介绍,在使用过程中需要我们不断学习。也使我们了解了在C#中如何使用COM组件。
      

  12.   

    客户端连接成功并接收完数据后进行socket Shundown操作:
    socket.Shutdown(SocketShutdown.Both);
    试试。