我在服务器端用异步套接字监听连接
notifyReset.Reset();//这是ManualResetEvent对象
ctlTcpSock.BeginAccept ( new AsyncCallback ( AcceptCallBack ), ctlTcpSock );//ctlTcpSock是监听用的sock
notifyReset.WaitOne();
下面是回调方法
private void AcceptCallBack ( IAsyncResult ar )
{
notifyReset.Set ( );                 //事件状态设为终止,允许一个或多个等待线程继续
Socket sockObj = (Socket)ar.AsyncState;
accpSock = sockObj.EndAccept ( ar );//异步接收传入的连接尝试,返回socket对象来处理于远程主机的通信
StateInfomation stInfo = new StateInfomation ( );//StateInfomation 是自定义的状态信息类
stInfo.WorkSock = accpSock;
AddToHostList ( chatComm );
Thread chatThd = new Thread ( new ThreadStart ( AcceptMsg ) );
chatThd.Start ( );
}
关闭时使用的是
ctlTcpSock.Close();accpSock = sockObj.EndAccept ( ar );一句出现异常:未处理ObjectDisposedException异常, 无法访问已释放的对象。对象名:“System.Net.Sockets.Socket”。
放在try块里不管他,反复监听断开(中间未建立连接),在ctlTcpSock.BeginAccept ( new AsyncCallback ( AcceptCallBack ), ctlTcpSock )一句又出现同样异常。
好郁闷!
请哪位好心的兄弟指点一下如何解决 在下不胜感激(第一次发贴,昨天才注册 呵呵)

