c# 如何判断socket连接断开?

时间:2022-05-30 23:55:15
        private void timer1_Tick(object sender, EventArgs e)
        {
            if (socket != null && socket.Connected)
            {
                if (socket.Poll(1, SelectMode.SelectRead))
                {
                    try
                    {
                        byte[] temp = new byte[1024];
                        int nRead = socket.Receive(temp);
                        if (nRead == 0)
                        {
                            MessageBox.Show("000连接已断开了,请处理");
                        }
                    }
                    catch
                    {
                        MessageBox.Show("连接已断开了,请处理");
                    }
                }
                try
                {
                   int ii=socket.Send(new byte[1]);
                }
                catch (SocketException se)
                {
                    if (se.ErrorCode == 10054)         //   Error   code   for   Connection   reset   
                    {

                        MessageBox.Show("连接已断开了,请处理");
                    }
                    else
                    {
                        MessageBox.Show(se.Message);
                    }
                }   
    
            }
        }
目前我用一个定时器来做心跳发送包,但先和服务端连接上,再把网络禁用了
我这边的客户端一点反应也没有,禁用后,我不停的发包一切也正常没有异常,socket.Connected一直为true
如果才能知道服务端已断开连接了呢

28 个解决方案

#1


不是很熟悉  帮顶

#2


新手,高手来

#3


应该有一个超时设置吧!

#4


给个例子看看呀各位,这问题真把我搞晕了

#5


呃,是客户端向服务端发包还是服务端向客户端发哦?

#6


 if (socket != null && socket.Connected)
既然检查了socket.Connected属性,又何必加个 socket!=null ?
没有得到任何对象socket.Connected自然是false

试试把发信息和接收信息分写在两个Timer中,要是能分别做到两个窗体里就更好了.

#7


用socket连接一般都是若服务器断开了连接,客户端是不会报异常的,而如果是客户端断开了连接,服务器是会出现异常的
这个问题其实也很好的,不管是哪边断开都发送一条特殊的我们一般情况下不会输的指定,当对方收到的若是这样的指令,就表明已经断开了连接,自己也可以断开不需要再连接了

#8


我前两天也遇到过一模一样的问题!
后来采用了比较原始的方法就是在心跳测试中调用ping命令去ping服务器,ping不通就报异常。
lz不妨试试

#9


心跳检测。google 一下

#10


前两天还遇到了和lz相同的问题
后来用了个土法解决的,就是在心跳代码中去ping,ping不通就报异常

#11


if (socket.Poll(100, SelectMode.SelectRead))
{
  if(socket.Available == 0) throw new Exception("网络断了");
}
这里的轮询间隔是以微秒(百万分之一秒)计算的,不用设得太小了

#12


能给出代码例子看一下吗

#13


引用 11 楼 westfly 的回复:
if (socket.Poll(100, SelectMode.SelectRead)) 

  if(socket.Available == 0) throw new Exception("网络断了"); 

这里的轮询间隔是以微秒(百万分之一秒)计算的,不用设得太小了


我把网线拔掉了,但是if (socket.Poll(100, SelectMode.SelectRead))总是为false不能执行进来

#14


Poll只能用于检测网络电缆正常且远程主机不关闭的情况,
其他的情况需要借助Read/Send数据时捕捉错误码来判断了(在一个长连接中可以借助心跳包来处理)

#15


            const int keepAlive = -1744830460; // SIO_KEEPALIVE_VALS
            byte[] inValue = new byte[] { 1, 0, 0, 0, 0x10, 0x27, 0, 0, 0xe8, 0x03, 0, 0 }; // True, 10秒, 1 秒
            TcpSock.IOControl(keepAlive, inValue, null);
            //Sock.IOControl(IOControlCode.KeepAliveValues, inValue, null);
            //设置 KeepAlive 为 10 秒,检查间隔为 1 秒。如果拨掉客户端网线
              //服务器的 Socket.Receive() 会在 10 秒后断开连接

