从Socket中解析Http协议实现通信

        在网络协议中,Socket是连接应用层和运输层的中间层,主要作用为了通信。Http协议是应用层上的封装协议。我们可以通过Http协议的规范解析Socket中数据,完成Http通信。

        首先,我们先回顾一下Http协议的规范。主要复习一下,请求与响应报文格式,方便我们解析Socket中数据。请求报文格式具体如下图:

         响应报文格式具体如下图:

         了解Http请求和响应的报文格式后,可准备编写代码了。Java的Socket支持BIO、NIO等IO模型,我以下的代码使用BIO阻塞模式实现通信,具体代码如下:

        HttpBioServer类主要负责开启Socket服务端监听,当有客户端连接接入后,读取客户端数据,将客户端数据交给另一个线程处理。另一个线程会调用http(),http()会解析Http请求的数据,对数据进行一些操作后,再封装一个响应体返回给客户端。


import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;/*** 〈一句话功能简述〉<br>* 〈Bio服务端〉** @author hanxiaozhang* @create 2023/6/20* @since 1.0.0*/
public class HttpBioServer {public static void main(String[] args) throws Exception {ServerSocket server = new ServerSocket(9090, 20);while (true) {// 阻塞1Socket client = server.accept();
//            System.out.println(client.getInetAddress());
//            System.out.println(client.getLocalPort());System.out.println("client connect success,client port is " + client.getPort());new Thread(new Runnable() {@Overridepublic void run() {try {http(client);client.close();System.out.println("client close");} catch (IOException e) {e.printStackTrace();}}}).start();}}/*** Http协议** @param client* @throws IOException*/private static void http(Socket client) throws IOException {// 读取输入流中数据ByteArrayOutputStream byteArrayOut = new ByteArrayOutputStream();try {InputStream in = client.getInputStream();int len = 0;byte[] buf = new byte[1024];// 每次读取 1024 字节,知道读取完成while ((len = in.read(buf)) != 0) {byteArrayOut.write(buf, 0, len);if (in.available() == 0) {break;}}byte[] bytes = byteArrayOut.toByteArray();RequestEntity request = new RequestEntity();request.byteToRequest(bytes);byte[] responseBytes = handler(request);OutputStream ops = client.getOutputStream();ops.write(responseBytes);ops.flush();} finally {byteArrayOut.close();}}private static byte[] handler(RequestEntity request) {System.out.println("request is " + request);Map<String, String> headers = new HashMap<>(4);headers.put("Content-Type", "text/plain");String body = "success";// 假装处理一些逻辑ResponseEntity response = new ResponseEntity(200, "OK", headers, body);byte[] responseBytes = response.responseToBytes(request);System.out.println("response is " + response);return responseBytes;}}

        RequestEntity类主要是存储Http请求解析后的数据,并且包含了一个将请求数据转换为RequestEntity类数据的方法。


import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;/*** 〈一句话功能简述〉<br>* 〈请求实体〉** @author hanxiaozhang* @create 2023/6/25* @since 1.0.0*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Accessors(chain = true)
public class RequestEntity {/*** 请求行*/private String requestLine;/*** 请求方法*/private String method;/*** Url*/private String url;/*** 版本协议*/private String requestAndVersion;/*** header*/private Map<String, String> headers;/*** 报文内容*/private String body;/*** 字节数组转换request实体** @param bytes* @return*/public void byteToRequest(byte[] bytes) {// \r\n连续出现两次的情况认为首部结束,剩下是主体部分int flag = 0;// 是否为body内容boolean isBody = false;char temp;StringBuffer headerSb = new StringBuffer(),bodySb = new StringBuffer();Map<String, String> headers = new HashMap<>(16);// 解析请求报文头和请求bodyfor (int i = 0; i < bytes.length; i++) {if (isBody) {bodySb.append((char) bytes[i]);} else {temp = (char) bytes[i];if (temp == '\r' || temp == '\n') {flag++;} else {flag = 0;}if (flag == 4) {isBody = true;}headerSb.append(temp);}}// 解析请求行String[] lines = headerSb.toString().split("\r\n");String requestLine = lines[0];String[] requestLines = requestLine.split("\\s");this.setRequestLine(requestLine).setMethod(requestLines[0]).setUrl(requestLines[1]).setRequestAndVersion(requestLines[2]);// 解析请求headerfor (int i = 1; i < lines.length; i++) {if (lines[i] != "") {String[] header = lines[i].split(": ");headers.put(header[0], header[1]);}}this.setHeaders(headers).setBody(bodySb.toString());}}

        ResponseEntity类主要是存储Http需要响应的数据,并且包含了一个将ResponseEntity类数据转换成Http响应的方法。

import com.hanxiaozhang.utils.StringUtil;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;import java.util.HashMap;
import java.util.Map;/*** 〈一句话功能简述〉<br>* 〈〉** @author hanxiaozhang* @create 2023/6/25* @since 1.0.0*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Accessors(chain = true)
public class ResponseEntity {public ResponseEntity(Integer stateCode, String reason, Map<String, String> headers, String body) {this.stateCode = stateCode;this.reason = reason;this.headers = headers;this.body = body;}/*** 状态*/private String stateLine;/*** 版本协议*/private String requestAndVersion;/*** 状态码*/private Integer stateCode;/*** 原因*/private String reason;/*** 响应header*/private Map<String, String> headers;/*** 响应内容*/private String body;public byte[] responseToBytes(RequestEntity request) {// 处理状态行StringBuilder sb = new StringBuilder();this.requestAndVersion = request.getRequestAndVersion();this.stateLine = request.getRequestAndVersion() + " " + stateCode + " " + reason;sb.append(stateLine);sb.append("\r\n");// 处理响应headerMap<String, String> tempHeaders = new HashMap<>(16);tempHeaders.putAll(request.getHeaders());if (this.headers != null && !this.headers.isEmpty()) {tempHeaders.putAll(this.headers);}if (StringUtil.isNotBlank(this.body)) {tempHeaders.put("Content-Length", String.valueOf(this.body.length()));}tempHeaders.forEach((k, v) -> {sb.append(k + ": " + v + "\r\n");});sb.append("\r\n");// 处理响应bodyif (StringUtil.isNotBlank(this.body)) {sb.append(this.body);}return sb.toString().getBytes();}}

