http连接处理(下)(四)

2023-11-11

1.结合代码分析请求报文响应

下面我们将介绍服务器如何响应请求报文,并将该报文发送给浏览器端。首先介绍一些基础API,然后结合流程图和代码对服务器响应请求报文进行详解。

基础API部分,介绍stat、mmap、iovecwritev

流程图部分,描述服务器端响应请求报文的逻辑,各模块间的关系。

代码部分,结合代码对服务器响应请求报文进行详解。

1.1 基础API

为了更好的源码阅读体验,这里提前对代码中使用的一些API进行简要介绍,更丰富的用法可以自行查阅资料。

stat

stat函数用于取得指定文件的文件属性,并将文件属性存储在结构体stat里,这里仅对其中用到的成员进行介绍。

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

//获取文件属性,存储在statbuf中
int stat(const char *pathname, struct stat *statbuf);

struct stat 
{
   mode_t    st_mode;        /* 文件类型和权限 */
   off_t     st_size;        /* 文件大小,字节数*/
};

mmap

用于将一个文件或其他对象映射到内存,提高文件的访问速度。

void* mmap(void* start,size_t length,int prot,int flags,int fd,off_t offset);
int munmap(void* start,size_t length);
  1. start:映射区的开始地址,设置为0时表示由系统决定映射区的起始地址
  2. length:映射区的长度
  3. prot:期望的内存保护标志,不能与文件的打开模式冲突
    • PROT_READ 表示页内容可以被读取
  4. flags:指定映射对象的类型,映射选项和映射页是否可以共享
    • MAP_PRIVATE 建立一个写入时拷贝的私有映射,内存区域的写入不会影响到原文件
  5. fd:有效的文件描述符,一般是由open()函数返回
  1. off_toffset:被映射对象内容的起点

iovec

定义了一个向量元素,通常,这个结构用作一个多元素的数组。

struct iovec {
    void      *iov_base;      /* starting address of buffer */
    size_t    iov_len;        /* size of buffer */
};
  1. iov_base指向数据的地址
  2. iov_len表示数据的长度

writev

writev函数用于在一次函数调用中写多个非连续缓冲区,有时也将这该函数称为聚集写。

#include <sys/uio.h>
ssize_t writev(int filedes, const struct iovec *iov, int iovcnt);
  1. filedes表示文件描述符
  2. iov为前述io向量机制结构体iovec
  3. iovcnt为结构体的个数

若成功则返回已写的字节数,若出错则返回-1。

writev以顺序iov[0]iov[1]iov[iovcnt-1]从缓冲区中聚集输出数据。

writev返回输出的字节总数,通常,它应等于所有缓冲区长度之和。

特别注意: 循环调用writev时,需要重新处理iovec中的指针和长度,该函数不会对这两个成员做任何处理。writev的返回值为已写的字节数,但这个返回值“实用性”并不高,因为参数传入的是iovec数组,计量单位是iovcnt,而不是字节数,我们仍然需要通过遍历iovec来计算新的基址,另外写入数据的“结束点”可能位于一个iovec的中间某个位置,因此需要调整临界iovec的io_base和io_len。

1.2 流程图

浏览器端发出HTTP请求报文,服务器端接收该报文并调用process_read对其进行解析,根据解析结果HTTP_CODE,进入相应的逻辑和模块。

其中,服务器子线程完成报文的解析与响应;主线程监测读写事件,调用read_oncehttp_conn::write完成数据的读取与发送。

HTTP_CODE含义

表示HTTP请求的处理结果,在头文件中初始化了八种情形,在报文解析与响应中只用到了七种。

  1. NO_REQUEST
    • 请求不完整,需要继续读取请求报文数据
    • 跳转主线程继续监测读事件
  2. GET_REQUEST
    • 获得了完整的HTTP请求
    • 调用do_request完成请求资源映射
  3. NO_RESOURCE
    • 请求资源不存在
    • 跳转process_write完成响应报文
  4. BAD_REQUEST
    • HTTP请求报文有语法错误或请求资源为目录
    • 跳转process_write完成响应报文
  5. FORBIDDEN_REQUEST
    • 请求资源禁止访问,没有读取权限
    • 跳转process_write完成响应报文
  6. FILE_REQUEST
    • 请求资源可以正常访问
    • 跳转process_write完成响应报文
  7. INTERNAL_ERROR
    • 服务器内部错误,该结果在主状态机逻辑switch的default下,一般不会触发

