程序间达成的某种包含了信息交换的形式和意义的共识称为协议,用来实现特定应用程序的协议叫做应用程序协议。大部分应用程序协议是根据由字段序列组成的离散信息定义的,其中每个字段中都包含了一段以位序列编码(即二进制字节编码,也可以使用基于文本编码的方式,但常用协议如:TCP、UDP、HTTP等在传输数据时,都是以位序列编码的)的特定信息。应用程序协议中明确定义了信息的发送者应该如何排列和解释这些位序列,同时还要定义接收者应该如何解析,这样才能使信息的接收者能够抽取出每个字段的意义。TCP/IP协议唯一的约束:信息必须在块中发送和接收,而块的长度必须是8位的倍数,因此,我们可以认为TCP/IP协议中传输的信息是字节序列。

由于协议通常处理的是由一组字段组成的离散的信息,因此应用程序协议必须指定消息的接收者如何确定何时消息已被完整接收。成帧技术就是解决接收端如何定位消息首尾位置问题的,  由于协议通常处理的是由一组字段组成的离散的信息,因此应用程序协议必须指定消息的接收者如何确定何时消息已被完整。主要有两种技术使接收者能够准确地找到消息的结束位置:

1、基于定界符:消息的结束由一个唯一的标记指出,即发送者在传输完数据后显式添加的一个特定字节序列,这个特殊标记不能在传输的数据中出现(这也不是绝对的,应用填充技术能够对消息中出现的定界符进行修改,从而使接收者不将其识别为定界符)。该方法通常用在以文本方式编码的消息中。

2、显式长度:在变长字段或消息前附加一个固定大小的字段,用来指示该字段或消息中包含了多少字节。该方法主要用在以二进制字节方式编码的消息中。

由于UDP套接字保留了消息的边界信息,因此不需要进行成帧处理(实际上,主要是DatagramPacket负载的数据有一个确定的长度,接收者能够准确地知道消息的结束位置),而TCP协议中没有消息边界的概念,因此,在使用TCP套接字时,成帧就是一个非常重要的考虑因素(在TCP连接中,接收者读取完最后一条消息的最后一个字节后,将受到一个流结束标记,即read()返回-1,该标记指示出已经读取到了消息的末尾,非严格意义上来讲,这也算是基于定界符方法的一种特殊情况)。

下面给出一个自定义实现上面两种成帧技术的Demo(书上的例子),先定义一个Framer接口,它由两个方法:frameMag()方法用来添加成帧信息并将指定消息输出到指定流,nextMsg()方法则扫描指定的流,从中抽取出下一条消息。

import java.io.IOException;
import java.io.OutputStream;  public interface Framer {  void frameMsg(byte[] message, OutputStream out) throws IOException;  byte[] nextMsg() throws IOException;
}  

下面的代码实现了基于定界符的成帧方法,定界符为换行符“\n”,frameMsg()方法并没有实现填充,当成帧的字节序列中包含有定界符时,它只是简单地抛出异常;nextMsg()方法扫描刘,直到读取到了定界符,并返回定界符前面所有的字符,如果流为空则返回null,如果直到流结束也没找到定界符,程序将抛出一个异常来指示成帧错误。

import java.io.ByteArrayOutputStream;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;  public class DelimFramer implements Framer {  private InputStream in;        // 数据来源  private static final byte DELIMITER = '\n'; // 定界符  public DelimFramer(InputStream in) {  this.in = in;  }  public void frameMsg(byte[] message, OutputStream out) throws IOException {  for (byte b : message) {  if (b == DELIMITER) {  //如果在消息中检查到界定符,则抛出异常  throw new IOException("Message contains delimiter");  }  }  out.write(message);  out.write(DELIMITER);  out.flush();  }  public byte[] nextMsg() throws IOException {  ByteArrayOutputStream messageBuffer = new ByteArrayOutputStream();  int nextByte;  while ((nextByte = in.read()) != DELIMITER) {  //如果流已经结束还没有读取到定界符  if (nextByte == -1) {   //如果读取到的流为空,则返回null  if (messageBuffer.size() == 0) {   return null;  } else {   //如果读取到的流不为空,则抛出异常  throw new EOFException("Non-empty message without delimiter");  }  }  messageBuffer.write(nextByte);   }  return messageBuffer.toByteArray();  }
}  

下面的代码实现了基于长度的成帧方法,适用于长度小于65535个字节的消息。发送者首先给出指定消息的长度,并将长度信息以big-endian顺序(从左边开始,由高位到低位发送)存入2个字节的整数中,再将这两个字节存放在完整的消息内容前,连同消息一起写入输出流;在接收端,使用DataInputStream读取整型的长度信息,readFully()方法将阻塞等待,直到给定的数组完全填满。使用这种成帧方法,发送者不需要检查要成帧的消息内容,而只需要检查消息的长度是否超出了限制。

import java.io.DataInputStream;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;  public class LengthFramer implements Framer {  public static final int MAXMESSAGELENGTH = 65535;  public static final int BYTEMASK = 0xff;  public static final int SHORTMASK = 0xffff;  public static final int BYTESHIFT = 8;  private DataInputStream in;  public LengthFramer(InputStream in) throws IOException {  this.in = new DataInputStream(in);    //数据来源
  }  //对字节流message添加成帧信息,并输出到指定流   public void frameMsg(byte[] message, OutputStream out) throws IOException {  //消息的长度不能超过65535  if (message.length > MAXMESSAGELENGTH) {  throw new IOException("message too long");  }  out.write((message.length >> BYTESHIFT) & BYTEMASK);  out.write(message.length & BYTEMASK);  out.write(message);  out.flush();  }  public byte[] nextMsg() throws IOException {  int length;  try {   //该方法读取2个字节,将它们作为big-endian整数进行解释,并以int型整数返回它们的值  length = in.readUnsignedShort();   } catch (EOFException e) { // no (or 1 byte) message  return null;  }  // 0 <= length <= 65535  byte[] msg = new byte[length];  //该方法处阻塞等待,直到接收到足够的字节来填满指定的数组
    in.readFully(msg);   return msg;  }
}  

