讨论Socket必讨论长连接和短连接

一、长连接和短连接的概念

  1、长连接与短连接的概念:前者是整个通讯过程,客户端和服务端只用一个Socket对象,长期保持Socket的连接;后者是每次请求,都新建一个Socket,处理完一个请求就直接关闭掉Socket。所以,其实区分长短连接就是:整个客户和服务端的通讯过程是利用一个Socket还是多个Socket进行的。

  可能你会想:这还不简单,长连接不就是不关Socket嘛,短连接不就是每次都关Socket每次都new Socket嘛。然而事实其实并没有那么简单的,请继续看下面的整理

  2、关闭流而保持Socket正常?

    在网上百度了一下,发现很多人都是以关闭流还是关闭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
//发送核心方法
    public String send(String send) throws IOException {
        String rtn = null;
        BufferedWriter writer = null;
        OutputStreamWriter ow = null;
        OutputStream os = null;
        try{
            os = socket.getOutputStream();
            ow = new OutputStreamWriter(os);
            writer = new BufferedWriter(ow);
            char [] sendChar = send.toCharArray();
            ArrayList<Integer> list = new ArrayList<Integer>();
            for(char ch:sendChar){
                list.add((int)ch);
            }
            //进行加密操作
            list = encry(list);
            Iterator<Integer> it = list.iterator();
            while(it.hasNext()){
                writer.write(it.next());
            }
            writer.flush();
            rtn = "发送成功!";
        }finally{
            //注意:直接关闭流将会导致socket关闭,只能通过shutdownOutput/input的方式关闭流
            //另外,流关闭之后,相当于关闭底层的连接,除非新new个socket,否则和客户端的连接相当于断开
//          if(writer!=null){
//              writer.close();
//          }
//          if(ow!=null){
//              ow.close();
//          }
//          if(os!=null){
                //os.close();
//          }
            //socket.shutdownOutput();流关闭之后,相当于关闭底层的连接,除非新<br>new个socket,否则和客户端的连接相当于断开
        }
        return rtn;
    }

  这是我写的一个测试的发送消息的核心方法,在关闭了对应的流(无论是输出或者输入)之后,下一次调用getInputStream或者getOutputStream会抛出异常说:Socket is closed;这里讲明一个事实:Socket和流联系着,流关闭了,Socket其实也就相当于关闭状态!

  其实这个也很好理解,Socket本来就是依靠流进行关闭的,流,就只有一个,你关闭了流,Socket赖以通讯的渠道也就关闭了,与客户的连接也断开了,所以抛出异常是很合理的。

  所以,流关闭而要求Socket正常通讯是不可能的!

  所以,如何实现长连接?

二、长连接的正确实现方式

  1、不关闭流实现长连接?

    前面讨论了,流关闭了而不关闭Socket,还是无法达到长连接的效果的,所以,要长连接,流必须不能关闭!那么,是不是直接不关闭流,然后每次要发消息就直接往流里面任进去数据,然后调用flush()方法强制刷新就行了?其实不行的,这样客户端是无法正常接收信息的,你会发觉就算服务端flush了,客户端还是会一直在read方法那里阻塞!具体原因各位可以看一下java api文档的截图:

