使用 Java 类 实现Http协议

目录
  • Java 实现Http协议
    • 一、协议请求的定义
    • 二、响应协议的定义
    • 三、编码常量定义
    • 四、客户端的实现
    • 五、服务端的实现
    • 六、ProtocolUtils工具类的实现
    • 七、ByteUtils类的实现

Java 实现Http协议

HTTP协议属于应用层协议,它构建于TCP和IP协议之上,处于TCP/IP协议架构层的顶端,所以,它不用处理下层协议间诸如丢包补发、握手及数据的分段及重新组装等繁琐的细节,使开发人员可以专注于应用业务。

协议是通信的规范,为了更好的理解HTTP协议,我们可以基于Java的Socket API接口,通过设计一个简单的应用层通信协议,来简单分析下协议实现的过程和细节。

在我们今天的示例程序中,客户端会向服务端发送一条命令,服务端在接收到命令后,会判断命令是否是“HELLO”,如果是“HELLO”, 则服务端返回给客户端的响应为“hello”,否则,服务端返回给客户端的响应为“bye bye”。

我们接下来用Java实现这个简单的应用层通信协议,

一、协议请求的定义

协议的请求主要包括:编码、命令和命令长度三个字段。

package com.binghe.params;
/**
 * 协议请求的定义
 * @author binghe
 *
 */
public class Request {
 /**
  * 协议编码
  */
 private byte encode;

 /**
  * 命令
  */
 private String command;

 /**
  * 命令长度
  */
 private int commandLength;

 public Request() {
  super();
 }

 public Request(byte encode, String command, int commandLength) {
  super();
  this.encode = encode;
  this.command = command;
  this.commandLength = commandLength;
 }

 public byte getEncode() {
  return encode;
 }

 public void setEncode(byte encode) {
  this.encode = encode;
 }

 public String getCommand() {
  return command;
 }

 public void setCommand(String command) {
  this.command = command;
 }

 public int getCommandLength() {
  return commandLength;
 }

 public void setCommandLength(int commandLength) {
  this.commandLength = commandLength;
 }

 @Override
 public String toString() {
  return "Request [encode=" + encode + ", command=" + command
    + ", commandLength=" + commandLength + "]";
 }

}

二、响应协议的定义

协议的响应主要包括:编码、响应内容和响应长度三个字段。

package com.binghe.params;

/**
 * 协议响应的定义
 * @author binghe
 *
 */
public class Response {
 /**
  * 编码
  */
 private byte encode;

 /**
  * 响应内容
  */
 private String response;

 /**
  * 响应长度
  */
 private int responseLength;

 public Response() {
  super();
 }

 public Response(byte encode, String response, int responseLength) {
  super();
  this.encode = encode;
  this.response = response;
  this.responseLength = responseLength;
 }

 public byte getEncode() {
  return encode;
 }

 public void setEncode(byte encode) {
  this.encode = encode;
 }

 public String getResponse() {
  return response;
 }

 public void setResponse(String response) {
  this.response = response;
 }

 public int getResponseLength() {
  return responseLength;
 }

 public void setResponseLength(int responseLength) {
  this.responseLength = responseLength;
 }

 @Override
 public String toString() {
  return "Response [encode=" + encode + ", response=" + response
    + ", responseLength=" + responseLength + "]";
 }

}

三、编码常量定义

编码常量的定义主要包括UTF-8和GBK两种编码。

package com.binghe.constant;

/**
 * 常量类
 * @author binghe
 *
 */
public final class Encode {
 //UTF-8编码
 public static final byte UTF8 = 1;
 //GBK编码
 public static final byte GBK = 2;
}

四、客户端的实现

客户端先构造一个request请求,通过Socket接口将其发送到远端,并接收远端的响应信息,并构造成一个Response对象。

package com.binghe.protocol.client;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

import com.binghe.constant.Encode;
import com.binghe.params.Request;
import com.binghe.params.Response;
import com.binghe.utils.ProtocolUtils;

/**
 * 客户端代码
 * @author binghe
 *
 */
