目录
  • 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协议内容请搜索www.887551.com以前的文章或继续浏览下面的相关文章希望大家以后多多支持www.887551.com!