【网络编程】一文详解http协议(超文本传输协议)

news2024/12/27 12:18:34


 目录

一、http协议

1、http协议的介绍

2、URL的组成

3、urlencode和urldecode

二、http的请求方法、状态码及状态码描述、常见的响应报头

1、http请求方法

2、http状态码及状态码描述 

3、http常见的响应报头

三、http协议客户端和服务器的通信过程

1、如何保证请求和响应被应用层完整的读取了?

2、请求和响应如何做到序列化和反序列化

3、客户端和服务器通信的全过程 

4、获取响应正文的长度

四、http长连接

五、http会话保持(客户端Cookie,服务器session)

六、http相关工具


本文http协议详细代码可参照博主gitee。

一、http协议

1、http协议的介绍

        http属于应用层协议。虽然应用层协议是程序员自己定的,但实际上, 已经有前辈们定义了一些现成的, 又非常好用的应用层协议, 供我们参考使用。 http(超文本传输协议) 就是其中之一,这个协议就是用户从服务器拿视频、图片等文件资源的一种协议。(这些资源存放在服务器的磁盘上)

2、URL的组成

        平时我们俗称的 "网址" 其实就是说的 URL。

        ip会标识一台网络主机,看到"/"就知道这台网络主机用的是Linux系统。使用url就可以通过浏览器请求这台网络主机的服务器,从指定的文件路径下找到用户请求的文件返回给用户。

3、urlencode和urldecode

        像 / + : ?等字符, 已经被url特殊处理了。比如, 某个参数中需要带有这些特殊字符, 就必须先对特殊字符进行转义.

        转义的规则如下:取出字符的ASCII码,转成16进制,然后前面加上百分号即可。编码成%XY格式。服务器收到url请求,将会对%XY进行解码,该过程称为decode,如果哪天需要解码了,网上搜一下就行,这不是很重要的东西。

        "+" 被转义成了 "%2B"。urldecode就是urlencode的逆过程。

二、http的请求方法、状态码及状态码描述、常见的响应报头

1、http请求方法

请求方法

说明

支持的http协议版本

GET

获取资源

1.0/1.1

POST

传输实体主体

1.0/1.1

其他方法不常用,略。

        GET和POST方法提交参数的区别

        客户端进行数据提交时,是通过前端的from表单提交的,浏览器会将from表单中的内容转换为GET/POST方法。

1、GET方法通过URL传递参数。例如http://ip:port/XXX/YY?key1=value1&key2=value2。像百度的搜索就是用的GET方法。GET方法通过url传递参数,参数注定不能太大,例如上传视频等巨长的二进制文件就不适合用GET了。

2、POST提交参数通过http请求正文提交参数。请求正文可以很大,可以提交视频等巨长的文件。

3、POST方法提交参数,用户是看不到的,私密性更高,而GET方法不私密。私密性不等于安全性,POST方法和GET方法其实都不安全!(http请求都是可以被抓到的,想要安全必须加密,使用https协议)

        注意:如果用的是GET方法,需要对url进行额外的处理,例如/test.py?key1=value1&key2=value2,需要拆解出其中的路径(_path),即"test.py"。问号右侧则是参数(_parm)。

if(req._path=="test.py")
{
    //建立进程间通信,pipe
    //fork创建子进程,execl("/bin/python",test.py)进行进程程序替换
    //父进程,将req._parm通过管道写给某些后端语言,例如py、java、php等
    //....
    return true;
}

2、http状态码及状态码描述 

HTTP状态码是由服务器返回给客户端的三位数字代码,用于表示客户端请求的处理状态。以下是常见的HTTP状态码及其描述:

1xx(信息性状态码):表示请求已被接收,继续处理。

2xx(成功状态码):表示请求已成功被服务器接收、理解、并接受。

  • 200 OK:请求成功。
  • 201 Created:请求已经被实现,资源已经被创建。
  • 204 No Content:请求成功,但响应报文不含实体的主体部分。

3xx(重定向状态码):客户端发送请求,服务器返回3XX状态码和一个新的URL,客户端拿着这个新的URL再次请求服务器,这就是重定向。

  • 301 Moved Permanently:永久性重定向。
  • 302 Found:临时性重定向。
  • 304 Not Modified:客户端已经执行了GET,但文件未变化。
  • 307 Temporary Redirect:临时性重定向。