public final class Client {
 public static void main(String[] args) throws IOException{
  //请求
  Request request = new Request();
  request.setCommand("HELLO");
  request.setCommandLength(request.getCommand().length());
  request.setEncode(Encode.UTF8);

  Socket client = new Socket("127.0.0.1", 4567);
  OutputStream out = client.getOutputStream();

  //发送请求
  ProtocolUtils.writeRequest(out, request);

  //读取响应数据
  InputStream in = client.getInputStream();
  Response response = ProtocolUtils.readResponse(in);
  System.out.println("获取的响应结果信息为: " + response.toString());
 }
}

五、服务端的实现

服务端接收客户端的请求,根据接收命令的不同,响应不同的消息信息,如果是“HELLO”命令,则响应“hello”信息,否则响应“bye bye”信息。

package com.binghe.protocol.server;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

import com.binghe.constant.Encode;
import com.binghe.params.Request;
import com.binghe.params.Response;
import com.binghe.utils.ProtocolUtils;

/**
 * Server端代码
 * @author binghe
 *
 */
public final class Server {
 public static void main(String[] args) throws IOException{
  ServerSocket server = new ServerSocket(4567);
  while (true) {
   Socket client = server.accept();
   //读取请求数据
   InputStream input = client.getInputStream();
   Request request = ProtocolUtils.readRequest(input);
   System.out.println("收到的请求参数为: " + request.toString());
   OutputStream out = client.getOutputStream();
   //组装响应数据
   Response response = new Response();
   response.setEncode(Encode.UTF8);
   if("HELLO".equals(request.getCommand())){
    response.setResponse("hello");
   }else{
    response.setResponse("bye bye");
   }
   response.setResponseLength(response.getResponse().length());
   ProtocolUtils.writeResponse(out, response);
  }
 }
}

六、ProtocolUtils工具类的实现

ProtocolUtilsreadRequest方法将从传递进来的输入流中读取请求的encodecommandcommandLength三个参数,进行相应的编码转化,构造成Request对象返回。而writeResponse方法则是将response对象的字段根据对应的编码写入到响应的输出流中。

有一个细节需要重点注意:OutputStream中直接写入一个int类型,会截取其低8位,丢弃其高24位,所以,在传递和接收数据时,需要进行相应的转化操作。

package com.binghe.utils;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import com.binghe.constant.Encode;
import com.binghe.params.Request;
import com.binghe.params.Response;

/**
 * 协议工具类
 * @author binghe
 *
 */
public final class ProtocolUtils {
 /**
  * 从输入流中反序列化Request对象
  * @param input
  * @return
  * @throws IOException
  */
 public static Request readRequest(InputStream input) throws IOException{
  //读取编码
  byte[] encodeByte = new byte[1];
  input.read(encodeByte);
  byte encode = encodeByte[0];

  //读取命令长度
  byte[] commandLengthBytes = new byte[4];
  input.read(commandLengthBytes);
  int commandLength = ByteUtils.byte2Int(commandLengthBytes);

  //读取命令
  byte[] commandBytes = new byte[commandLength];
  input.read(commandBytes);
  String command = "";
  if(Encode.UTF8 == encode){
   command = new String(commandBytes, "UTF-8");
  }else if(Encode.GBK == encode){
   command = new String(commandBytes, "GBK");
  }
  //组装请求返回
  Request request = new Request(encode, command, commandLength);
  return request;
 }
 /**
  * 从输入流中反序列化Response对象
  * @param input
  * @return
  * @throws IOException
  */
 public static Response readResponse(InputStream input) throws IOException{
  //读取编码
  byte[] encodeByte = new byte[1];
  input.read(encodeByte);
  byte encode = encodeByte[0];

  //读取响应长度
  byte[] responseLengthBytes = new byte[4];
  input.read(responseLengthBytes);
  int responseLength = ByteUtils.byte2Int(responseLengthBytes);

  //读取命令
  byte[] responseBytes = new byte[responseLength];
  input.read(responseBytes);
  String response = "";
  if(Encode.UTF8 == encode){
   response = new String(responseBytes, "UTF-8");
  }else if(Encode.GBK == encode){
   response = new String(responseBytes, "GBK");
  }
  //组装请求返回
  Response resp = new Response(encode, response, responseLength);
  return resp;
 }