解决方案 »

  1.   

    Socket异步使用的是多线程机制.出现这个异常是因为:
    1. 如果我猜的没错,那么下面这段代码应该在一个循环里面:
       notifyReset.Reset();//这是ManualResetEvent对象
       ctlTcpSock.BeginAccept ( new AsyncCallback ( AcceptCallBack ),   
           tlTcpSock );//ctlTcpSock是监听用的sock
       notifyReset.WaitOne();
    2. 如果上面代码在一个循环里面,则当调用notifyReset.Set()并且
       accpSock = sockObj.EndAccept ( ar );成功返回建立连接时,     
       ctlTcpSock.BeginAccept ( new AsyncCallback ( AcceptCallBack ),   
           tlTcpSock );
       会被再次调用,即系统自动新开一个线程执行回调函数AcceptCallBack,并且停在
       accpSock = sockObj.EndAccept ( ar );
       的位置.
    3. 当第一个连接使用完毕调用ctlTcpSock.Close();关闭连接时,系统将自动释放
       ctlTcpSock对象所占用的资源,即该对象将被回收而不再可用.则此时当客户端发送一个创建连
       接请求到服务器端的时候,系统将自动检测到accpSock = sockObj.EndAccept ( ar );,但此时
       sockObj所引用的对象(即ctlTcpSock对象)已经不存在,所以会抛出ObjectDisposedException
       异常。解决办法:
    控制好同步.仔细看看msdn的例子就明白了,例子里面的状态对象的使用非常关键.
      

  2.   

    notifyReset.Reset();//这是ManualResetEvent对象
       ctlTcpSock.BeginAccept ( new AsyncCallback ( AcceptCallBack ),   
           tlTcpSock );//ctlTcpSock是监听用的sock
       notifyReset.WaitOne();
    如果上面这段代码没在循环里面,则当多次调用ctlTcpSock.BeginAccept()方法也可能引发LZ所说的异常.
      

  3.   

    1. 如果我猜的没错,那么下面这段代码应该在一个循环里面:
    notifyReset.Reset();//这是ManualResetEvent对象
    ctlTcpSock.BeginAccept ( new AsyncCallback ( AcceptCallBack ),
    tlTcpSock );//ctlTcpSock是监听用的sock
    notifyReset.WaitOne();我的确是把他放到循环里了 因为服务器要接受多个客户端连接,经你提起我发现我是现关闭套接字后关闭循环的 呵呵 (因为我把设置循环条件和按钮状态放在了一个方法里,刚才把它单提了出来)
    先关闭循环后关闭套接字,并捕获了accpSock = sockObj.EndAccept ( ar )的异常后,在反复监听断开时 ctlTcpSock.BeginAccept ( new AsyncCallback ( AcceptCallBack ), ctlTcpSock );一句就不会再产生异常了,但是那个“无法访问已释放的对象。”还是会出现。
    我找了半天 终于让我找到了msdn的套接字代码示例,呵呵,看了一下 那里面用的是
    Socket handler = (Socket) ar.AsyncState;
    handler.Shutdown(SocketShutdown.Both); 
    handler.Close();
    这几句是在SendCallback(IAsyncResult ar)方法中,示例是发送个信息后直接就关闭了,实际上肯定不能这么做啊。
    我对ctlTcpSock用Shutdown()方法,产生异常:由于套接字没有连接并且(当使用一个 sendto 调用发送数据报套接字时)没有提供地址,发送或接收数据的请求没有被接受。
    说明不能未连接时就Shutdown(),只用ctlTcpSock还是会有“无法访问已释放的对象。”,不断开还不能正常退出~,好郁闷,我就是想解决一下socket监听后没建立连接怎么关闭它才能正常。
      

  4.   

    上面的  只用ctlTcpSock还是会有“无法访问已释放的对象。” 改为
    只用ctlTcpSock.Close()还是会有“无法访问已释放的对象。”
      

  5.   

    1.调用Shutdown()之前先判断下Socket对象的Connected属性是否为真,如果为真才可以调用.
    2.对于"无法访问已释放的对象."这个问题,可以这样解决:
    a.调用Close()方法之后,讲ctlTcpSock置空,即ctlTcpSock = null;
    b.在任何调用ctlTcpSock的属性或方法的地方判断它是否为空,不为空才执行操作,否则做相应处理.
    上面的解决方法是比较差的.出现这问题就是我上面说的,你的同步没有做好.同步要讲的话要很大篇幅,你还是自己花时间看看示例中StateObject的使用吧.注意Socket定义成局部变量和全局变量的区别和作用.
      

  6.   

    //listener.Bind( new IPEndPoint( IPAddress.Loopback, 399 ) ); // For use with localhost 127.0.0.1
    listener.Listen(MAX_SOCKET); // Setup a callback to be notified of connection requests
    listener.BeginAccept(new AsyncCallback(OnConnectRequest), listener);
    /// <summary>
    /// Callback used when a client requests a connection. 
    /// Accpet the connection, adding it to our list and setup to 
    /// accept more connections.
    /// </summary>
    /// <param name="ar"></param>
    public void OnConnectRequest(IAsyncResult ar)
    { Socket listener = (Socket) ar.AsyncState;
    NewConnection(listener.EndAccept(ar));
    listener.BeginAccept(new AsyncCallback(OnConnectRequest), listener);
                       }
    Close: if( m_sock != null && m_sock.Connected )
    {
    m_sock.Shutdown( SocketShutdown.Both );
    m_sock.Close();
    }
      

  7.   

    关于这个"无法访问已释放的对象.",刚才又发现一点 已经释放的东西不是null,可能是nil ?因为在你说之前我已经把很多地方都加上了if判断不为空才调用,但是还是会在if后面的语句产生ObjectDisposedException异常,(就是所谓的"无法访问已释放的对象."),没办法我在用到那些对象的地方都捕获了这个异常,,呵呵,原则上是有多少捕多少,不留漏网之鱼! 
    刚才想到一个问题,异步套接字是不是很多时候能自动释放,,想到这个的原因是:我用客户端连接服务器,连接后没有断开,也就是没有关闭socket,点退出(里面是application.exit),这样居然也可以正常退出了 进程里看不到客户端了,这是怎么回事呢。其实我是最近才开始尝试使用一下异步套接字的,因为原来使用同步套接字的时候accept总是阻塞,结束他就要有异常,现在异步的异常似乎更多,崩溃中~!
    麻烦星空大哥再指点指点~
      

  8.   

    1.对象是否后确实不是null,所以我才让你在调用Close()之后用代码置为null(ctlTcpSock = null;),这样if判断才会起作用.
    2.Socket是要你手动释放的,之所以你能正常退出是因为你调用过Close(),该方法无论是客户端还是服务器端调用都可以正常释放连接.
    3.异步是非常复杂的,我4月份刚刚完成一个项目,里面的上传下载就是用的异步Socket,花了我很多时间学习,建议你要学异步的话可以看看MSDN里面关于"异步编程"的内容,这是一个比较大的课题.
      

  9.   

    关闭的问题也解决的差不多了,改结帖拉~
    谢谢大家了 尤其 AtaLoss0202(星空天宇),
      

  10.   

    其实在抛出异常之前return出去 就不会到发生那个异常了