1.3 代码分析

do_request

process_read函数的返回值是对请求的文件分析后的结果,一部分是语法错误导致的BAD_REQUEST,一部分是do_request的返回结果.该函数将网站根目录和url文件拼接,然后通过stat判断该文件属性。另外,为了提高访问速度,通过mmap进行映射,将普通文件映射到内存逻辑地址。

为了更好的理解请求资源的访问流程,这里对各种各页面跳转机制进行简要介绍。其中,浏览器网址栏中的字符,即url,可以将其抽象成ip:port/xxxxxx通过html文件的action属性进行设置。

m_url为请求报文中解析出的请求资源,以/开头,也就是xxx,项目中解析后的m_url有8种情况。

  1. /
    • GET请求,跳转到judge.html,即欢迎访问页面
  2. /0
    • POST请求,跳转到register.html,即注册页面
  3. /1
    • POST请求,跳转到log.html,即登录页面
  4. /2CGISQL.cgi
    • POST请求,进行登录校验
    • 验证成功跳转到welcome.html,即资源请求成功页面
    • 验证失败跳转到logError.html,即登录失败页面
  5. /3CGISQL.cgi
    • POST请求,进行注册校验
    • 注册成功跳转到log.html,即登录页面
    • 注册失败跳转到registerError.html,即注册失败页面
  6. /5
    • POST请求,跳转到picture.html,即图片请求页面
  7. /6
    • POST请求,跳转到video.html,即视频请求页面
  8. /7
    • POST请求,跳转到fans.html,即关注页面

如果大家对上述设置方式不理解,不用担心。具体的登录和注册校验功能会在第1下面进行详解,到时候还会针对html进行介绍。

//网站根目录,文件夹内存放请求的资源和跳转的html文件
const char* doc_root="/home/wfc/obj/MyWebserver/root";

http_conn::HTTP_CODE http_conn::do_request()
{
    //将初始化的m_real_file赋值为网站根目录
    strcpy(m_real_file,doc_root);
    int len=strlen(doc_root);

    //找到m_url中/的位置
    const char *p = strrchr(m_url, '/'); 

    //实现登录和注册校验
    if(cgi==1 && (*(p+1) == '2' || *(p+1) == '3'))
    {
        //根据标志判断是登录检测还是注册检测

        //同步线程登录校验

        //CGI多进程登录校验
    }

    //如果请求资源为/0,表示跳转注册界面
    if(*(p+1) == '0'){
        char *m_url_real = (char *)malloc(sizeof(char) * 200);
        strcpy(m_url_real,"/register.html");

        //将网站目录和/register.html进行拼接,更新到m_real_file中
        strncpy(m_real_file+len,m_url_real,strlen(m_url_real));

        free(m_url_real);
    }
    //如果请求资源为/1,表示跳转登录界面
    else if( *(p+1) == '1'){
        char *m_url_real = (char *)malloc(sizeof(char) * 200);
        strcpy(m_url_real,"/log.html");

        //将网站目录和/log.html进行拼接,更新到m_real_file中
        strncpy(m_real_file+len,m_url_real,strlen(m_url_real));

        free(m_url_real);
    }
    else
        //如果以上均不符合,即不是登录和注册,直接将url与网站目录拼接
        //这里的情况是welcome界面,请求服务器上的一个图片
        strncpy(m_real_file+len,m_url,FILENAME_LEN-len-1);

    //通过stat获取请求资源文件信息,成功则将信息更新到m_file_stat结构体
    //失败返回NO_RESOURCE状态,表示资源不存在
    if(stat(m_real_file,&m_file_stat)<0)
        return NO_RESOURCE;

    //判断文件的权限,是否可读,不可读则返回FORBIDDEN_REQUEST状态
    if(!(m_file_stat.st_mode&S_IROTH))
        return FORBIDDEN_REQUEST;
    //判断文件类型,如果是目录,则返回BAD_REQUEST,表示请求报文有误
    if(S_ISDIR(m_file_stat.st_mode))
        return BAD_REQUEST;

    //以只读方式获取文件描述符,通过mmap将该文件映射到内存中
    int fd=open(m_real_file,O_RDONLY);
    m_file_address=(char*)mmap(0,m_file_stat.st_size,PROT_READ,MAP_PRIVATE,fd,0);

    //避免文件描述符的浪费和占用
    close(fd);

    //表示请求文件存在,且可以访问
    return FILE_REQUEST;
}