文档说明了,如果流一直可用,而且没有读到流的末尾(就是对应着对方流已经关闭或者网络断开!),read会一直阻塞!其实这样做也是可以解释清楚的:本来服务端的read方法就不知道Server端的消息什么时候发送完,说不定我以为数据发送完 了,但其实是因为网络延迟而导致部分数据延后到来(况且也不可能所有数据同时到达),所以,read方法只能一直在阻塞等待对方的应答。所以,怎么实现长连接?

  2、实现长连接的方法

  A、客户端自动退出开读取的动作。前面说了,就算服务端调用了flush方法进行输出刷新,客户端也不一定能退出read的动作,所以还是会阻塞。所以,退出动作必须有客户端程序自己完成,我们可以在服务端没发送完一段消息并且刷新前就进行一个写入结束符号的标志,客户端解析到结束符号时,变可直接退出read的循环读取操作,避免一直阻塞。

  B、可以调用有读取一定字节到某个数组的read方法(不过好像这个不太行,毕竟每次消息的长度好像会变的),当然,这只是针对消息定长的情况。

  下面贴上长连接实现后的代码(其实就是比前面的代码加多了读入结束标记符号)

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
40
41
//发送核心方法
    public String send(String send) throws IOException {
        String rtn = null;
        BufferedWriter writer = null;
        OutputStreamWriter ow = null;
        OutputStream os = null;
        try{
            os = socket.getOutputStream();
            ow = new OutputStreamWriter(os);
            writer = new BufferedWriter(ow);
            char [] sendChar = send.toCharArray();
            ArrayList<Integer> list = new ArrayList<Integer>();
            for(char ch:sendChar){
                list.add((int)ch);
            }
            //进行加密操作
            list = encry(list);
            Iterator<Integer> it = list.iterator();
            while(it.hasNext()){
                writer.write(it.next());
            }
            //写入结束标志符号:%
            writer.write('%');
            writer.flush();
            rtn = "发送成功!";
        }finally{
            //注意:直接关闭流将会导致socket关闭,只能通过shutdownOutput/input的方式关闭流
            //另外,流关闭之后,相当于关闭底层的连接,除非新new个socket,否则和客户端的连接相当于断开
//          if(writer!=null){
//              writer.close();
//          }
//          if(ow!=null){
//              ow.close();
//          }
//          if(os!=null){
                //os.close();
//          }
            //socket.shutdownOutput();流关闭之后,相当于关闭底层的连接,除非新new个socket,否则和客户端的连接相当于断开
        }
        return rtn;
    }

 三、短连接

    短连接就基本没什么好讲的啦,只是每次关闭Socket和流时需要注意一下事情:

    1、虽然前面说了流关闭了,Socket就不可用了,但是,我们还是要显式的关闭Socket的,因为在Socekt中还有中状态:叫做半连接状态,当我们只是用到输出流的时候,我们关闭了输出流,并且不能直接调用close方法,只能调用shutDown对应方法(具体请查看java API),其实输入流还是连接着的(只是我们没有用到而已!),这时候,如果没有显式关闭Soceket,很容易导致内存泄露,所以,所有流Socket都要显式关闭

    2、短连接和长连接有不同的用途:对于某次服务只需要一次回话的客户,使用短连接显得简单;但是,如果该次服务需要很多交互式的操作通信,那还是长连接比较高性能,毕竟,Socket的打开和关闭都是很耗性能的。

四、总结

  1、对应流关闭,Socket的对应输入(出)数据的通道也就关闭,此时无法达到长连接效果;

  2、关闭Socket,记得显式关闭流与socket,顺序是线管流再关socket.

  3、要实先长连接,一般需要发送结束标记符号来告诉客户端服务端的某段消息已经发送完毕,否则客户端会一直阻塞在read方法。

原文转载:https://www.cnblogs.com/lcplcpjava/p/6581179.html