4xx(客户端错误状态码):表示客户端请求出错,服务器无法处理请求。

  • 400 Bad Request:请求报文存在语法错误。
  • 401 Unauthorized:未经授权,需要身份验证。
  • 403 Forbidden:服务器拒绝请求。
  • 404 Not Found:服务器无法找到请求的资源。(属于客户端错误,客户端请求资源在服务器不存在)

5xx(服务器错误状态码):表示服务器处理请求出错。

  • 500 Internal Server Error:服务器内部错误。
  • 502 Bad Gateway:网关错误。
  • 503 Service Unavailable:服务器暂时无法处理请求。
  • 504 Gateway Timeout:网关超时。

以307状态码为例,临时重定向至CSDN首页:

std::string respLine="HTTP/1.1 307 Temporary Redirect\r\n";//重定向,配合"Location: "使用
//响应报头
std::string respHeader=suffdeixDesc(req._suffix);//将后缀转换为对应的响应报头
if(req._size>0)
{
    respHeader+="Content-Length: ";
    respHeader+=std::to_string(req._size);
    respHeader+="\r\n";
}
respHeader+="Location: https://www.csdn.net/\r\n";

3、http常见的响应报头

HTTP协议常见的响应报头包括:

  • Content-Type:指定响应体的MIME类型,例如text/html表示HTML文本,image/jpeg表示JPEG图片等。
  • Content-Length:指定响应体的长度,单位为字节。
  • Cache-Control:指定缓存控制策略,例如no-cache表示不缓存,max-age=3600表示缓存1小时等。
  • Expires:指定响应过期时间,通常与Cache-Control一起使用。
  • Last-Modified:指定资源的最后修改时间,用于协商缓存。
  • ETag:指定资源的唯一标识符,用于协商缓存。
  • Location:搭配3XX状态码使用,指定重定向的目标URL。
  • Set-Cookie:指定响应中的Cookie信息。
  • Server:指定服务器软件的名称和版本号。
  • X-Powered-By:指定服务器使用的编程语言和框架。

三、http协议客户端和服务器的通信过程

        以个人云服务器作服务器,浏览器作客户端,服务器打印客户端请求如图:

        这个http请求可以看到请求的设备信息,如果在手机端浏览器搜索“微信下载”,浏览器将会返回手机版的微信下载网页,若在电脑浏览器搜索,将会返回电脑版的微信下载网页。

        以个人云服务器作服务器,浏览器作客户端,服务器的响应格式:

        Content-Type: text/html\r\n用于指示所传输的数据是HTML格式的文本。注意响应报头位置不要打成test了,这些都是设定好的,如果输错了,浏览器请求服务器时,会变成下载html文件!同样的,图片的响应报头写错了,当客户端请求图片时,同样会变成下载逻辑。

1、如何保证请求和响应被应用层完整的读取了?

1、可以读取完整的一行

2、while循环读取行,将所有的请求行和请求报头全部读完,直到遇到空行

3、我们可以保证把请求行和请求报头读完,报头中有Content-Length:XXX(正文长度)

4、通过Content-Length所示的长度,读取对应长度的正文即可。

        一个用户看到的网页结果,可能由多个资源组合而成,所以要获取一张完整的网页效果,浏览器会发起多次http请求。所以需要根据客户端的请求信息,在服务器设置好不同的状态行和响应报头。

2、请求和响应如何做到序列化和反序列化

1、http不用关注json等序列化和反序列化工具,直接发送即可。服务器解析客户端的请求,获取其中的信息填充至响应缓冲区。服务器通过响应报头的方式返回请求的参数,在响应正文中返回请求的资源。

2、对于正文部分,如果需要的话,可以设计自定义序列化与反序列化方案。

3、客户端和服务器通信的全过程 

void HandlerHttp(int sock)
{
    //1、读取完整的http请求
    char buffer[4096];
    HttpRequest req;
    HttpResponse resp;
    size_t n=recv(sock,buffer,sizeof(buffer)-1,0);//读取套接字中的内容
    if(n>0)
    {
        buffer[n]=0;//添加'\0'
        req._inBuffer=buffer;//获得序列化请求
        //2、对客户端请求进行反序列化
        //从客户端请求中解析获得请求行(请求方法、请求url、http版本)、请求资源的后缀、请求资源的大小
        req.Parse();//对请求进行解析
        //3、回调_func方法,由http请求获得http响应  _func(req,resp)
        //4、对http响应resp进行序列化
        _func(req,resp);
        //funcs[req._path](req,resp);
        send(sock,resp._outBuffer.c_str(),resp._outBuffer.size(),0);//5、send发送
    }
}

