Socket 读取 写入判断网络断开

当客户端已经将socket正常关掉时,服务器端的socket.connected还是显示true,并没有判断出客户端断开,而C++就能够通过检测close事件,立刻判断出客户端断开。后来查阅资料发现,服务器端需要通过发送数据才能检测出客户端中断。

    以下是我参考的一点资料:
    首先,Socket类的Connected属性只表示最后一次I/O操作的状态,如果这之后[连接的另一方]断开了,它还一直返回true, 除非你再通过socket来发送数据。所以通过个属性来判断是行不通的!
       有人说可以用Socket.Available属性来判断,msdn中说:如果[连接的另一方]断开了,它就会抛出异常。然而,这个BUG报告(http://dam.mellis.org/2004/08/net_socket_bugs_gotchas/)却指出:msdn的说法并不完全正确,这个属性只有在少数情况下才抛出异常。所以,这一招还是行不通!
       事实上,Socket.Receive()方法在[连接的另一方]断开时,它返回结果告知只读了0个字节,我们可以籍由这一点来找出答案。这个问答(http://www.dotnet247.com/247reference/msgs/36/182526.aspx)给出了好的解决方案:可以调用Socket.Poll() 方法,为该方法的第二个参数传入SelectRead 值,如果该方法返回true,  则可以再由Socket.Receive()方法的返回值来判断, 我简要的写出代码:

        private bool SocketConnected()
        {
            try
            {
                return !_client.Poll(1, SelectMode.SelectRead) && (_client.Available == 0);
            }
            catch (SocketException)
            {
                return false;
            }
            catch (ObjectDisposedException)
            {
                return false;
            }
        }

     但是我发现参考资料上给的方法也不是很好用,因为即便是网络正常连接时,nRead的值也可能是0,比较郁闷。看来只能用频繁发送探测包的方法了。

    困扰了我一天的问题,在这里做个小记。

转自:http://bbs.csdn.net/topics/290010343

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里的数据的话,就会接收不全了,我在做一个远程通信软件时也遇到这样的问题。



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
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对象的SetSocketOption方法设置套接字的各种选项,它有3种重载的形式:

public void SetSocketOption(SetSocketOptionLevel sl,SocketOptionName sn,byte[]value)

public void SetSocketOption(SetSocketOptionLevel sl,SocketOptionName sn,int value)

public void SetSocketOption(SetSocketOptionLevel sl,SocketOptionName sn,object value)

其中sl定义套接字选项的类型,可选类弄有IP、Socket、Tcp、Udp。

sn指定套接字选项的值,常用的选项值。

SocketOptionLevel SocketOptionName 说明
IP HeaderIncluded 指出发送到套接字的数据将包括IP头
IP IPOptions 指定IP选项用于输出包中
IP MulticastInterface 设置组播包使用的端口
IP MultiLookBack IP组播回送
IP PacketInformation 返回关于接收包的信息
IP UnBlockSource 设置套接字为无阻塞模式
Socket AcceptConnection 如果为真,表时套接字正在侦听
Socket Broadcast 如果为真,表时允许在套接字上发送广播消息
Socket MaxConnections 设置使用的最大队列长度
Socket ReceiveBuffer 接收套接字的缓存大小
Socket ReceiveTimeout 接收套接字的超时时间
Socket SendBuffer 发送套接字的缓存大小
Socket SendTimeout 发送套接字的超时时间
Socket UseLookback 使用回传
Udp NoDelay 为发送合并禁用Nagle算法
Udp ChecksumConverage 设置或获取UDP校验和覆盖
Udp NoChecksum 发送校验和设置为零的UDP数据报

使用方法:

s.SetSocketOption(SocketOptionLevel.Socket,SocketOptionName.SendTimeout,1000);

原:至于是否有效还需测试
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值