java如何实现Socket的长连接和短连接的更多相关文章

  1. Socket的长连接和短连接

    讨论Socket必讨论长连接和短连接 一.长连接和短连接的概念 1.长连接与短连接的概念:前者是整个通讯过程,客户端和服务端只用一个Socket对象,长期保持Socket的连接:后者是每次请求,都新建 ...

  2. python socket 编程之三:长连接、短连接以及心跳

    长连接:开启一个socket连接,收发完数据后,不立刻关闭连接,可以多次收发数据包. 短连接:开启一个socket连接,收发完数据后,立刻关闭连接. 心跳:长连接在没有数据通信时,定时发送数据包(心跳 ...

  3. TCP/IP,http,socket,长连接,短连接

    TCP/IP TCP/IP是个协议组,可分为三个层次:网络层.传输层和应用层. 在网络层有IP协议.ICMP协议.ARP协议.RARP协议和BOOTP协议. 在传输层中有TCP协议与UDP协议. 在应 ...

  4. TCP/IP,http,socket,长连接,短连接——小结。

    来源:http://blog.chinaunix.net/uid-9622484-id-3392992.html TCP/IP是什么? TCP/IP是个协议组,可分为三个层次:网络层.传输层和应用层. ...

  5. (转载)http和socket之长连接和短连接区别

    TCP/IPTCP/IP是个协议组,可分为三个层次:网络层.传输层和应用层.在网络层有IP协议.ICMP协议.ARP协议.RARP协议和BOOTP协议.在传输层中有TCP协议与UDP协议.在应用层有: ...

  6. python socket 编程之三:长连接、短连接以及心跳(转药师Aric的文章)

    长连接:开启一个socket连接,收发完数据后,不立刻关闭连接,可以多次收发数据包. 短连接:开启一个socket连接,收发完数据后,立刻关闭连接. 心跳:长连接在没有数据通信时,定时发送数据包(心跳 ...

  7. http和socket之长连接和短连接区别【转】

    转自:https://blog.csdn.net/mengyafei43/article/details/25195445 TCP/IP TCP/IP是个协议组,可分为三个层次:网络层.传输层和应用层 ...

  8. TCP/IP,http,socket,长连接,短连接——小结(转)

    概要: 之前对这几个概念有点糊涂,查阅了些资料,稍微概括下他们的区别吧.如有错误,请拍~~~ 先看图: TCP/IP是什么? TCP/IP是个协议组,可分为三个层次:网络层.传输层和应用层.    在 ...

  9. 6.1 socket 长连接、短连接

    一般情况下,服务器的长连接和短连接不是服务器说了算,而是客户端说了算.因为服务器是给别人提供业务的,一旦连接建立起来之后,服务器端不会主动把连接给close掉. 客户端发送一笔业务,没有关闭连接,然后 ...

随机推荐

  1. intel EPT 机制详解

    2016-11-08 在虚拟化环境下,intel CPU在处理器级别加入了对内存虚拟化的支持.即扩展页表EPT,而AMD也有类似的成为NPT.在此之前,内存虚拟化使用的一个重要技术为影子页表. 背景: ...

  2. Unity系统自带函数生命周期以及相互关系

    官方参考手册:http://docs.unity3d.com/Manual/ExecutionOrder.html unity脚本从唤醒到销毁都有着一套比较完善的生命周期,添加任何脚本都要遵守生命周期 ...

  3. 汉字转换为拼音的JavaScript库

    将JSPinyin剥离mootools这个JavaScript库,可以独立使用. 1)一个是将汉字翻译为拼音,其中每一个字的首字母大写: pinyin.getFullChars(this.value) ...

  4. Python误区之strip,lstrip,rstrip

    最近在处理数据的时候,想把一个字符串开头的“)”符号去掉,所以使用targetStr.lstrip(")"),发现在 将处理完的数据插入到数据库时会出现编码报错,于是在网上搜到了这 ...

  5. mysql数据库从删库到跑路之mysql基础

    一 数据库是什么 之前所学,数据要永久保存,比如用户注册的用户信息,都是保存于文件中,而文件只能存在于某一台机器上. 如果我们不考虑从文件中读取数据的效率问题,并且假设我们的程序所有的组件都运行在一台 ...

  6. 使用Xib创建自定义视图(不是cell)时需要注意的问题

    开发项目过程中,有些地方不免会用到Xib来提高开发效率,如果你的手速够快,写代码建视图,我并不反对这样做.因为我以前也是纯手写代码开发. 进入正题,Xib好用,但是这些下面这些问题需要注意一下. 问题 ...

  7. wait、notify为什么要放在同步代码块中

    等待方遵循的原则: 获取对象的锁,不满足条件就调用wait()方法,条件满足继续执行 通知方原则: 获取对象的锁,改变条件,然后notify 每个对象都有一个监视器锁,这个监视器锁的数据结构如下: w ...

  8. c++之旅:模板库中的容器

    容器 C++中的容器包括array, vector, list,map,set 数组 array不可变长,创建时其大小就固定了,array中可以存储各种数据类型包括对象,不过array是在栈上分配的, ...

  9. Web前端页面的浏览器兼容性测试心得(三)总结一些IE8兼容问题的解决方案

    由于IE8不支持HTML5,而它又是Win7的默认浏览器,我们即使讨厌它,在这几年却也拿它没办法. 最近做了个需要兼容IE8的项目,不可避免地用了HTML5+CSS3,甚至canvas和svg,做兼容 ...

  10. 防抖debounce和节流throttle

    大纲 一.出现缘由 二.什么是防抖debounce和节流throttle 三.应用场景 3.1防抖 3.2节流 一.出现缘由 前端开发中,有一部分用户行为会频繁触发事件,而对于DOM操作,资源加载等耗 ...