步骤2反序列化:解析请求行,从url中获取请求的资源路径并计算资源的大小等。

void Parse()//从客户端请求中解析获得请求行(请求方法、请求url、http版本)、请求资源的后缀、请求资源的大小
{
    //1、从请求结构体中的_inbuffer中拿到请求行(第一行),分隔符\r\n
    std::string line=Util::getOneLine(_inBuffer,sep);
    if(line.empty()){return;}
    //2、从请求行中获取三个字段:请求方法、请求url、请求版本
    //std::cout<<"line:"<<line<<std::endl;
    std::stringstream ss(line);
    ss>>_method>>_url>>_httpVersion;//以空格为分割读取其中的字段
    //2.1如果是GET方法,需要对_url进行额外处理
    ///search?name=jiang&pwd=123通过?对GET方法进行左右分离(POST本来就是分离的没有问号)
    //左边是PATH,右边是_parm

    //3、添加web默认路径
    _path=defaultRoot;//客户端所有请求路径前都会被加上./wwwroot前导目录字符串
    _path+=_url;//如果客户端请求a/b/c.html,则会请求./wwwroot/a/b/c.html
    if(_path[_path.size()-1]=='/')//如果请求的是web根目录(./wwwroot/),就让它访问设定好的默认首页的路径(./wwwroot/index.html)
    {
        _path+=homePage;
    }
    //4、获取path对应的资源后缀
    //./wwwroot/index.html
    //./wwwroot/test/a.html
    //./wwwroot/test/b.html
    //./wwwroot/image/dog.jpg
    auto pos=_path.rfind(".");
    if(pos==std::string::npos){_suffix=".html";}//实在找不到,先给个html
    else{_suffix=_path.substr(pos);}
    //5、得到响应正文的大小(客户端请求资源的大小)
    struct stat st;
    int n=stat(_path.c_str(),&st);
    if(0==n)
    {
        _size=st.st_size;
    }
    else{_size=-1;}
}

步骤3、4,由客户端请求转换为客户端响应(设置一下不同响应方法的状态行、响应报头、响应正文等信息,这里的响应正文是html和图片)

bool Get(const HttpRequest& req,HttpResponse& resp)
{
    // if(req._path=="test.py")
    // {
    //     //建立进程间通信,pipe
    //     //fork创建子进程,execl("/bin/python",test.py)进行进程程序替换
    //     //父进程,将req._parm通过管道写给某些后端语言,例如py、java、php等
    //     //....
    //     return true;
    // }
    // if(req._path=="/search")
    // {
    //     //如果PATH是"/search",可以在这里写具体的C++方法,提供相应的服务
    //     //....
    //     return true;
    // }
    //打印客户端的请求的一些信息
    std::cout<<"-----------httpStart------------"<<std::endl;
    std::cout<<req._inBuffer<<std::endl;
    std::cout<<"method:"<<req._method<<std::endl;
    std::cout<<"url:"<<req._url<<std::endl;
    std::cout<<"httpVersion:"<<req._httpVersion<<std::endl;
    std::cout<<"path:"<<req._path<<std::endl;
    std::cout<<"suffix:"<<req._suffix<<std::endl;
    std::cout<<"size:"<<req._size<<"字节"<<std::endl;
    std::cout<<"-----------httpEnd--------------"<<std::endl;
    //服务器的状态行、响应报头、空行、响应正文等信息
    //状态行
    std::string respLine="HTTP/1.1 200 OK\r\n";
    //std::string respLine="HTTP/1.1 307 Temporary Redirect\r\n";//重定向,配合"Location: "使用
    //响应报头
    std::string respHeader=suffdeixDesc(req._suffix);//将后缀转换为对应的响应报头
    if(req._size>0)
    {
        respHeader+="Content-Length: ";
        respHeader+=std::to_string(req._size+1);//为了和后面的body.size()大小匹配
        respHeader+="\r\n";
    }
    //respHeader+="Location: https://www.csdn.net/\r\n";
    //写入Cookie
    respHeader+="Set-Cookie: name=12345abcde;Max-Age=120\r\n";//设置Cookie响应报头
    //往后,每次http请求都会自动携带曾经设置的所有Cookie,帮助服务器的鉴权行为
    //空行
    std::string respBlack="\r\n";
    std::string body;
    body.resize(req._size+1);
    if(!Util::readFile(req._path,(char*)body.c_str(),req._size))//将_path路径下的文件内容读到buffer里
    {
        Util::readFile(html_404,(char*)body.c_str(),req._size);//访问的资源不存在,body的路径就是404html的路径
        respLine="HTTP/1.1 404 Not Found\r\n";//同时,状态行修改为404
    }
    std::cout<<"-----------httpStart------------"<<std::endl;
    std::cout<<(respLine+respHeader+respBlack)<<std::endl;
    std::cout<<"-----------httpEnd--------------"<<std::endl;
    resp._outBuffer=respLine+respHeader+respBlack+body;
    return true;
}