 /**
  * 序列化请求信息
  * @param output
  * @param response
  */
 public static void writeRequest(OutputStream output, Request request) throws IOException{
  //将response响应返回给客户端
  output.write(request.getEncode());
  //output.write(response.getResponseLength());直接write一个int类型会截取低8位传输丢弃高24位
  output.write(ByteUtils.int2ByteArray(request.getCommandLength()));
  if(Encode.UTF8 == request.getEncode()){
   output.write(request.getCommand().getBytes("UTF-8"));
  }else if(Encode.GBK == request.getEncode()){
   output.write(request.getCommand().getBytes("GBK"));
  }
  output.flush();
 }
 /**
  * 序列化响应信息
  * @param output
  * @param response
  */
 public static void writeResponse(OutputStream output, Response response) throws IOException{
  //将response响应返回给客户端
  output.write(response.getEncode());
  //output.write(response.getResponseLength());直接write一个int类型会截取低8位传输丢弃高24位
  output.write(ByteUtils.int2ByteArray(response.getResponseLength()));
  if(Encode.UTF8 == response.getEncode()){
   output.write(response.getResponse().getBytes("UTF-8"));
  }else if(Encode.GBK == response.getEncode()){
   output.write(response.getResponse().getBytes("GBK"));
  }
  output.flush();
 }
}

七、ByteUtils类的实现

package com.binghe.utils;

/**
 * 字节转化工具类
 * @author binghe
 *
 */
public final class ByteUtils {
 /**
  * 将byte数组转化为int数字
  * @param bytes
  * @return
  */
 public static int byte2Int(byte[] bytes){
  int num = bytes[3] & 0xFF;
  num |= ((bytes[2] << 8) & 0xFF00);
  num |= ((bytes[1] << 16) & 0xFF0000);
  num |= ((bytes[0] << 24) & 0xFF000000);
  return num;
 }

 /**
  * 将int类型数字转化为byte数组
  * @param num
  * @return
  */
 public static byte[] int2ByteArray(int i){
  byte[] result = new byte[4];
  result[0]  = (byte)(( i >> 24 ) & 0xFF);
  result[1]  = (byte)(( i >> 16 ) & 0xFF);
  result[2]  = (byte)(( i >> 8 ) & 0xFF);
  result[3]  = (byte)(i & 0xFF);
  return result;
 }
}