process_write

根据do_request的返回状态,服务器子线程调用process_writem_write_buf中写入响应报文。

  1. add_status_line函数,添加状态行:http/1.1 状态码 状态消息
    • add_headers函数添加消息报头,内部调用add_content_length和add_linger函数
    • content-length记录响应报文长度,用于浏览器端判断服务器是否发送完数据
    • connection记录连接状态,用于告诉浏览器端保持长连接
  2. add_blank_line添加空行

上述涉及的5个函数,均是内部调用add_response函数更新m_write_idx指针和缓冲区m_write_buf中的内容。

bool http_conn::add_response(const char* format,...)
{
    //如果写入内容超出m_write_buf大小则报错
    if(m_write_idx>=WRITE_BUFFER_SIZE)
        return false;

    //定义可变参数列表
    va_list arg_list;

    //将变量arg_list初始化为传入参数
    va_start(arg_list,format);

    //将数据format从可变参数列表写入缓冲区写,返回写入数据的长度
    int len=vsnprintf(m_write_buf+m_write_idx,WRITE_BUFFER_SIZE-1-m_write_idx,format,arg_list);

    //如果写入的数据长度超过缓冲区剩余空间,则报错
    if(len>=(WRITE_BUFFER_SIZE-1-m_write_idx)){
        va_end(arg_list);
        return false;
    }

    //更新m_write_idx位置
    m_write_idx+=len;
    //清空可变参列表
    va_end(arg_list);

    return true;
}

//添加状态行
bool http_conn::add_status_line(int status,const char* title)
{
    return add_response("%s %d %s\r\n","HTTP/1.1",status,title);
}
//添加消息报头,具体的添加文本长度、连接状态和空行
bool http_conn::add_headers(int content_len)
{
    add_content_length(content_len);
    add_linger();
    add_blank_line();
}

//添加Content-Length,表示响应报文的长度
bool http_conn::add_content_length(int content_len)
{
    return add_response("Content-Length:%d\r\n",content_len);
}

//添加文本类型,这里是html
bool http_conn::add_content_type()
{
    return add_response("Content-Type:%s\r\n","text/html");
}

//添加连接状态,通知浏览器端是保持连接还是关闭
bool http_conn::add_linger()
{
    return add_response("Connection:%s\r\n",(m_linger==true)?"keep-alive":"close");
}
//添加空行
bool http_conn::add_blank_line()
{
    return add_response("%s","\r\n");
}

//添加文本content
bool http_conn::add_content(const char* content)
{
    return add_response("%s",content);
}

响应报文分为两种,一种是请求文件的存在,通过io向量机制iovec,声明两个iovec,第一个指向m_write_buf,第二个指向mmap的地址m_file_address;一种是请求出错,这时候只申请一个iovec,指向m_write_buf

  1. iovec是一个结构体,里面有两个元素,指针成员iov_base指向一个缓冲区,这个缓冲区是存放的是writev将要发送的数据。
  2. 成员iov_len表示实际写入的长度