4、获取响应正文的长度

STAT(2)  
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int stat(const char *path, struct stat *buf);
int fstat(int fd, struct stat *buf);
int lstat(const char *path, struct stat *buf);
struct stat {
    dev_t     st_dev;         // 包含文件的设备ID 
    ino_t     st_ino;         // inode号 
    mode_t    st_mode;        // 文件保护模式 
    nlink_t   st_nlink;       // 硬链接数 
    uid_t     st_uid;         // 文件所有者的用户ID 
    gid_t     st_gid;         // 文件所有者的组ID 
    dev_t     st_rdev;        // 设备ID(如果是特殊文件) 
    off_t     st_size;        // 总大小,以字节为单位
    blksize_t st_blksize;     // 文件系统I/O的块大小 
    blkcnt_t  st_blocks;      // 分配的512B块数 
    time_t    st_atime;       // 上次访问时间 
    time_t    st_mtime;       // 上次修改时间 
    time_t    st_ctime;       // 上次状态更改时间 
};

用途:函数stat用于获取文件的状态信息,包括文件类型、文件大小、文件权限等。函数stat只能获取普通文件、目录、符号链接等文件的状态信息,无法获取设备文件等特殊文件的状态信息。

参数:

  • path:文件路径
  • buf:存储文件状态信息的结构体指针

返回值:函数返回值为0表示成功,-1表示失败。

得到_path路径下的文件大小,单位字节:

struct stat st;
int n=stat(_path.c_str(),&st);
if(0==n)
{
	_size=st.st_size;
}
else{_size=-1;}

四、http长连接

        http请求是基于tcp协议的,而tcp是需要进行连接的。对于一个网页,可能包含多种元素,则需要发起多次连接。为了减少连接次数,需要客户端和服务器均支持长链接,建立一条连接,传输一份大的资源通过一条连接完成。

Connection: keep-alive
Connection: close

        如果报头的"Connection: "显示是"keep-alive",则代表支持长连接。

五、http会话保持(客户端Cookie,服务器session)

        例如我们打开哔哩哔哩的首页进行登录操作,哪怕用户马上把浏览器关了,短期内再次访问哔哩哔哩是不需要用户重复登录操作的。同样的,当我们在哔哩哔哩进行页面跳转时,http协议并不会记录用户信息,但是曾经的用户登录信息在页面跳转时并不会丢失。浏览器仍会记住上一次登录的信息。这就是会话保持。

        其实http请求是无状态的,每次请求并不会记录它曾经请求了什么。所以会话保持不是http协议天然具备的特点,而是浏览器为了满足用户的使用需求,做了相应的工作。

        用户在第一次输入账号和密码时,浏览器会进行保存(Cookie),近期再次访问同一个网站,浏览器会自动将用户信息推送给服务器。像哔哩哔哩中某些需要大会员才能观看的视频,服务器都会先获取用户信息进行身份判断,用的就是浏览器缓存的信息。这样只要用户首次输入密码,一段时间内将不用再做登录操作了。

        但是本地的Cookie如果被不法分子拿到,那不是危险了,所以信息的保存是在服务器上完成的,服务器会对每个用户创建一份独有的session id,并将其返回给浏览器,浏览器存到Cookie的其实是session id。但这样只能保证原始的账号密码不会被泄漏,黑客盗取了用户的session id后仍可以非法登录,只能靠服务端的安全策略保障安全,例如账号被异地登录了,服务端察觉后只要让session id失效即可,这样异地登录将会使用户重新验证账号密码或手机或人脸信息(尽可能确保是本人),一定程度上保障了信息的安全。

服务器向客户端返回Cookie:

