io之socket编程

news2024/12/27 3:10:31

写在前面

在这里插入图片描述

本文通过socket编程来实现一个简单的HttpServer。

1:单线程版本

我们使用单线程来实现一个HttpServer,如下:

package dongshi.daddy.io.httpserver;

import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;

public class HttpServer1 {

    public static void main(String[] args) throws Exception {
        ServerSocket serverSocket = new ServerSocket(8801);
        while (true) {
            try {
                Socket socket = serverSocket.accept();
                service(socket);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    private static void service(Socket socket) {
        String body = "hello,nio1";
        try {
            System.out.println("request come!!!");
            // 模拟耗时操作
            Thread.sleep(100);
            PrintWriter printWriter = new PrintWriter(socket.getOutputStream(), true);
            // 模拟http的响应,分为响应头和响应体(对象的组成也是头和体,不过是对象头和对象体),其中响应头和响应体通过换行符分割
            /*** 响应头开始 ***/
            printWriter.println("HTTP/1.1 200 OK");
            printWriter.println("Content-Type:text/html;charset=utf-8");
            // 注意一定要有该内容告知客户端响应体的长度,不然客户端将无法正常读取数据
            printWriter.println("Content-Length:" + body.getBytes().length);
            // 空行结束响应头
            printWriter.println();
            /*** 响应头结束 ***/

            /*** 响应体开始 ***/
            printWriter.write(body);
            /*** 响应体结束 ***/
//            printWriter.flush();
            printWriter.close();
            socket.close();
        } catch (Exception e) {
        }
    }
}

curl:

C:\WINDOWS\system32>curl http://localhost:8801
hello,nio1

superbenchmark,即sb压力测试:

D:\>sb -u http://localhost:8801 -c 40 -N 10
Starting at 2023/5/31 星期三 15:48:15
[Press C to stop the test]
92      (RPS: 6.4)
---------------Finished!----------------
Finished at 2023/5/31 星期三 15:48:29 (took 00:00:14.5303526)
102     (RPS: 7)                        Status 200:    102

RPS: 9 (requests/second)
Max: 4471ms
Min: 194ms
Avg: 3580.1ms

  50%   below 4380ms
  60%   below 4389ms
  70%   below 4400ms
  80%   below 4405ms
  90%   below 4415ms
  95%   below 4418ms
  98%   below 4418ms
  99%   below 4420ms
99.9%   below 4471ms
130     (RPS: 9)

RPS: 9 (requests/second)可以看到处每秒请求数是9,接下来看下多线程版本的性能表现。

2:多线程版本

我们使用多线程来实现一个HttpServer,如下:

package dongshi.daddy.io.httpserver;

import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;

public class HttpServer2 {

    public static void main(String[] args) throws Exception {
        ServerSocket serverSocket = new ServerSocket(8802);
        while (true) {
            try {
                Socket socket = serverSocket.accept();
//                service(socket);
                new Thread(() -> {
                    service(socket);
                }).start();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    private static void service(Socket socket) {
        String body = "hello,nio1";
        try {
            System.out.println("request come!!!");
            Thread.sleep(100);
            PrintWriter printWriter = new PrintWriter(socket.getOutputStream(), true);
            // 模拟http的响应,分为响应头和响应体(对象的组成也是头和体,不过是对象头和对象体),其中响应头和响应体通过换行符分割
            /*** 响应头开始 ***/
            printWriter.println("HTTP/1.1 200 OK");
            printWriter.println("Content-Type:text/html;charset=utf-8");
            // 注意一定要有该内容告知客户端响应体的长度,不然客户端将无法正常读取数据
            printWriter.println("Content-Length:" + body.getBytes().length);
            // 空行结束响应头
            printWriter.println();
            /*** 响应头结束 ***/

            /*** 响应体开始 ***/
            printWriter.write(body);
            /*** 响应体结束 ***/
//            printWriter.flush();
            printWriter.close();
            socket.close();
        } catch (Exception e) {
        }
    }
}

superbenchmark,即sb压力测试:

D:\>sb -u http://localhost:8802 -c 40 -N 10
Starting at 2023/5/31 星期三 15:49:33
[Press C to stop the test]
3478    (RPS: 253.3)
---------------Finished!----------------
Finished at 2023/5/31 星期三 15:49:47 (took 00:00:13.9143063)
Status 200:    3444
Status 303:    34

RPS: 308.8 (requests/second)
Max: 315ms
Min: 101ms
Avg: 112.8ms

  50%   below 108ms
  60%   below 108ms
  70%   below 109ms
  80%   below 110ms
  90%   below 114ms
  95%   below 124ms
  98%   below 218ms
  99%   below 220ms
99.9%   below 238ms

RPS 是308.8,明显好于单线程版本,但是这里是每次创建线程,而创建线程本身因为涉及到底层的操作,所以比较重,我们再改为线程池的版本看下效果。

3:线程池版本

package dongshi.daddy.io.httpserver;

import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class HttpServer3 {

    public static void main(String[] args) throws Exception {
        ServerSocket serverSocket = new ServerSocket(8803);
//        ExecutorService executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 2);
        ExecutorService executorService = Executors.newFixedThreadPool(50);
        while (true) {
            try {
                Socket socket = serverSocket.accept();
//                service(socket);
                executorService.execute(() -> service(socket));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    private static void service(Socket socket) {
        String body = "hello,nio1";
        try {
            System.out.println("request come!!!");
            Thread.sleep(100);
            PrintWriter printWriter = new PrintWriter(socket.getOutputStream(), true);
            // 模拟http的响应,分为响应头和响应体(对象的组成也是头和体,不过是对象头和对象体),其中响应头和响应体通过换行符分割
            /*** 响应头开始 ***/
            printWriter.println("HTTP/1.1 200 OK");
            printWriter.println("Content-Type:text/html;charset=utf-8");
            // 注意一定要有该内容告知客户端响应体的长度,不然客户端将无法正常读取数据
            printWriter.println("Content-Length:" + body.getBytes().length);
            // 空行结束响应头
            printWriter.println();
            /*** 响应头结束 ***/

            /*** 响应体开始 ***/
            printWriter.write(body);
            /*** 响应体结束 ***/
//            printWriter.flush();
            printWriter.close();
            socket.close();
        } catch (Exception e) {
        }
    }
}

superbenchmark,即sb压力测试:

D:\>sb -u http://localhost:8803 -c 40 -N 10
Starting at 2023/5/31 星期三 15:59:52
[Press C to stop the test]
3422    (RPS: 248.7)
3428    (RPS: 248.9)                    ---------------Finished!----------------
3428    (RPS: 248.9)                    Finished at 2023/5/31 星期三 16:00:06 (took 00:00:13.8633252)
3466    (RPS: 251.6)                    Status 200:    3430
Status 303:    36

RPS: 314.4 (requests/second)
Max: 256ms
Min: 101ms
Avg: 112.9ms

  50%   below 107ms
  60%   below 108ms
  70%   below 108ms
  80%   below 109ms
  90%   below 114ms
  95%   below 126ms
  98%   below 217ms
  99%   below 232ms
99.9%   below 255ms

RPS 是314.4,好于多线程版本的308.8。

写在后面

参考文章列表

SuperBenchmarker(简称“sb“)压力测试工具详解 。

在windows上通过choco安装superbenchmarker进行压测 。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

何为儒家的四书五经?

中国古代的四书五经是儒家经典之一,是中国古代最为重要的经典之一。它们包括了四书:《大学》、《中庸》、《论语》、《孟子》以及五经:《诗经》、《尚书》、《礼记》、《周易》、《春秋》,被誉为“经国之宝”、“德育之本”。 四书…

java服务接入SkyWalking时生成TraceId信息(基于logback)

java服务生成TraceId 一、背景二、配置2.1 pom文件引入依赖2.2 logback-spring.xml配置 三、启动项目 一、背景 springboot服务接入SkyWalking时,想要在控制台输出TraceId信息,如下图的效果: 二、配置 参考文章: https://juej…

2023最全性能测试学习指南【建议收藏】

浅谈软件测试中的性能测试 很多时候,我们都知道软件有黑白盒测试,但往往还遗漏掉了一个性能测试。 在下面的这篇文章中,就带领大家来了解性能测试。一起来学习吧~ 学习目录 一、 性能测试概念 二、 性能测试指标 三、 性能测试种类 四、 性能…

“政会银企”齐聚纵目科技,探索四方合作新模式

近日,纵目科技携手浦东新区工商业联合会、浦东新区金融工作局、上海市人工智能行业协会、交通银行张江支行、招商银行上海分行外滩支行、中信银行上海漕河泾支行、中国建设银行张江分行举办了一场别开生面的“政会银企”座谈会,深入交流、探讨了推动四方…

并发编程学习(十四):tomcat线程池

1、Tomcat 功能组件结构 Tomcat 的核心功能有两个,分别是负责接收和反馈外部请求的连接器 Connector,和负责处理请求的容器 Container。 其中连接器和容器相辅相成,一起构成了基本的 web 服务 Service。每个 Tomcat 服务器可以管理多个 Servi…

同声传译方法有哪些?我来给你介绍三个同声传译的好方法

假设有一场国际性的会议,参会者来自不同的国家和语言背景。在会议中,主要的演讲和讨论都是以主持人或演讲者的母语进行,这个时候场中的其他人很可能因为语言不通而无法理解演讲的内容,而翻译人员人数不足的时候,就更难…

Nmap常用基础命令详解

阅读目录 Nmap 主机发现扫描 Nmap 使用扫描脚本 Nmap 内网服务扫描 Nmap 是免费开放源代码实用程序,用于网络发现和安全审核。许多系统和网络管理员还发现它对于诸如网络清单,管理服务升级计划以及监视主机或服务正常运行时间之类的任务很有用。Nmap以…

2023全国科技工作者日——回顾2023小蛮腰科技大会暨AIGC人工智能峰会,致敬全国科技工作者

文章目录 一、前言二、2023全国科技工作者日三、回顾2023小蛮腰科技大会暨AIGC人工智能峰会3.1 关于小蛮腰科技大会暨AIGC人工智能峰会的背景3.2 2023小蛮腰科技大会:探寻AIGC新未来3.2.1 开幕式暨主论坛3.2.2 平行论坛1&6:迈向智能时代,…

Linux系统下imx6ull QT编程—— C++构造函数、析构函数、this指针(四)

Linux QT编程 文章目录 Linux QT编程一、什么是构造函数?二、什么是析构函数?三、示例四、this指针 一、什么是构造函数? 构造函数在对象实例化时被系统自动调用,仅且调用一次。前面我们学过类,实际上定义类时&#x…

普源DG1062Z函数/任意波形发生器产品介绍

DG1000Z系列函数/任意波形发生器是一款集函数发生器、任意波形发生器、噪声发生器、脉冲发生器、谐波发生器、模拟/数字调制器、频率计等功能于一身的多功能信号发生器。该系列所有型号皆具有2个功能*相同的通道,通道间相位可调。 产品特性 SiFi(Signal Fidelity)…

Android UEvent事件分析

1.背景概述 众所周知,在安卓系统中有状态栏,在插入外设的时候,会在顶部状态栏显示小图标。 比如,camera设备,耳机设备,U盘,以及电池等等。这些都需要在状态栏动态显示。 从上面这张图片可以看出这些设备都有自己的服务一直在跑,并且都是继承了UEventObserver.java这个…

自学网络安全/Web安全,一般人真的不行

本人之前写了不少网络安全技术相关的文章,不少读者朋友知道我是从事网络安全相关的工作,于是经常有人私信问我: 我刚入门网络安全,该怎么学? 要学哪些东西? 有哪些方向? 怎么选&#xf…

Windows和Linux服务器给图片添加水印两种方法,引用字体库和自带字体库

文章目录 一、效果展示二、前提说明三、Windows自带字体库实现方法四、引入字体库实现方法 一、效果展示 水印123如下图 1.可以自定义(类型:汉字、数字都支持) 2.可以定位指定位置 二、前提说明 实现添加水印功能中Windows服务器和Linux服…

系统日志管理

什么是系统日志 系统日志由 Linux/Unix 和其他网络设备(如交换机、路由器和防火墙)生成。系统日志包含有价值的信息,有助于保护网络和解决操作问题。因此,收集和分析系统日志至关重要。 系统日志包含什么 系统日志标准包含三个不…

Linux:MBR 扇区故障处理 (备份|恢复)

大概思路: 我们准备一个硬盘,并分出一个分区用于单独存放MBR备份文件 或者 和别的文件放在一起也可以(前提是不怕乱) 然后将分区挂载 然后进行MBR备份 把备份文件放到分区里 然后对MBR进行破坏(仅供实验参考&…

选择好的自动化测试工具影响会很大

根据当前项目和QA团队的人员能力,选择的自动化测试工具除具有使用的广泛性外,还必须考虑许多不同方面兼容性,例如项目迭代范围和需求变更。最佳工具并不能保证最佳的测试使用结果。 测试自动化的意义 随着自动化测试的普及,有关…

iPhone漏电10年大量用户受伤,官方回应:建议戴套

由于欧盟的强制要求,苹果用了多年的 Lightning 终于走到了尽头。 今年开始,包括 iPhone 15 全机型都将统一更换为 Type-C 接口。 对重视使用体验的用户来说,简直大快人心。 之前的 Lightning 不光蹭充电器相对麻烦,USB 2.0 的速…

可配置Modbus网关 嵌入式设备联网解决方案

1.概述 可配置Modbus网关可以预先配置Modbus RTU端的设备的地址、功能码和寄存器列表,并存储到网关内部。网关会自动采集这些配置的RTU设备的数据,然后映射到连续的Modbus TCP寄存器地址,从而允许Modbus TCP端一次性读取所有的设备的不同寄存…

基于AT89C51单片机的电子密码锁设计

点击链接获取Keil源码与Project Backups仿真图: https://download.csdn.net/download/qq_64505944/87848194?spm=1001.2014.3001.5503 源码获取 摘 要 随着经济社会发展,人们生活水平的提高,如何实现家庭防盗这一问题也变的尤其的突出。传统的机械锁,由于其构造简单,安…

手机卡停机三个月被自动注销,欠费需要补交吗?不交会影响征信?

经常换手机卡的朋友都会面临着这样的一个问题,手机卡欠费不用而且忘了注销,三个月过后自动注销了,这样就会面临着一个问题,欠费应该怎么处理,需要补交吗?如果不补交会影响个人征信吗? 官方解释是…