        最后,我们启动HttpBioServer类,在浏览器中地址栏请求该地址,看一下效果:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/465056.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

前端工程化面试题 | 01.精选前端工程化高频面试题

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

JAVA设计模式之代理模式详解

代理模式 1 代理模式介绍 在软件开发中,由于一些原因,客户端不想或不能直接访问一个对象,此时可以通过一个称为"代理"的第三者来实现间接访问.该方案对应的设计模式被称为代理模式. 代理模式(Proxy Design Pattern ) 原始定义是&#xff1a;让你能够提供对象的替代…

Java String源码剖析+面试题整理

由于字符串操作是计算机程序中最常见的操作之一&#xff0c;在面试中也是经常出现。本文从基本用法出发逐步深入剖析String的结构和性质&#xff0c;并结合面试题来帮助理解。 String基本用法 在Java中String的创建可以直接像基本类型一样定义&#xff0c;也可以new一个 Str…

配备Apple T2 安全芯片的 Mac 机型及T2芯片mac电脑U盘装系统教程

T2 芯片为 Mac 提供了一系列功能&#xff0c;例如加密储存和安全启动功能、增强的图像信号处理功能&#xff0c;以及适用于触控 ID 数据的安全保护功能。哪些电脑配备了 T2 安全芯片呢&#xff0c;T2芯片mac电脑又如何重装系统呢&#xff1f;跟随小编一起来看看吧&#xff01; …

2024-2-11-复习作业

1> 要求&#xff1a; 源代码&#xff1a; #include <stdio.h> int fun(int n) {if(n0) return 1;return n*fun(n-1); } int main(int argc, char const *argv[]) {/* code */int n;printf("enter n :");scanf("%d",&n);int sfun(n);printf(…

[word] word分割线在哪里设置 #其他#经验分享

word分割线在哪里设置 在工作中有些技巧&#xff0c;可以快速提高工作效率&#xff0c;解决大部分工作&#xff0c;今天给大家分享word分割线在哪里设置的小技能&#xff0c;希望可以帮助到你。 1、快速输入分割线 输入三个【_】按下回车就是一条长直线&#xff0c;同样分别…

面向对象--静态

目录 一、静态 1.1 static修饰成员变量 1.2 static修饰成员变量的应用场景 1.3 static修饰成员方法 1.4 工具类 1.5 static的注意事项 1.6 static应用&#xff08;代码块&#xff09; 面向对象基本理解 写完会在此处放上链接 一、静态 面向对象编程中很常见的一个关键字…

一台Mac同时安装vue2和vue3

背景&#xff1a;电脑需要运行vue2和vue3项目&#xff0c;就得同时有vue2和vue3环境&#xff0c;之前以配置好vue2了&#xff0c;现在增加vue3 1. 新建一个安装vue3的目录 进入vue3文件夹安装vue3 // 注意这里没有参数-g&#xff0c;因为-g全局安装的命令 npm install vue/cli…

Jumpserver教程01:部署jumpserver

Jumpserver教程 注&#xff1a; 本教程由羞涩梦整理同步发布&#xff0c;本人技术分享站点&#xff1a;blog.hukanfa.com 转发本文请备注原文链接&#xff0c;本文内容整理日期&#xff1a;2024-02-11 csdn 博客名称&#xff1a;五维空间-影子&#xff0c;欢迎关注 简要说明…

【计算机网络】进程通信

进程 process 客户和服务器进程 下载文件表示为客户 &#xff0c;上载文件的对等方表示为服务器进程与计算机网络之间的接口 套接字 socket 应用层与传输层之间的接口是建立网络应用程序的可编程接口 API进程寻址 为了标识接收进程 需要两种信息 主机的地址目的主机中的接收进程…

实景三维数据库管理系统助力实景三维中国建设

四维轻云实景三维平台作为立足基础测绘与实景三维建设工作的产品&#xff0c;致力于通过技术创新与应用&#xff0c;支持构建时空一体、联动更新、按需服务、开放共享的实景三维数据体系&#xff0c;实现对实景三维数据从处理、建库、更新、管理到应用服务的全生命周期管理&…

多视图特征学习 Multi-view Feature Learning既可以被看作是一种学习框架,也可以被看作是一种具体的学习算法!

Multi-view Feature Learning 1.多视图特征学习Multi-view Feature Learning的基本介绍总结 1.多视图特征学习Multi-view Feature Learning的基本介绍 多视图特征学习是一种利用多视图数据集来进行联合学习的机器学习方法。多视图数据指的是对同一事物从多种不同的途径或角度进…