//写入Cookie
respHeader+="Set-Cookie: name=12345abcde; Max-Age=120\r\n";//设置Cookie响应报头,有效期2分钟
//往后,每次http请求都会自动携带曾经设置的所有Cookie,帮助服务器的鉴权行为————http会话保持

六、http相关工具

1、postman——能够模拟客户端浏览器的行为。

2、fiddler——一个本地抓包工具,作为http调试使用。(能够明文抓到本地的POST方法请求正文!)

所以http协议并不安全,想要安全还得看https协议......

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

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

相关文章

驱动LSM6DS3TR-C实现高效运动检测与数据采集(2)----配置滤波器

工作模式 在LSM6DS3TR-C中&#xff0c;加速度计和陀螺仪可以独立地开启/关闭&#xff0c;并且可以拥有不同的ODR和功耗模式。 LSM6DS3TR-C有三种可用的操作模式&#xff1a; ● 仅加速度计活动&#xff0c;陀螺仪处于断电状态 ● 仅陀螺仪活动&#xff0c;加速度计处于断电状态…

chatgpt赋能python:Python中0.2+0.1的问题解决方案

Python中0.20.1的问题解决方案 在Python中&#xff0c;0.20.1的结果并非等于0.3。这是由于计算机在二进制中存储小数时会存在精度问题导致的。而这个问题在日常编程中可能并不会带来太大的影响&#xff0c;但在需要精确计算的场景下&#xff0c;如金融或科学领域&#xff0c;就…

第 2 章:Vue 组件化编程

目录 模块与组件、模块化与组件化 模块 组件 模块化 组件化 非单文件组件 小结 组件的几个注意点 组件的嵌套 VueComponent构造函数 小结 一个重要的内置关系 小结 单文件组件 一个.vue 文件的组成(3 个部分) 1. 模板页面 2. JS 模块对象 3. 样式 基本使用 模…

chatgpt赋能python:Python中4+5的结果是多少?

Python中45的结果是多少&#xff1f; Python是一种高级的编程语言&#xff0c;由它所支持的各种库和框架&#xff0c;可以对不同的业务场景进行快速、高效的处理。在Python中&#xff0c;基本的运算符包括加、减、乘、除等&#xff0c;其中加操作是一个非常基本的操作&#xf…

chatgpt赋能python:Python中isin函数的使用方法

Python中isin函数的使用方法 Python是一种流行的编程语言&#xff0c;被广泛使用于数据分析、Web应用程序和游戏开发等领域。其中&#xff0c;Python的算法和数据结构库为程序员提供了实用的工具&#xff0c;使得数据的筛选、排序和搜索操作更加简易。Python之中的isin函数&am…

浅尝RTSP

RTSP (real time streaming protocol) RTC2326 RTSP 实时流传输协议,是TCP/IP 协议体系中的一个应用层协议,由哥伦比亚大学, 网景和realnetworks公司提交的IETF RTC 标准&#xff0c;该协议定义了一对多应用程序如何有效地通过IP网络传送多媒体数据。 RTSP在体系结构上位于 rtp…

二分搜索树层序遍历

二分搜索树的层序遍历&#xff0c;即逐层进行遍历&#xff0c;即将每层的节点存在队列当中&#xff0c;然后进行出队&#xff08;取出节点&#xff09;和入队&#xff08;存入下一层的节点&#xff09;的操作&#xff0c;以此达到遍历的目的。 通过引入一个队列来支撑层序遍历…

【SpringBoot】整合Mybatis-Plus并输出SQL日志

目录 本地开发环境说明pom.xml主要依赖application.yml主要配置MapperScan注解使用说明实体类示例Mapper接口示例Service接口示例Service接口实现类示例单元测试示例打印SQL日志使用slf4j打印SQL 总结 本地开发环境说明 开发依赖版本Spring Boot3.0.6Mybatis-Plus3.5.3.1JDK20…

git客户端的使用

1. git 分布式版本控制工具。 具有中央服务器仓库和本地仓库。 客户端下载&#xff1a;GitHub Desktop | Simple collaboration from your desktop 2. git的使用 2.1 修改操作本地仓库的用户信息 2.2 创建本地仓库 左上角&#xff1a;File - New repository 本地的两个仓库…

chatgpt赋能python:Python中4.5/2:浮点数除法的谬误