转自:http://blog.csdn.net/ns_code/article/details/14225541

转载于:https://www.cnblogs.com/yixiu868/p/8034774.html

【Java TCP/IP Socket】应用程序协议中消息的成帧与解析(含代码)相关推荐

  1. Java TCP/IP Socket 编程 笔记

    http://jimmee.iteye.com/blog/617110 http://jimmee.iteye.com/category/93740 Java TCP/IP Socket 编程 笔记( ...

  2. tcp/ip协议中消息传输对帧消息的操作

    2019独角兽企业重金招聘Python工程师标准>>> 接口:Framer.java: package com.tcpip;import java.io.IOException; i ...

  3. 【Java TCP/IP Socket】TCP Socket通信中由read返回值造成的的死锁问题(含代码)(转)...

    书上示例 在第一章<基本套接字>中,作者给出了一个TCP Socket通信的例子--反馈服务器,即服务器端直接把从客户端接收到的数据原原本本地反馈回去. 书上客户端代码如下: 1 2 3 ...

  4. java tcp read_【Java TCP/IP Socket】TCP Socket通信中由read返回值造成的的死锁问题(含代码)(转)...

    书上示例 在第一章<基本套接字>中,作者给出了一个TCP Socket通信的例子--反馈服务器,即服务器端直接把从客户端接收到的数据原原本本地反馈回去. 书上客户端代码如下: 书上的服务器 ...

  5. WIFI项目--【Java TCP/IP Socket】 — 单播、广播、组播

    在当前网络通信中(TCP/IP也不例外)有三种通信模式:单播.广播.组播(又叫多播, 个人感觉叫多播描述的有点不恰当),其中多播出现的时间最晚,但同时具备单播和广播的优点,最具有发展前景. 通信方式分 ...

  6. 【Java TCP/IP Socket】 — close()/shutdownOutput()/shutdownInput() 分析

    https://blog.csdn.net/dabing69221/article/details/17351881

  7. JMeter测试TCP/IP Socket应用的性能

    摘要 本文描述了如何利用JMeter来测试TCP/IP Socket应用的性能.文章先对Socket作了一点简单介绍,然后提供并解释了两个样例Socket应用,最后介绍如何利用JMeter来对它们进行 ...

  8. TCP/IP SOCKET HTTP及HTTPS之间的关系

    GET跟POST的区别: get只能传送128K的数据 而post是无限制的 post提交是不在会IE上带上参数 就算你加密了别人也会解密 一般比较重要的数据通过post 传,因为get是别人可以改参 ...

  9. linux下IPROTO_TCP,TCP/IP协议栈在Linux内核中的运行时序分析

    可选题目三:TCP/IP协议栈在Linux内核中的运行时序分析 在深入理解Linux内核任务调度(中断处理.softirg.tasklet.wq.内核线程等)机制的基础上,分析梳理send和recv过 ...

最新文章

  1. [Linux程序设计][调试][ElectricFence]
  2. P3964-[TJOI2013]松鼠聚会【计算几何】
  3. 不攀比,不张望,用心,专一
  4. Teamviewer远程连接(Win和Linux下teamviewer软件互连)
  5. FLAG_ACTIVITY_CLEAR_TOP和singleTask的区别
  6. VS下使用多字符集编码和Unicode字符集编码的总结
  7. 用java语言写出青蛙的身份_第三章 JAVA 语言基础
  8. git恢复已删除的本地分支
  9. begin tran创建事务、commit tran提交事务、rollback tran回滚(撤消)事务的用法及理解
  10. [WARNING] Corrupted STDOUT by directly writing to native stream in forked JVM 1
  11. 揭开 Xxl-job 的神秘面纱
  12. 网络工程师备考6章(续3)
  13. 云目录(DaaS )快速入门
  14. Topcoder 2016 TCO Algorithm Algo Semifinal 1 Hard ColorfunPath [网络流]
  15. Openwrt-Chaos_Calmer搭建编译环境问题处理
  16. 未来视频编码_设计编码营销并消费未来
  17. 计算机课设微程序最大值,计算机组成原理课程设计(微程序设计).doc
  18. set、env、export的区别
  19. elementui的el-autocomplete远程搜索组件如何回显结果
  20. 戴尔 OptiPlex 7070 台式电脑配置信息

热门文章

  1. Proxy(代理,拦截器),Reflect(反射)
  2. Python 操作 Azure Blob Storage
  3. Python OpenCV学习笔记之:灰度图像的直方图计算
  4. en 2014-12-31
  5. SCCM报表点和SQL Server的报表服务集成, 随心所欲创建报表?
  6. 小程序Windows和linux,改进后的《自动显示天气预报》小程序(Linux和Windows环境都可以)...
  7. camera驱动电源配置_基于AD7656-1和ADuC7026评估电源时序控制影响
  8. windows优化大师怎么用_软件不能用又卸载不掉怎么办——用Windows自家的卸载工具吧(dos级卸载)...
  9. 洛谷P3292 [SCOI2016]幸运数字(倍增+线性基)
  10. NNS域名系统之SGAS