当前位置: 首页 > news >正文

衡阳网站建设公司哪家好手机优化是什么意思

衡阳网站建设公司哪家好,手机优化是什么意思,商水县建设局网站,wordpress 论坛整合http服务器的实现 本文使用上一篇博文实现的epollreactor百万并发的服务器实现了一个使用http协议和WebSocket协议的WebServer。 完整代码请看我的github项目 1. 水平触发(Level Trigger)与边沿触发(Edge Trigger) 1.1 水平触发 水平触发是一种状态驱动机制。当文件描述符&a…

http服务器的实现

本文使用上一篇博文实现的epoll+reactor百万并发的服务器实现了一个使用http协议和WebSocket协议的WebServer。

完整代码请看我的github项目

1. 水平触发(Level Trigger)与边沿触发(Edge Trigger)

1.1 水平触发

水平触发是一种状态驱动机制。当文件描述符(如套接字)处于可读或可写状态时,内核会持续通知应用程序,直到应用程序处理完所有数据或资源。

优点

  • 容易编写,通常可以简单处理,因为内核会持续通知应用程序事件。

  • 不容易丢失事件通知。

缺点

  • 对于高并发场景,水平触发可能会造成不必要的系统调用。因为即使数据或资源已经读取过,内核还是会通知文件描述符仍然处于可读/可写状态。

使用场景

  • 典型的阻塞式 I/O 使用水平触发较为合适。
  • 适用于那些可以容忍一定的事件重复通知的应用程序。
1.2 边沿触发

边沿触发是一种状态变化驱动机制。只有当文件描述符的状态从不可读/不可写到可读/可写时,内核才会通知应用程序。ET 只在状态变化的那一刻通知,不会持续通知。

优点

  • 触发次数更少,减少了系统调用开销,适合高性能、高并发场景。

缺点

  • 容易出现遗漏事件的情况。应用程序需要一次性读取或写入尽可能多的数据,以确保没有遗漏。
  • 实现更为复杂。

使用场景

  • 非阻塞IO通常配合边沿触发使用,以避免阻塞和提高性能。
  • 边沿触发适用于高并发、追求性能的场景。
  • 如果数据包大小变化较大,适合使用边沿触发。

2. httpserver

2.1 调整内核tcp缓冲区大小

在这里插入图片描述

如果文件块太大,而用户层buffer太小或者内核tcp缓冲区太小,会导致需要多次发送,从而导致发送速度变慢。

可以尝试扩大TCP缓冲区,在/etc/sysctl.conf中设置

net.ipv4.tcp_wmem = 8192 8192 16384
net.ipv4.tcp_rmem = 8192 8192 16384
2.2 IO层和协议层

IO层包含负责管理IO事件的epoll和进行事件处理的reactor。

协议层就是实现http请求处理和发送http响应的函数。

2.3 使用状态机保存连接状态信息

可以在连接中保存一个status字段,表示当前连接的状态,当status为0,表示还没有发送任何信息,为1表示已经发送了头部,正在发送文件块,为2表示已经全部发送完毕。

显然我们需要在status为1时,将整个文件分块发送,因此就需要保存该文件描述符的上下文信息。

2.4 分块发送大文件,保存被发送文件的上下文信息

大文件传输中显然不能一次性把整个文件读出,然后写入用户缓冲区,再写入内核缓冲区。我们需要把文件分块,利用水平触发分多次写入,这样就绪要在connection中保存当前文件描述符,在status为0时打开文件,在status为2时关闭文件。

2.5 可选择使用sendfile函数减少内存复制

senfile函数可以在两个文件描述符之间直接传输数据,数据流不需要经过用户空间。它利用mmap指令直接将文件内容读取到系统缓冲区,因此性能更好。

缺点是,由于不经过用户空间,无法对文件分块发送,在阻塞IO模式下发送大文件可能长时间陷入阻塞。在非阻塞IO模式下,尽管不会陷入阻塞,但会可能导致其他连接饥饿。

2.6 性能测试qps

wrk是一款针对 Http 协议的基准测试工具,它能够在单机多核 CPU 的条件下,使用系统自带的高性能 I/O 机制,如 epoll,kqueue 等,通过多线程和事件模式,对目标机器产生大量的负载。

下载wrk。

这篇文章详细介绍了如何安装和使用wrk进行性能测试。

特点

  • 轻量级,简单易用
  • 只用于单机压测

测试结果:

  1. 对于每个http请求都返回一个738KB大小的图片,测试结果如下:
(base) fyli@a431:~/programs/sockets/course1 network_programs$ wrk -t12 -c400 -d30s http://localhost:2000
Running 30s test @ http://localhost:200012 threads and 400 connectionsThread Stats   Avg      Stdev     Max   +/- StdevLatency    17.69ms   14.40ms   1.68s    99.92%Req/Sec   143.45    153.46   600.00     83.31%25494 requests in 30.10s, 17.80GB readSocket errors: connect 0, read 25499, write 0, timeout 1
Requests/sec:    847.08
Transfer/sec:    605.61MB

可以看到qps是847.08

  1. 对于每个http请求都返回一个600+字节的html文件,测试结果如下:
(base) fyli@a431:~/programs/sockets/course1 network_programs$ wrk -c400 -t12 -d30 http://localhost:2000
Running 30s test @ http://localhost:200012 threads and 400 connectionsThread Stats   Avg      Stdev     Max   +/- StdevLatency     2.72ms   33.82ms   1.79s    99.38%Req/Sec     1.62k     1.02k    6.07k    72.66%461290 requests in 30.09s, 318.94MB readSocket errors: connect 0, read 461294, write 0, timeout 21
Requests/sec:  15327.85
Transfer/sec:     10.60MB

可以看到因为数据传输量变少,qps上升到了15327

2.7 代码实现

这里只展现了协议层和业务层的代码,IO层和事件回调的底层代码请看完整项目reactor.c。

webserver.h

#pragma once#include <stdio.h>#define BUFFER_LENGTH 819200
#define CONNECTION_LENGTH 256
#define READY_LENFTH 1024
#define PORT_NUM 2typedef int (*RCallBack)(int fd);struct Conn
{int fd;char rbuffer[BUFFER_LENGTH];char wbuffer[BUFFER_LENGTH];int rlength;int wlength;RCallBack send_callback;RCallBack recv_callback;int status;int file_fd;
};int http_request(struct Conn *);
int http_response(struct Conn *);int set_event(int fd, int event, int flag);void error_handling(const char *message);void log_error(const char *message);

webserver.c

#include <fcntl.h>
#include <unistd.h>
#include <sys/epoll.h>
#include <sys/stat.h>
#include <sys/types.h>#include "webserver.h"int http_request(struct Conn *conn)
{set_event(conn->fd, EPOLLOUT, EPOLL_CTL_MOD);conn->status = 0;conn->wlength = 0;return 0;
}int http_response(struct Conn *conn)
{const char *file = "pic.png";int file_fd;if (conn->status == 0){file_fd = open(file, O_RDONLY);if (file_fd == -1){log_error("open() fails");return 1;}conn->file_fd = file_fd;}else{file_fd = conn->file_fd;}if (conn->status == 0){struct stat filestat = {0};fstat(file_fd, &filestat);int sended = snprintf(conn->wbuffer, BUFFER_LENGTH,"HTTP/1.1 200 OK\r\n""Content-Type: image/png\r\n""Accept-Ranges: bytes\r\n""Content-Length: %ld\r\n\r\n",filestat.st_size);conn->wlength = sended;conn->status = 1;}else if (conn->status == 1){ssize_t recved = read(file_fd, conn->wbuffer, BUFFER_LENGTH);if (recved == 0){close(file_fd);conn->status = 2;}if (recved < 0){close(file_fd);log_error("read() fails");conn->status = 2;}conn->wlength = recved;}return 0;
}

3. 可能出现的问题及解决

  1. connection reset

    recv()函数可能由于对端reset连接而返回-1,这是正常现象,关闭对应的fd即可。

  2. 服务器程序在客户端关闭后直接退出

    可能是由于服务器程序向已经被关闭的socket写数据时会接收到一个SIGPIPE,默认情况下没有设置该信号的处理函数的话,就会导致该进程直接被kill。

    • 可以设置忽略该信号。
    signal(SIGPIPE, SIG_IGN);
    
    • 也可以自定义信号处理函数
    struct sigaction sa;
    sa.sa_handler = handle_sigpipe;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;sigaction(SIGPIPE, &sa, NULL);  // 设置信号处理程序
    
    • 也可以在send函数参数中设置不发出信号
    send(fd, buffer, length, MSG_NOSIGNAL);
    

学习参考

学习更多请前往零声github。

http://www.wooajung.com/news/99.html

相关文章:

  • wordpress多语言建站淘宝美工培训
  • 简易app制作平台抖音seo优化系统招商
  • 自助建站网站建设智能建站abc
  • 公众号开发展模式下文章归类到菜单百度推广seo怎么学
  • 公司做网站合同邮件营销
  • 网站头部特效杭州上城区抖音seo如何
  • 襄樊和襄阳是一个地方吗seo关键词优化案例
  • 自己做网站怎么挣钱信息发布
  • 杭州外贸建站公司站长查询域名
  • 做惠而浦售后网站赚钱温州网站快速排名
  • 深圳做网站应该怎么做谷歌seo搜索引擎优化
  • 广州品牌网站建设 优美网站优化排名技巧
  • 工商局注册公司网站百度一下就知道了官网楯
  • 杭州网络公司网站建设哈尔滨百度推广联系人
  • wordpress 漫画站旺道seo软件技术
  • 网站常见问题是什么做销售记住这十句口诀
  • 网站建设美化中期报告百度竞价的优势和劣势
  • hao123网址下载到桌面seo关键词优化外包公司
  • 手工制作礼品盒可靠的网站优化
  • 上海网站开发工程师招聘网seo课程总结
  • 如何查看网站域名信息seo搜索引擎优化案例
  • python基础教程免费下载海城seo网站排名优化推广
  • 无版权图片网站 日本最新国内新闻10条
  • 建设政府网站的费用网络宣传渠道有哪些
  • 承德兴隆建设局网站凡科建站app
  • 河北网站建设排名最近的疫情情况最新消息
  • 做精神科医院网站费用seo排名优化点击软件有哪些
  • 长春建站优化百度怎么推广自己的作品
  • 阿里云免费网站备案好看的网页设计作品
  • 企业网络营销策划方案设计的例子seo网站有优化培训吗