bool http_conn::process_write(HTTP_CODE ret)
{
    switch(ret)
    {
        //内部错误,500
        case INTERNAL_ERROR:
        {
            //状态行
            add_status_line(500,error_500_title);
            //消息报头
            add_headers(strlen(error_500_form));
            if(!add_content(error_500_form))
                return false;
            break;
        }
        //报文语法有误,404
        case BAD_REQUEST:
        {
            add_status_line(404,error_404_title);
            add_headers(strlen(error_404_form));
            if(!add_content(error_404_form))
                return false;
            break;
        }
        //资源没有访问权限,403
        case FORBIDDEN_REQUEST:
        {
            add_status_line(403,error_403_title);
            add_headers(strlen(error_403_form));
            if(!add_content(error_403_form))
                return false;
            break;
        }
        //文件存在,200
        case FILE_REQUEST:
        {
            add_status_line(200,ok_200_title);
            //如果请求的资源存在
            if(m_file_stat.st_size!=0)
            {
                add_headers(m_file_stat.st_size);
                //第一个iovec指针指向响应报文缓冲区,长度指向m_write_idx
                m_iv[0].iov_base=m_write_buf;
                m_iv[0].iov_len=m_write_idx;
                //第二个iovec指针指向mmap返回的文件指针,长度指向文件大小
                m_iv[1].iov_base=m_file_address;
                m_iv[1].iov_len=m_file_stat.st_size;
                m_iv_count=2;
                //发送的全部数据为响应报文头部信息和文件大小
                bytes_to_send = m_write_idx + m_file_stat.st_size;
                return true;
            }
            else
            {
                //如果请求的资源大小为0,则返回空白html文件
                const char* ok_string="<html><body></body></html>";
                add_headers(strlen(ok_string));
                if(!add_content(ok_string))
                    return false;
            }
        }
        default:
            return false;
    }
    //除FILE_REQUEST状态外,其余状态只申请一个iovec,指向响应报文缓冲区
    m_iv[0].iov_base=m_write_buf;
    m_iv[0].iov_len=m_write_idx;
    m_iv_count=1;
    return true;
}

http_conn::write

服务器子线程调用process_write完成响应报文,随后注册epollout事件。服务器主线程检测写事件,并调用http_conn::write函数将响应报文发送给浏览器端。

该函数具体逻辑如下:

在生成响应报文时初始化byte_to_send,包括头部信息和文件数据大小。通过writev函数循环发送响应报文数据,根据返回值更新byte_have_send和iovec结构体的指针和长度,并判断响应报文整体是否发送成功。

  1. 若writev单次发送成功,更新byte_to_send和byte_have_send的大小,若响应报文整体发送成功,则取消mmap映射,并判断是否是长连接.
    • 长连接重置http类实例,注册读事件,不关闭连接,
    • 短连接直接关闭连接
  2. 若writev单次发送不成功,判断是否是写缓冲区满了。
    • 若不是因为缓冲区满了而失败,取消mmap映射,关闭连接
    • 若eagain则满了,更新iovec结构体的指针和长度,并注册写事件,等待下一次写事件触发(当写缓冲区从不可写变为可写,触发epollout),因此在此期间无法立即接收到同一用户的下一请求,但可以保证连接的完整性。
bool http_conn::write()
{
    int temp = 0;

    int newadd = 0;

    //若要发送的数据长度为0
    //表示响应报文为空,一般不会出现这种情况
    if(bytes_to_send==0)
    {
        modfd(m_epollfd,m_sockfd,EPOLLIN);
        init();
        return true;
    }

    while (1)
    {   
        //将响应报文的状态行、消息头、空行和响应正文发送给浏览器端
        temp=writev(m_sockfd,m_iv,m_iv_count);

        //正常发送,temp为发送的字节数
        if (temp > 0)
        {
            //更新已发送字节
            bytes_have_send += temp;
            //偏移文件iovec的指针
            newadd = bytes_have_send - m_write_idx;
        }
        if (temp <= -1)
        {
            //判断缓冲区是否满了
            if (errno == EAGAIN)
            {
                //第一个iovec头部信息的数据已发送完,发送第二个iovec数据
                if (bytes_have_send >= m_iv[0].iov_len)
                {
                    //不再继续发送头部信息
                    m_iv[0].iov_len = 0;
                    m_iv[1].iov_base = m_file_address + newadd;
                    m_iv[1].iov_len = bytes_to_send;
                }
                //继续发送第一个iovec头部信息的数据
                else
                {
                    m_iv[0].iov_base = m_write_buf + bytes_to_send;
                    m_iv[0].iov_len = m_iv[0].iov_len - bytes_have_send;
                }
                //重新注册写事件
                modfd(m_epollfd, m_sockfd, EPOLLOUT);
                return true;
            }
            //如果发送失败,但不是缓冲区问题,取消映射
            unmap();
            return false;
        }

        //更新已发送字节数
        bytes_to_send -= temp;

        //判断条件,数据已全部发送完
        if (bytes_to_send <= 0)
        {
            unmap();

            //在epoll树上重置EPOLLONESHOT事件
            modfd(m_epollfd,m_sockfd,EPOLLIN);

            //浏览器的请求为长连接
            if(m_linger)
            {
                //重新初始化HTTP对象
                init();
                return true;
            }
            else
            {
                return false;
            }
        }
    }
}