Python中4.5/2&#xff1a;浮点数除法的谬误 在Python中&#xff0c;当我们尝试对两个整数进行除法运算时&#xff0c;通常可以得到预期的正确结果。但是&#xff0c;当我们的被除数或者除数是浮点数时&#xff0c;可能会遇到令人疑惑的结果。 例如&#xff0c;执行4.5/2的计…

chatgpt赋能python:Python中Delete的用法及其重要性

Python中Delete的用法及其重要性 Python是一种强大的编程语言&#xff0c;它提供了许多强大的工具和API&#xff0c;帮助程序员轻松编写高效的代码。其中&#xff0c;Delete是Python语言中一个非常重要的关键字&#xff0c;用于删除对象和变量。 Delete的用法 Delete作为Pyt…

chatgpt赋能python:Python中IDLE怎么执行代码

Python中IDLE怎么执行代码 介绍 作为一种非常流行的编程语言&#xff0c;Python可以编写各种应用程序&#xff0c;从自动化脚本到网站后端。无论您是一个新手还是一个经验丰富的程序员&#xff0c;您都可能会使用Python编程语言来完成您的工作。 一个好的Python IDE可以大大…

sql的各种排序(order by加asc或者desc、order by加field()加asc或者desc)

sql的各种排序&#xff08;order by加asc或者desc、order by加field()加asc或者desc&#xff09; 1.单字段排序&#xff1b; 【order by】排序&#xff1a;order by后面跟着的字段就是数据的排序字段&#xff1b; &#xff08;1&#xff09;升序排序&#xff1b; 举例&#x…

c++—封装:构造函数、析构函数、成员操作

1. 封装的主要目的是解决代码的维护性问题&#xff0c;经过封装的函数代码独立性高&#xff1b; 2. 封装的演变历史&#xff0c;以栈为例子介绍&#xff1a; ①成员&#xff08;top、data[ ]&#xff09;都在main函数里&#xff0c;动作方法&#xff08;push、pop&#xff09;…

力扣sql中等篇练习(二十八)

力扣sql中等篇练习(二十八) 1 每个城市最高气温的第一天 1.1 题目内容 1.1.1 基本题目信息 1.1.2 示例输入输出 1.2 示例sql语句 # Write your MySQL query statement below SELECT w.city_id,MIN(w.day) day,w.degree FROM Weather w INNER JOIN (SELECT city_id,MAX(degr…

chatgpt赋能python:Python中keys的概述

Python中keys的概述 在Python中&#xff0c;字典&#xff08;dictionary&#xff09;是一种非常常见的数据结构&#xff0c;它由一系列键&#xff08;keys&#xff09;和对应值&#xff08;values&#xff09;组成。键是唯一的&#xff0c;而值可以重复。在字典中&#xff0c;…

Lucene基础学习

一、基础知识 1.Lucene简介 2.入门实例 3.内建Query对象 4.分析器Analyzer 5.Query Parser 6.索引 7.排序 8.过滤 9.概念简介 10.Lucene入门实例 二、Lucene的基础 三、索引建立 1.lucene索引_创建_域选项 2.lucene索引_的删除和更新 3.lucene索引_加权操作和Luke的简单演示…

msvcp140.dll丢失怎么办?msvcp140.dll重新安装的解决方法

msvcp140.dll是微软编译器系统中的一个动态链接库文件&#xff0c;它存储了许多的代码和数据&#xff0c;能帮助计算机程序正常运行。当系统中出现了msvcp140.dll丢失的情况时&#xff0c;则会出现程序无法正常运行的错误。这篇文章将为大家介绍如何解决msvcp140.dll丢失的问题…

WookTeam是一款轻量级的开源在线团队协作工具

产品介绍 English Documentation wookteam 是一款轻量级的在线团队协作工具&#xff0c;提供各类文档工具、在线思维导图、在线流程图、项目管理、任务分发&#xff0c;知识库管理等工具。wookteam 支持团队在线聊天沟通&#xff0c;订阅任务动态实时推送。wookteam 全部开源…

JavaScript实现用while语句来计算1-10的和的代码

以下为实现用while语句来计算1-10的和的程序代码和运行截图 目录 前言 一、用while语句来计算1-10的和 1.1 运行流程及思想 1.2 代码段 1.3 JavaScript语句代码 1.4 运行截图 前言 1.若有选择&#xff0c;您可以在目录里进行快速查找&#xff1b; 2.本博文代码可以根据…