#16


SocketEvent 是事件
Socket_e 是事件参数
外部对象获得SocketEvent事件进行重连操作即可
读的线程终止就可以了.
这只是一个类中的SOCKET读线程操作示例:

           //接收线程
            public void Thread_Read()
            {
                while (true)
                {
                    try
                    {

                        if (socket.Poll(-1, SelectMode.SelectRead))
                        {
                            byte[] bytes = new byte[socket.ReceiveBufferSize];
                            int bytesRec = socket.Receive(bytes);
                            string data = Encoding.UTF8.GetString(bytes, 5, bytesRec);

                            Rec_e.vDataPack = data;
                            RecEvent(this, Rec_e);
                            if (bytesRec == 0)
                            {
                                //socket连接已断开
                                    Socket_e.ResCode = "00000";
                                SocketEvent(this, Socket_e);
                                return;
                            }
                        }
                        else if (socket.Poll(-1, SelectMode.SelectError))
                        {
                            //TODO : SOCKET错误
                        }
                    }
                    catch (SocketException e)
                    {
                        //10035 == WSAEWOULDBLOCK
                        if (e.NativeErrorCode.Equals(10035))
                        {
                            //仍然处于连接状态,但是发送可能被阻塞
                        }
                        else
                        {
                            //连接错误,返回错误代码:e.NativeErrorCode
                            Socket_e.ResCode = e.NativeErrorCode.ToString();
                            SocketEvent(this, Socket_e);
                            return;
                        }
                    }
                }
            }

#17


学习

#18


如果正常close的话 可以读下他connection熟悉
如果强制断开 那么在 另外一边会抛出异常

#19


socket 有个属性好象叫connect

#20


Poll 方法将会检查 Socket 的状态。指定 selectMode 参数的 SelectMode..::.SelectRead,可确定 Socket 是否为可读。指定 SelectMode..::.SelectWrite,可确定 Socket 是否为可写。使用 SelectMode..::.SelectError 检测错误条件。Poll 将在指定的时段(以 microseconds 为单位)内阻止执行。如果希望无限期的等待响应,则将 microSeconds 设置为一个负整数。如果要检查多个套接字的状态,则不妨使用 Select 方法。 

此方法不能检测某些类型的连接问题,例如,网络电缆中断或远程主机意外关闭。您必须尝试发送或接收数据以检测这些类型的错误。
这个是我在http://technet.microsoft.com/zh-cn/system.net.sockets.socket.poll.aspx上看的,够权威吧,看来只能发一个特殊的东西给socket的另一方,再在对方的逻辑里写上收到的是这个特殊的东西就回发一个特殊的东西。这样才能保证socket还能用。

而且还有。poll方法是向socket里写或者读出一部分数据,这样的话,如果你其他的线程也在接收socket里的数据的话,就会接收不全了,我在做一个远程通信软件时也遇到这样的问题。

希望你能看到我这条回复,如果你已有好的解决办法,麻烦你给我留言,十分感谢!我也被这个问题困扰好久了。

#21


在学习这面得只是,谁有没有一个完整的代码能供我参考下!

#22


应该等待对方的ACK,这样才能确认发送成功   
  超过一定时间没有收到ACK,就重发。   
  如果重发连续N次没收到ACK,就认为对方断开连接。

#23



private void timer1_Tick(object sender, EventArgs e) 

if (socket != null && socket.Connected) 

if (socket.Poll(1, SelectMode.SelectRead)) 

try 

byte[] temp = new byte[1024]; 
int nRead = socket.Receive(temp); 
if (nRead == 0) 

MessageBox.Show("000连接已断开了,请处理"); 


catch 

MessageBox.Show("连接已断开了,请处理"); 


try 

int ii=socket.Send(new byte[1]); 

catch (SocketException se) 

if (se.ErrorCode == 10054) // Error code for Connection reset 