到此这篇关于关于Java 实现Http协议详细内容的文章就介绍到这了,更多相关Java 实现Http协议内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 基于JAVA中Jersey处理Http协议中的Multipart的详解

    那么Http协议中的Multipart是个什么东东?下面是摘抄http协议1.1的一段话:在multipart entity(多部分实体)的例子中,一个或多个不同的数据集合并在一个单一的body(体)中,一个"multipart"(多部分)类型 field的(域)必须出现在实体的header(头域).body(体)必须包括一个或多个body part(体部分),每一个位于boundary(边界)定界符线之前,最后一个则跟着一个结束边界定界符线.在它的边界定界符线后,每一个体部分由头域.

  • Java下载远程服务器文件到本地(基于http协议和ssh2协议)

    Java中java.io包为我们提供了输入流和输出流,对文件的读写基本上都依赖于这些封装好的关于流的类中来实现.前段时间遇到了以下两种需求: 1.与某系统对接,每天获取最新的图片并显示在前端页面.该系统提供的是一个http协议的图片URL,本来获取到该系统的图片地址以后在HTML中显示就可以了,但是该系统不太稳定,图片URL经常不能使用,而且每天生成图片不一定成功, 对自己系统的功能影响很大,emm...所以就考虑每天从该系统下载最新的图片到本地更新保存,没有新图片就继续使用上次的图片. 2.公

  • HTTP协议详解_动力节点Java学院整理

    一.概念 协议是指计算机通信网络中两台计算机之间进行通信所必须共同遵守的规定或规则,超文本传输协议(HTTP)是一种通信协议,它允许将超文本标记语言(HTML)文档从Web服务器传送到客户端的浏览器. HTTP协议,即超文本传输协议(Hypertext transfer protocol).是一种详细规定了浏览器和万维网(WWW = World Wide Web)服务器之间互相通信的规则,通过因特网传送万维网文档的数据传送协议. HTTP协议是用于从WWW服务器传输超文本到本地浏览器的传送协议.

  • Java与Http协议的详细介绍

    Java与Http协议的详细介绍 引言      http(超文本传输协议)是一个基于请求与响应模式的.无状态的.应用层的协议,常基于TCP的连接方式.HTTP协议的主要特点是:      1.支持客户/服务器模式.      2.简单快速:客户向服务器请求服务时,只需传送请求方法和路径.由于HTTP协议简单,通信速度很快.      3.灵活:HTTP允许传输任意类型的数据对象.类型由Content-Type加以标记.      4.无连接:即每次连接只处理一个请求,处理完客户的请求,并收到客

  • Java HTTP协议收发MQ 消息代码实例详解

    1. 准备环境 在工程 POM 文件添加 HTTP Java 客户端的依赖. <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-client</artifactId> <version>9.3.4.RC1</version> </dependency> <dependency> <groupId>com

  • HTTP协议入门_动力节点Java学院整理

    HTTP 协议是互联网的基础协议,也是网页开发的必备知识,最新版本 HTTP/2 更是让它成为技术热点. 本文介绍 HTTP 协议的历史演变和设计思路. 一.HTTP/0.9 HTTP 是基于 TCP/IP 协议的应用层协议.它不涉及数据包(packet)传输,主要规定了客户端和服务器之间的通信格式,默认使用80端口. 最早版本是1991年发布的0.9版.该版本极其简单,只有一个命令GET. GET /index.html 上面命令表示,TCP 连接(connection)建立后,客户端向服务器

  • javaweb中Http协议详解

    一.什么是HTTP协议 HTTP是hypertext transfer protocol(超文本传输协议)的简写,它是TCP/IP协议的一个应用层协议,用于定义WEB浏览器与WEB服务器之间交换数据的过程.客户端连上web服务器后,若想获得web服务器中的某个web资源,需遵守一定的通讯格式,HTTP协议用于定义客户端与web服务器通迅的格式. 二.HTTP协议的版本 HTTP协议的版本:HTTP/1.0.HTTP/1.1 三.HTTP1.0和HTTP1.1的区别 在HTTP1.0协议中,客户端

  • HTTP协议简介_动力节点Java学院整理

    TCP协议对应于传输层,而HTTP协议对应于应用层,从本质上来说,二者没有可比性.Http协议是建立在TCP协议基础之上的,当浏览器需要从服务器获取网页数据的时候,会发出一次Http请求.Http会通过TCP建立起一个到服务器的连接通道,当本次请求需要的数据完毕后,Http会立即将TCP连接断开,这个过程是很短的.所以Http连接是一种短连接,是一种无状态的连接.所谓的无状态,是指浏览器每次向服务器发起请求的时候,不是通过一个连接,而是每次都建立一个新的连接.如果是一个连接的话,服务器进程中就能

  • 使用 Java 类 实现Http协议

    目录 Java 实现Http协议 一.协议请求的定义 二.响应协议的定义 三.编码常量定义 四.客户端的实现 五.服务端的实现 六.ProtocolUtils工具类的实现 七.ByteUtils类的实现 Java 实现Http协议 HTTP协议属于应用层协议,它构建于TCP和IP协议之上,处于TCP/IP协议架构层的顶端,所以,它不用处理下层协议间诸如丢包补发.握手及数据的分段及重新组装等繁琐的细节,使开发人员可以专注于应用业务. 协议是通信的规范,为了更好的理解HTTP协议,我们可以基于Jav

  • java实现基于SGIP协议开发联通短信的方法

    本文实例讲述了java实现基于SGIP协议开发联通短信的方法.分享给大家供大家参考.具体如下: 近段时间,由于公司的业务需要,开发出了联通短信.此文章的编写也是根据网上的一些示例来完成的.闲话少说,下面来看代码:(运行此程序的时候需要导入华为的开发包,此包可以到网上下载) 下行: public class Mt { private static String SPNumber = "**********"; //接入号码 private static String ChargeNumb

  • Java实现TCP/IP协议的收发数据(服务端)代码实例

    这篇文章主要介绍了Java实现TCP/IP协议的收发数据(服务端)代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 功能如下: 注: 只有服务端,没有客户端,测试时采用第三方软件作为客户端的. 收发数据目前能正常收发数据,只是中文的会变成乱码显示. 采用Thread类实现一个收发数据的线程. 服务端代码: import java.io.IOException; import java.io.InputStream; import java

  • java实现基于TCP协议网络socket编程(C/S通信)

    一.前言:TCP原理简介 首先,保证文章完整性,TCP的理论原理还是需要简介一下,略显枯燥๑乛◡乛๑. TCP(传输控制协议,Transmission Control Protocol)是一种面向连接的.可靠的.基于字节流的传输层通信协议.TCP旨在适应支持多网络应用的分层协议层次结构.也就是说,TCP是为了在不可靠的互联网络上提供可靠的端到端字节流而专门设计的一个传输协议. 连接到不同但互连的计算机通信网络的主计算机中的成对进程之间依靠TCP提供可靠的通信服务. 以上TCP的特点,也正是与UD

  • java实现基于UDP协议网络Socket编程(C/S通信)

    一.前言:认识UDP UDP,全称User Datagram Protocol(用户数据报协议),是Internet 协议集支持一个无连接的传输协议.UDP 为应用程序提供了一种无需建立连接就可以发送封装的 IP 数据包的方法. UDP主要用于不要求分组顺序到达的传输中,分组传输顺序的检查与排序由应用层完成,提供面向报文的简单不可靠信息传送服务.UDP 协议基本上是IP协议与上层协议的接口,适用端口分别运行在同一台设备上的多个应用程序. 二.UDP的特点(与TCP相比) 正是UDP提供不可靠服务

  • 在DWR中实现直接获取一个JAVA类的返回值的两种方法

    第一种实现(来源网上转贴): js 代码 function Test() { var _data = ""; this.getString = function() { //设置成同步 DWREngine.setAsync(false); //调用Java类Test的getString方法,callBackFun为回调函数 JTest.getString(function(data){_data = data;} //重新设置为异步方式 DWREngine.setAsync(true)

  • classloader类加载器_基于java类的加载方式详解

    基础概念 Classloader 类加载器,用来加载 Java 类到 Java 虚拟机中.与普通程序不同的是.Java程序(class文件)并不是本地的可执行程序.当运行Java程序时,首先运行JVM(Java虚拟机),然后再把Java class加载到JVM里头运行,负责加载Java class的这部分就叫做Class Loader. JVM本身包含了一个ClassLoader称为Bootstrap ClassLoader,和JVM一样,BootstrapClassLoader是用本地代码实现

  • Java类初始化和实例化中的2个“雷区”

    在考虑类初始化时,我们都知道进行子类初始化时,如果父类没有初始化要先初始化子类.然而事情并没有一句话这么简单. 首先看看Java中初始化触发的条件: (1)在使用new实例化对象,访问静态数据和方法时,也就是遇到指令:new,getstatic/putstatic和invokestatic时: (2)使用反射对类进行调用时: (3)当初始化一个类时,父类如果没有进行初始化,先触发父类的初始化: (4)执行入口main方法所在的类: (5)JDK1.7动态语言支持中方法句柄所在的类,如果没有初始化

  • Java类的定义以及执行顺序学习教程

    类必须先定义才能使用.类是创建对象的模板,创建对象也叫类的实例化. 下面通过一个简单的例子来理解Java中类的定义: public class Dog{ String name; int age; void bark(){ // 汪汪叫 System.out.println("汪汪,不要过来"); } void hungry(){ // 饥饿 System.out.println("主人,我饿了"); } } 对示例的说明: public 是类的修饰符,表明该类是公

  • 浅析Java类和数据结构中常用的方法

    1.Object类里面常用的方法: protected Object clone()创建并返回此对象的一个副本. boolean equals(Object obj)指示其他某个对象是否与此对象"相等". protected void finalize()当垃圾回收器确定不存在对该对象的更多引用时,由对象的垃圾回收器调用此方法. Class<?> getClass()返回此 Object 的运行时类. int hashCode()返回该对象的哈希码值. void notif

随机推荐