书中原代码的write函数不严谨,这里对其中的Bug进行了修复,可以正常传输大文件。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

http连接处理(下)(四) 的相关文章

  • 如何使用 python 的 http.client 准确读取一个响应块?

    Using http client在 Python 3 3 或任何其他内置 python HTTP 客户端库 中 如何一次读取一个分块 HTTP 响应一个 HTTP 块 我正在扩展现有的测试装置 使用 python 编写 http clie
  • WCF WebHttp 混合身份验证(基本和匿名)

    所有这些都与 WebHttp 绑定有关 托管在自定义服务主机中 IIS 目前不是一个选项 我已经实现了自定义 UserNamePasswordValidator 和自定义 IAuthorizationPolicy 当我将端点的绑定配置为使用
  • 最适合“正在进行的作业”的 HTTP 状态代码

    向客户端提供的最合适的 HTTP 状态代码是什么 表示 您的请求很好 但仍在进行中 请稍后在完全相同的位置回来查看 例如 假设客户端提交初始请求以启动繁重的查询 服务器立即返回一个 URL 客户端可以定期轮询该 URL 以获取结果 如果客户
  • 注册期间现有电子邮件的 422 或 409 状态代码

    我正在构建 RESTful API 遇到了一种情况 在用户注册期间 如果电子邮件已存在 则在422 and 409哪个http响应代码有意义 我浏览过类似的one https stackoverflow com questions 9269
  • 自定义 HTTP 标头:命名约定

    我们的一些用户要求我们将与其帐户相关的数据包含在HTTP 标头我们向他们发送的请求 甚至是他们从我们的 API 获得的响应 添加自定义 HTTP 标头的一般约定是什么 naming format etc 另外 请随意发布您在网络上偶然发现的
  • 如何将文件透明地传输到浏览器?

    受控环境 IE8 IIS 7 ColdFusion 当从 IE 发出指向媒体文件 例如 mp3 mpeg 等 的 GET 请求时 浏览器将启动关联的应用程序 Window Media Player 我猜测 IIS 提供文件的方式允许应用程序
  • 是否可以检测 http git 远程是智能还是愚蠢?

    我正在我的应用程序中实现一个选项来使用 depth 1制作 git repo 的最小功能克隆 我刚刚意识到愚蠢的 http 传输不支持 depth 我想自动检测 http 远程是愚蠢的还是聪明的 这样我就可以省略 depth与哑 http
  • Android httpclient文件上传数据损坏和超时问题

    我在 Android 中上传图像时遇到问题 我正在使用 apache httpmime 4 1 lib 代码是这样的 MultipartEntity reqEntity new MultipartEntity HttpMultipartMo
  • 流星图像、CSS、“普通”Web 服务

    我经常看到这个问题出现 如何在我的 Meteor 网站上放置图像 如何使用 Meteor 托管 标准 网页内容 我尝试添加一个 img src img myimage png 标签但没有图像显示 如何在 Meteor 站点上托管一些文件 将
  • C# HTTP 请求解析器[重复]

    这个问题在这里已经有答案了 可能的重复 将原始 HTTP 请求转换为 HTTPWebRequest 对象 https stackoverflow com questions 318506 converting raw http reques
  • 如何在c++中使用libcurl发送POST请求并接收它?

    我正在使用 c libcurl 向网页发送 POST 请求 但我正在努力测试它 使用的代码是 include
  • Apache HttpClient TCP Keep-Alive(套接字保持活动)

    我的 http 请求需要太多时间才能被服务器处理 大约 5 分钟 由于连接闲置 5 分钟 代理服务器将关闭连接 我正在尝试在 Apache DefaultHttpClient 中使用 TCP Keep Alive 来使连接长时间处于活动状态
  • Rails api 中阻止用户配置文件的最佳 HTTP 状态代码是什么?

    我在 Rails 中为社交应用程序编写了一个 API 这个应用程序就像Facebook一样 用户可以阻止其他用户 如果用户 A 阻止用户 B 则用户 B 无法查看用户 A 的个人资料页面 那么我应该返回的最佳 HTTP 代码状态是什么 40
  • ASP.NET - 将所有 https 请求重写为 http

    我的问题正是所提出的问题here https stackoverflow com questions 16276860 iis 7 adding ssl to one site all other sites responds to htt
  • 哪些具体用例需要通过 WebSockets 和长轮询使用 BOSH? [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • Rest 和 Http 中“无状态”的含义

    当我阅读有关 REST 是什么的文档时 他们总是说 REST api 应该是无状态的 在这里 我感觉有点尴尬 因为普通的 HTTP 也是无状态的 既然REST可以说是一种使用HTTP协议的特殊架构 那么说REST应该是无状态的似乎是多余的
  • 如何找出数据包的HTTP头长度?

    我知道如何手动执行此操作 通过查看十六进制转储 我怎样才能自动获得相同的信息 我必须使用 API 吗 我有wireshark 和Microsoft 网络监视器 这可以通过简单地实现Lua解析器 http wiki wireshark org
  • 使用:text/plain; 有什么缺点吗?字符集=“UTF-8”

    我的网络服务器提供的内容在 95 的情况下只是简单的 ascii 但在极少数情况下 内容包含一些德语非 ASCII 字符 现在我可以设置content type通过检测内容是否包含任何非 ASCII 字符来响应标头 或者我可以始终设置响应标
  • 使用 POST 请求向 Jira API 发送 JSON 时出现 System.Net.WebException

    好吧 伙计们 我已经为这个问题苦苦挣扎了一天左右 但没有明确的解决方案 我将从例外开始 The remote server returned an error NotFound at System Net Browser AsyncHelp
  • Response.Redirect 并不总是重定向

    我们在一个工作不一致的页面上有一个简单的 Response Redirect IIS 6 0 大多数情况下 它会正确重定向 但我们收到一些用户抱怨 他们没有重定向 而是看到 302 对象移至此处 页面 该页面显示标题信息以及正确的位置 如果

随机推荐

  • springboot框架介绍,让我们深入的了解

    Spring Boot是一种用于快速构建基于Spring框架的Java应用程序的开源框架 它旨在简化Spring应用程序的开发过程 通过提供一种约定优于配置的方式 让开发人员能够快速搭建起一个可独立运行的 可部署的 易于扩展的应用 Spri
  • Java的内存机制

    1 Java的内存机制 Java 把内存划分成两种 一种是栈内存 另一种是堆内存 在函数中定义的一些基本类型的变量和对象的引用变量都是在函数的栈内存中分配 当在一段代码块定义一个变量时 Java 就在栈中为这个变量分配内存空间 当超过变量的
  • 虚拟化一、虚拟化技术基础原理

    一 虚拟化 虚拟化 是指通过虚拟化技术将一台计算机虚拟为多台逻辑计算机 在一台计算机上同时运行多个逻辑计算机 每个逻辑计算机可运行不同的操作系统 并且应用程序都可以在相互独立的空间内运行而互不影响 从而显著提高计算机的工作效率 虚拟化使用软
  • java字符串转json

    针对不同jar包 一 import org json JSONObject JSONObject jo new JSONObject new String 需要转换的字符串 二 import com alibaba fastjson JSO
  • 巧用机器学习定位云服务器故障

    欢迎大家前往腾讯云 社区 获取更多腾讯海量技术实践干货哦 本文由roganhuang 发表于云 社区专栏 导语 随着腾讯云业务的扩大 母机数量越来越多 为减少人力并实现母机故障的自动化定位 本文尝试利用机器学习算法 通过对历史故障母机的日志
  • 在钉钉上怎么手写_钉钉群上课入门和独家进阶功能(图文)

    钉钉群上课入门和独家快速进阶 在钉钉上有两种视频连接方式 直播和视频会议 两者各有利弊 前者合适人数较多 超过两百人 的时候进行 后者适合一个班级进行上课 下面就两者之间的具体操作说明 文中图片皆可点击放大 一 直播 手机 只有手机怎么直播
  • mysql的连接路径_Mysql 连接路径 url 参数解析

    1 mysql url 参数解析 url jdbc mysql 127 0 0 1 3306 user useUnicode true characterEncoding utf8 useUnicode characterEncoding
  • Webpack构建多页应用Mpa(三):文件结构和自动化打包

    本系列教程整体完成后 会完成一个可用的MPA应用 教程实际就是整个MPA的实现过程的记录 如果是想了解单项功能的实现 请继续往下看 如果是想了解整个MPA的开发和思考过程 建议从 Webpack构建多页应用Mpa 一 阐述设计概要 教程开始
  • 方法:sorttable.js用法

    转至 用sorttable js对表格进行排序 对表格进行排序的实现步骤 第一 下载sorttable js 链接 http www kryogenix org code browser sorttable 不需要jquery js 第二
  • castep 编译安装说明

    科学计算软件编译安装方法说明 castep 篇 提供免费TEST QQ 178068275 1 什么是 castep CASTEP Cambridge Sequential Total Energy Package 的缩写 是一个基于密度泛
  • CNN,RNN,LSTM,GRU的前后向传播算法(梯度是怎么更新的)

    目录 1 简单的梯度计算 2 进阶的梯度计算 3 CNN前向后向算法 4 RNN前向后向算法
  • JavaFx中的Image和ImageView

    image 要转换成ImageView 对象才可以添加到结点中 Override public void start Stage stage stage setTitle 测试窗口 Pane pane new Pane Scene scen
  • 打表法经典2题:小于n的质数和第k个丑数

    1 求小于n的所有质数 1 开一个大小为n的bool数组A 下标代表整数 值true代表被mark过 有因子 非素数 2 i 从 2开始到n 1 如果A i 没被mark A i 就是质数 然后mark有A i 因子的数 2 A i 3 A
  • sed命令详解

    http www cnblogs com edwardlost archive 2010 09 17 1829145 htm 1 简介 sed是非交互式的编辑器 它不会修改文件 除非使用shell重定向来保存结果 默认情况下 所有的输出行都
  • MongoDB的基本使用

    基本操作 mongod f mongodb conf 启动mongodb mongo 进入到mongodb控制台 db shutdownServer 关闭服务 user admin db createUser user root pwd r
  • 怎么区分静态网页和动态网页

    在建设网站时 会经常听到静态网页和动态网页 但是他们真正的区别是什么 接下来仔细分析下二者的区别 静态网页是网站建设的基础 静态网页和动态网页之间也并不矛盾 为了网站适应搜索引擎检索的需要 即使采用动态网站技术 也可以将网页内容转化为静态网
  • Response.setContentType对应的类型大全

    Response setContentType MIME 的作用是时客户端的浏览器区分不同种类的数据 并根据不同的MIME调用浏览器内不同的程序嵌入模块来处理相应的数据 MIME的作用 由于MIME类型与文档的后缀相关 因此服务器使用文档的
  • MySQl心得4--5--数据库视图

    1 修改 查询 删除记录时都会提示多少条记录被影响 但建表不会提示 当表的数据修改后反映到视图 修改 查询 删除视图的命令跟建表时的一样 视图是从一个或多个表 或视图 导出的表 视图是数据库的用户使用数据库的观点 可以根据他们的不同需求 在
  • Jmeter做接口测试-面试题

    一 请说明你用Jmeter做接口测试的整体过程 用Jmeter做接口测试 至少要经过以下几步 1 根据开发提供的接口文档 编写接口测试用例 2 利用JMeter做接口测试 添加线程组和HTTP请求 在HTTP请求中 添加对应的ip地址 端口
  • http连接处理(下)(四)

    1 结合代码分析请求报文响应 下面我们将介绍服务器如何响应请求报文 并将该报文发送给浏览器端 首先介绍一些基础API 然后结合流程图和代码对服务器响应请求报文进行详解 基础API部分 介绍stat mmap iovec writev 流程图