MessageBox.Show("连接已断开了,请处理"); 

else 

MessageBox.Show(se.Message); 





#24


http://www.cnblogs.com/caoguanghong/archive/2008/09/19/1293943.html

#25


keep-alive进行自动检测

#26


引用 16 楼 much0726 的回复:
SocketEvent 是事件
Socket_e 是事件参数
外部对象获得SocketEvent事件进行重连操作即可
读的线程终止就可以了.
这只是一个类中的SOCKET读线程操作示例:

C# code


           //接收线程
            public void Thread_Read()
            {
             ……


+++

#27


  oh,这样啊

#28


这帖子还没结?哪个可用?

#1


不是很熟悉  帮顶

#2


新手,高手来

#3


应该有一个超时设置吧!

#4


给个例子看看呀各位,这问题真把我搞晕了

#5


呃,是客户端向服务端发包还是服务端向客户端发哦?

#6


 if (socket != null && socket.Connected)
既然检查了socket.Connected属性,又何必加个 socket!=null ?
没有得到任何对象socket.Connected自然是false

试试把发信息和接收信息分写在两个Timer中,要是能分别做到两个窗体里就更好了.

#7


用socket连接一般都是若服务器断开了连接,客户端是不会报异常的,而如果是客户端断开了连接,服务器是会出现异常的
这个问题其实也很好的,不管是哪边断开都发送一条特殊的我们一般情况下不会输的指定,当对方收到的若是这样的指令,就表明已经断开了连接,自己也可以断开不需要再连接了

#8


我前两天也遇到过一模一样的问题!
后来采用了比较原始的方法就是在心跳测试中调用ping命令去ping服务器,ping不通就报异常。
lz不妨试试

#9


心跳检测。google 一下

#10


前两天还遇到了和lz相同的问题
后来用了个土法解决的,就是在心跳代码中去ping,ping不通就报异常

#11


if (socket.Poll(100, SelectMode.SelectRead))
{
  if(socket.Available == 0) throw new Exception("网络断了");
}
这里的轮询间隔是以微秒(百万分之一秒)计算的,不用设得太小了

#12


能给出代码例子看一下吗

#13


引用 11 楼 westfly 的回复:
if (socket.Poll(100, SelectMode.SelectRead)) 

  if(socket.Available == 0) throw new Exception("网络断了"); 

这里的轮询间隔是以微秒(百万分之一秒)计算的,不用设得太小了


我把网线拔掉了,但是if (socket.Poll(100, SelectMode.SelectRead))总是为false不能执行进来

#14


Poll只能用于检测网络电缆正常且远程主机不关闭的情况,
其他的情况需要借助Read/Send数据时捕捉错误码来判断了(在一个长连接中可以借助心跳包来处理)

#15


            const int keepAlive = -1744830460; // SIO_KEEPALIVE_VALS
            byte[] inValue = new byte[] { 1, 0, 0, 0, 0x10, 0x27, 0, 0, 0xe8, 0x03, 0, 0 }; // True, 10秒, 1 秒
            TcpSock.IOControl(keepAlive, inValue, null);
            //Sock.IOControl(IOControlCode.KeepAliveValues, inValue, null);
            //设置 KeepAlive 为 10 秒,检查间隔为 1 秒。如果拨掉客户端网线
              //服务器的 Socket.Receive() 会在 10 秒后断开连接

#16


SocketEvent 是事件
Socket_e 是事件参数
外部对象获得SocketEvent事件进行重连操作即可
读的线程终止就可以了.
这只是一个类中的SOCKET读线程操作示例:

           //接收线程
            public void Thread_Read()
            {
                while (true)
                {
                    try
                    {

                        if (socket.Poll(-1, SelectMode.SelectRead))
                        {
                            byte[] bytes = new byte[socket.ReceiveBufferSize];
                            int bytesRec = socket.Receive(bytes);
                            string data = Encoding.UTF8.GetString(bytes, 5, bytesRec);

                            Rec_e.vDataPack = data;
                            RecEvent(this, Rec_e);
                            if (bytesRec == 0)
                            {
                                //socket连接已断开
                                    Socket_e.ResCode = "00000";
                                SocketEvent(this, Socket_e);
                                return;
                            }
                        }
                        else if (socket.Poll(-1, SelectMode.SelectError))
                        {
                            //TODO : SOCKET错误
                        }
                    }
                    catch (SocketException e)
                    {
                        //10035 == WSAEWOULDBLOCK
                        if (e.NativeErrorCode.Equals(10035))
                        {
                            //仍然处于连接状态,但是发送可能被阻塞
                        }
                        else
                        {
                            //连接错误,返回错误代码:e.NativeErrorCode
                            Socket_e.ResCode = e.NativeErrorCode.ToString();
                            SocketEvent(this, Socket_e);
                            return;
                        }
                    }
                }
            }

#17


学习

#18


如果正常close的话 可以读下他connection熟悉
如果强制断开 那么在 另外一边会抛出异常

#19


socket 有个属性好象叫connect

#20


Poll 方法将会检查 Socket 的状态。指定 selectMode 参数的 SelectMode..::.SelectRead,可确定 Socket 是否为可读。指定 SelectMode..::.SelectWrite,可确定 Socket 是否为可写。使用 SelectMode..::.SelectError 检测错误条件。Poll 将在指定的时段(以 microseconds 为单位)内阻止执行。如果希望无限期的等待响应,则将 microSeconds 设置为一个负整数。如果要检查多个套接字的状态,则不妨使用 Select 方法。 

此方法不能检测某些类型的连接问题,例如,网络电缆中断或远程主机意外关闭。您必须尝试发送或接收数据以检测这些类型的错误。
这个是我在http://technet.microsoft.com/zh-cn/system.net.sockets.socket.poll.aspx上看的,够权威吧,看来只能发一个特殊的东西给socket的另一方,再在对方的逻辑里写上收到的是这个特殊的东西就回发一个特殊的东西。这样才能保证socket还能用。

而且还有。poll方法是向socket里写或者读出一部分数据,这样的话,如果你其他的线程也在接收socket里的数据的话,就会接收不全了,我在做一个远程通信软件时也遇到这样的问题。

希望你能看到我这条回复,如果你已有好的解决办法,麻烦你给我留言,十分感谢!我也被这个问题困扰好久了。

#21


在学习这面得只是,谁有没有一个完整的代码能供我参考下!

#22


应该等待对方的ACK,这样才能确认发送成功   
  超过一定时间没有收到ACK,就重发。   
  如果重发连续N次没收到ACK,就认为对方断开连接。

#23



private void timer1_Tick(object sender, EventArgs e) 

if (socket != null && socket.Connected) 

if (socket.Poll(1, SelectMode.SelectRead)) 

try 

byte[] temp = new byte[1024]; 
int nRead = socket.Receive(temp); 
if (nRead == 0) 

MessageBox.Show("000连接已断开了,请处理"); 


catch 

MessageBox.Show("连接已断开了,请处理"); 


try 

int ii=socket.Send(new byte[1]); 

catch (SocketException se) 

if (se.ErrorCode == 10054) // Error code for Connection reset 


MessageBox.Show("连接已断开了,请处理"); 

else 

MessageBox.Show(se.Message); 





#24


http://www.cnblogs.com/caoguanghong/archive/2008/09/19/1293943.html

#25


keep-alive进行自动检测

#26


引用 16 楼 much0726 的回复:
SocketEvent 是事件
Socket_e 是事件参数
外部对象获得SocketEvent事件进行重连操作即可
读的线程终止就可以了.
这只是一个类中的SOCKET读线程操作示例:

C# code


           //接收线程
            public void Thread_Read()
            {
             ……


+++

#27


  oh,这样啊

#28


这帖子还没结?哪个可用?