博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
网络通信之检测远端连接是否断开连接
阅读量:6086 次
发布时间:2019-06-20

本文共 4175 字,大约阅读时间需要 13 分钟。

判断对方是否断开连接:

一、方法层面的实现:

  1,使用输入流的read方法:

    输入流的read(byte[] ,int ,int) 方法,表示从当前的通道中读取数据,具体读取到的数据有返回的int值决定;这里的返回值和抛出的异常很重要,如果抛出IOException异常,很明显连接已经断开;

    返回值说明:

    针对于基于tcp/ip协议的socket连接说明:

    如果没有设置socket的soTimeout属性,那么该方法将是一个阻塞方法,可以通过设置socket的soTimeout属性,让read方法退出。

    注意:read方法如果timeout将以抛出socketTimeoutException异常;

    客户端:

     如果对方断开连接,客户端的read方法将返回-1;

    服务器端:

     如果对方断开连接,服务器端的read方法将抛出IOException异常;

  提示:

    建议使用这种方式,netty底层源码就是使用的这种方式实现的;

 

  2,使用socket 的sendUrgentData(int) :

    注意:不建议使用此种方式,因为使用该方式有很多不可预测的情况;

    通常情况是:接收端没有开启socket的SO_OOBINLINE属性,那么使用sendUrgentData(int)测试连接时,在发送17次(windows测试数据)时会发生异常;而如果接收端开启socket的SO_OOBINLINE属性,那么接收端就会收到发送的数据,从而导致真实数据的混乱;

    socket sendUrgentData(int)  17次异常说明;

    对于17次发送异常,在一片文章中有看到,说:如果接收端没有开启socket的SO_OOBINLINE的属性(当然这也是想把该方法用于心跳检测的必须条件),那么接收端将抛弃接收到的这个数据,也不会向发送端返回对应的ack值;但是,发送端却会占用一个tcp/ip的发送窗口,一直等待接收端的返回,这里肯定等待不到,就会一直占用窗口;而一个tcp/ip基于平台只有8或16个窗口,于是,在第17次发送数据时抛出异常了;

    意思,作者是懂的,但真正的底层实现却不太清楚;提供tcp/ip窗口详解连接:

    https://technet.microsoft.com/zh-cn/library/2007.01.cableguy.aspx

 

二、协议层面的实现:

  通过自定义的心跳机制,这也是最常用的方式之一;

 

示例实现:

定义了一个抽象的通道处理类,提供远端断开连接的判断;

import java.io.IOException;import java.io.InputStream;import java.net.SocketTimeoutException;/** * 提供基于tcp/ip协议连接的断开判断实现 * @author pineapple food * */public abstract class AbstractChannelHandler {    /*     * 连接关闭标志     */    private boolean closed;        /**     * 尝试从输入流中读取数据,具体读取数据的数量,依据返回的int值作为依据;     * @param buf 缓存区     * @param index 起始地址     * @param length 读取长度     * @return 值大于零,表示读取到返回值表示大小的数据;等于0: 表示未读取到数据; 等于-1:表示远端已关闭连接;     */    public int tryReadMsg(byte[] buf ,int index ,int length) {        int result = 0;                try {            result = inputStream().read(buf, index, length);        } catch (SocketTimeoutException e) {            result = 0;        } catch (IOException e) {            result = -1;            setClosed();        }                return result;    }        protected void setClosed() {        closed = true;    }        /**     * 连接是否关闭     * @return false 未关闭; true 关闭     */    public boolean isClosed() {        return closed;    }        /**     * 向远端连接发送心跳数据;     */    protected void sendHeartbeat() {}        /**     * 通过协议层的心跳发送,判断远端连接是否关闭;     * @return     */    protected boolean isClosedBySendHeartbeat() {        return false;    }        /**     * 设置socket 输入流的读取超时时间,用于设置{
@link tryReadMsg(byte[] ,int ,int)} 方法的timeout时间 * 否则将一直阻塞; */ abstract protected void setSoTimeout(); /** * 返回与该通道相关联的输入流; * @return */ abstract protected InputStream inputStream() throws IOException;}

通道处理类,继承与上述抽象类,方便断开连接的判断

import java.io.IOException;import java.io.InputStream;import java.net.Socket;import java.net.SocketException;public class ChannelHandler extends AbstractChannelHandler{        private Socket socket;        private InputStream is;        public ChannelHandler(Socket socket) {        this.socket = socket;                setSoTimeout();    }    @Override    protected InputStream inputStream() throws IOException {        if(is == null) {            is = socket.getInputStream();        }        return is;    }    @Override    protected void setSoTimeout() {        try {            socket.setSoTimeout(1000);        } catch (SocketException e) {                    }    }}

demo,亲测可用:

static public void test() throws IOException {        String host = "127.0.0.1";                 Socket socket = new Socket();        socket.connect(new InetSocketAddress(host, 6800));                    ChannelHandler channelHandler = new ChannelHandler(socket);                byte[] b = new byte[20];                while(true) {                        int n = channelHandler.tryReadMsg(b, 0, b.length);                        if(n == -1 || channelHandler.isClosed()) {                System.out.println("___________ connection is closed");                break;            }                        if(n > 0) {                byte[] data = new byte[n];                System.arraycopy(b, 0, data, 0, n);                System.out.println(n + " : receive data = "+new String(data));            }        }    }

 

转载于:https://www.cnblogs.com/loveyoumi/p/9675023.html

你可能感兴趣的文章
【转】Android布局优化之ViewStub
查看>>
网络安全管理技术作业-SNMP实验报告
查看>>
根据Uri获取文件的绝对路径
查看>>
Flutter 插件开发:以微信SDK为例
查看>>
.NET[C#]中NullReferenceException(未将对象引用到实例)是什么问题?如何修复处理?...
查看>>
边缘控制平面Ambassador全解读
查看>>
Windows Phone 7 利用计时器DispatcherTimer创建时钟
查看>>
程序员最喜爱的12个Android应用开发框架二(转)
查看>>
vim学习与理解
查看>>
DIRECTSHOW在VS2005中PVOID64问题和配置问题
查看>>
MapReduce的模式,算法以及用例
查看>>
《Advanced Linux Programming》读书笔记(1)
查看>>
zabbix agent item
查看>>
一步一步学习SignalR进行实时通信_7_非代理
查看>>
AOL重组为两大业务部门 全球裁员500人
查看>>
字符设备与块设备的区别
查看>>
为什么我弃用GNOME转向KDE(2)
查看>>
Redis学习记录初篇
查看>>
爬虫案例若干-爬取CSDN博文,糗事百科段子以及淘宝的图片
查看>>
Web实时通信技术
查看>>