zoukankan      html  css  js  c++  java
  • JAVA通信系列一:Java Socket技术总结

     本文是学习java Socket整理的资料,供参考。

    1       Socket通信原理

    1.1     ISO七层模型

    1.2     TCP/IP五层模型

     

             应用层相当于OSI中的会话层,表示层,应用层。

             区别参考:http://blog.chinaunix.net/uid-22166872-id-3716751.html

     

    1.3     TCP报文

     

    (1)序号:Seq序号,占32位,用来标识从TCP源端向目的端发送的字节流,发起方发送数据时对此进行标记。

      (2)确认序号:Ack序号,占32位,只有ACK标志位为1时,确认序号字段才有效,Ack=Seq+1。

      (3)标志位:共6个,即URG、ACK、PSH、RST、SYN、FIN等,具体含义如下:

      (A)URG:紧急指针(urgent pointer)有效。

      (B)ACK:确认序号有效。

      (C)PSH:接收方应该尽快将这个报文交给应用层。

      (D)RST:重置连接。

      (E)SYN:发起一个新连接。

      (F)FIN:释放一个连接。

     

     需要注意的是:

      (A)不要将确认序号Ack与标志位中的ACK搞混了。

      (B)确认方Ack=发起方Req+1,两端配对。

    1.4     Socket通信

           Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。

    1.5     三次握手

             Socket连接建立和关闭,详见:http://www.2cto.com/net/201310/251896.html

    2       通信基本概念

    2.1     短连接

    连接->传输数据->关闭连接 

    短连接是指SOCKET连接,发送数据,接收数据后,马上断开连接。 

    比如:

    HTTP1.0默认是短连接,无状态的,浏览器和服务器每进行一次HTTP操作,就建立一次连接,但任务结束就中断连接。 、

    Http1.1默认是长连接

    无状态:协议对于事务处理没有记忆能力;

    2.2     长连接

    连接->传输数据->保持连接 -> 传输数据-> 。。。 ->关闭连接。 

    建立SOCKET连接后,不管是否使用,一致保持连接。

    2.3     半包

    接受方没有接受到一个完整的包,只接受了部分;

    原因:TCP为提高传输效率,将一个包分配的足够大,导致接受方并不能一次接受完。

    影响:长连接和短连接中都会出现

    2.4     粘包

    发送方发送的多个包数据到接收方接收时粘成一个包,从接收缓冲区看,后一包数据的头紧接着前一包数据的尾。

    分类:一种是粘在一起的包都是完整的数据包,另一种情况是粘在一起的包有不完整的包

    出现粘包现象的原因是多方面的:

    1)发送方粘包:由TCP协议本身造成的,TCP为提高传输效率,发送方往往要收集到足够多的数据后才发送一包数据。若连续几次发送的数据都很少,通常TCP会根据优化算法把这些数据合成一包后一次发送出去,这样接收方就收到了粘包数据。

    2)接收方粘包:接收方用户进程不及时接收数据,从而导致粘包现象。这是因为接收方先把收到的数据放在系统接收缓冲区,用户进程从该缓冲区取数据,若下一包数据到达时前一包数据尚未被用户进程取走,则下一包数据放到系统接收缓冲区时就接到前一包数据之后,而用户进程根据预先设定的缓冲区大小从系统接收缓冲区取数据,这样就一次取到了多包数据。

    2.5     分包

    分包(1):在出现粘包的时候,我们的接收方要进行分包处理;

    分包(2):一个数据包被分成了多次接收;

    原因:1. IP分片传输导致的;2.传输过程中丢失部分包导致出现的半包;3.一个包可能被分成了两次传输,在取数据的时候,先取到了一部分(还可能与接收的缓冲区大小有关系)。

    影响:粘包和分包在长连接中都会出现

    2.6     如何解决半包,粘包问题

    出现粘包和半包现象,是因为TCP当中,只有流的概念,没有包的概念。

    UDP不会出现半包,粘包情况,原因是UDP是一个完整的数据包,发送时不进行合并,因此接收的时候就不存在粘包情况。

     

    固定长度:每次发送固定长度的数据;

    特殊标示:以回车,换行作为特殊标示;获取到指定的标识时,说明包获取完整。

    字节长度:包头+包长+包体的协议形式,当服务器端获取到指定的包长时才说明获取完整;

     

    参考文章(有图):http://blog.csdn.net/pi9nc/article/details/17165171

    2.7     什么时候需要考虑粘包的情况

    短连接:不用考虑粘包的情况;

    发送数据无结构,如文件传输,这样发送方只管发送,接收方只管接收存储,也不用考虑粘包;

    长连接:需要在连接后一段时间内发送不同结构数据;

     

    处理方式:接收方创建一预处理线程,对接收到的数据包进行预处理,将粘连的包分开;

    2.8     TCP与UDP的差别

    • 基于连接与无连接;
    • 对系统资源的要求(TCP较多,UDP少);
    • UDP程序结构较简单;
    • 流模式与数据报模式 ;
    • TCP保证数据正确性,UDP可能丢包,TCP保证数据顺序,UDP不保证。
    • 网络分化:机器本身是好的,但是之间的通信出现问题;
    • 网络抖动:网络中的延迟是指信息从发送到接收经过的延迟时间,一般由传输延迟及处理延迟组成;而抖动是指最大延迟与最小延迟的时间差,如最大延迟是20毫秒,最小延迟为5毫秒,那么网络抖动就是15毫秒,它主要标识一个网络的稳定性。

    2.9     其他通信问题

    2.10         参考资料

    一个包没有固定长度,以太网限制在46-1500字节,1500就是以太网的MTU,超过这个量,TCP会为IP数据报设置偏移量进行分片传输,现在一般可允许应用层设置8k(NTFS系)的缓冲区,8k的数据由底层分片,而应用看来只是一次发送。

     

    对于UDP,就不要太大,一般在1024至10K。注意一点,你无论发多大的包,IP层和链路层都会把你的包进行分片发送,一般局域网就是1500左右,广域网就只有几十字节。分片后的包将经过不同的路由到达接收方,对于UDP而言,要是其中一个分片丢失,那么接收方的IP层将把整个发送包丢弃,这就形成丢包。

     

    TCP作为流,发包是不会整包到达的,而是源源不断的到,那接收方就必须组包。而UDP作为消息或数据报,它一定是整包到达接收方。

     

    关于接收,一般的发包都有包边界,首要的就是你这个包的长度要让接收方知道,于是就有个包头信息,对于TCP,接收方先收这个包头信息,然后再收包数据。一次收齐整个包也可以,可要对结果是否收齐进行验证。这也就完成了组包过程。UDP,那你只能整包接收了。要是你提供的接收Buffer过小,TCP将返回实际接收的长度,余下的还可以收,而UDP不同的是,余下的数据被丢弃并返回WSAEMSGSIZE错误。注意TCP,要是你提供的Buffer佷大,那么可能收到的就是多个发包,你必须分离它们,还有就是当Buffer太小,而一次收不完Socket内部的数据,那么Socket接收事件(OnReceive),可能不会再触发,使用事件方式进行接收时。

    3       Socket实例

    3.1     Socket通信模型

     

     

     

    3.2     Socket架构完整模型

    • 解决半包,粘包(编解码)
    • 服务端支持多线程
    • 支持心跳检测
    • 指定端口实例化一个SeverSocket
    • 调用ServerSocket的accept()方法,以在等待连接期间造成阻塞
    • 获取位于该底层的Socket的流以进行读写操作
    • 将数据封装成流
    • 对Socket进行读写
    • 关闭打开的流

    3.3     服务端开发

     

    //建立ServerSocket对象,监听绑定端口

    ServerSocket server=new ServerSocket(1000);

     

    //建立接收Socket,阻塞响应

    Socket client=server.accept();

     

    //获得输入流,用于接收客户端信息

    InputStream in=server.getInputStream();

    //获得输出流,用于输出客户端信息

     

    //对输入流进行包装,方便使用

    BufferedReader inRead=new BufferedReader(new InputStreamReader(in));

    //对输出流进行包装,方便使用

    PrintWriter outWriter=new PrintWriter(out);

     

    while(true)

    {

    String str=inRead.readLine();//读入

    outWriter.println("输出到客户端");

    outWriter.flush();//输出

    if(str.equals("end"))

    {

    break;

    }

    }

    //关闭Socket

    client.close();

    server.close();

     

    3.4     客户端开发

    • 通过IP地址和端口实例化Socket,请求连接服务器
    • 获得Socket上的流以进行读写
    • 把流封装进BufferedReader/PrintWriter的实例
    • 对Socket进行读写
    • 关闭打开的流

     

    //使用Socket,建立与服务端的连接

    Socket client=new Socket("127.0.0.1",1000);

    InputStream in=client.getInputStream();//获得输入流

    OutputStream out=client.getOutputStream();//获得输出流

    //包装输入流,输出流

    BufferedReader inRead=new BufferedReader(new InputStreamReader(in));

    PrintWriter outWriter=new PrintWriter(out);

    //获得控制台输入

    BufferedReader inConsole=new BufferedReader(new InputStreamReader(in));

    while(true)

    {

    String str=inConsole.readLine();//读取控制台输入

    outWriter.println(str);//输出到服务端

    outWriter.flush();//刷新缓冲区

    if(str.equals("end"))

    {

    break;

    }//退出

    System.out.println(inRead.readLine())//读取服务端输出

    }

    client.close();

     

    DOS下运行客户端

    java -classpath sockettest-0.0.1-SNAPSHOT.jar cn.com.gome.sockettest.basic.ClientTest

    3.5     多线程服务端

     

    3.6     心跳检测

             方法1:socket.sendUrgentData(0);//发送1个字节的紧急数据,默认情况下,服务器端没有开启紧急数据处理,不影响正常通信

    try{
          socket.sendUrgentData(0xFF);
    }catch(Exception ex){
          reconnect();
    }

             只要对方Socket的SO_OOBINLINE属性没有打开,就会自动舍弃这个字节,而SO_OOBINLINE属性默认情况下就是关闭的。

     

             方法2:自定义心跳字符串

    3.7     各类数据读写

             传输字节,字符,对象【ObjectInputStream ObjectOutputStream】(实例)

    参考:

    http://www.cnblogs.com/itfly8/p/5844803.html

  • 相关阅读:
    Truck History(poj 1789)
    Highways poj 2485
    117. Populating Next Right Pointers in Each Node II
    116. Populating Next Right Pointers in Each Node
    115. Distinct Subsequences
    114. Flatten Binary Tree to Linked List
    113. Path Sum II
    109. Convert Sorted List to Binary Search Tree
    106. Construct Binary Tree from Inorder and Postorder Traversal
    105. Construct Binary Tree from Preorder and Inorder Traversal
  • 原文地址:https://www.cnblogs.com/winner-0715/p/7252871.html
Copyright © 2011-2022 走看看