Linux网络——HTTP
一.应用层
我们程序员写的一个个解决我们实际问题, 满足我们日常需求的网络程序, 都是在应用层.
我们上一次写的网络版本计算器就是一个应用层的网络程序。
我们约定了数据的读取,一端发送时构造的数据, 在另一端能够正确的进行解析, 就是ok的. 这种约定, 就是应用层协议。
在应用层我们只负责将数据怎么读取,和怎么构造数据,然后将构造好的数据交给应用层的协议层传输层,再由传输层何其一下的网络协议栈来帮我们完成数据在网络中发送,至于数据在这之间是怎么发送的,什么时候发送的,我们不知道,不清楚,也不关心。
二.认识URL
平时我们俗称的 "网址" 其实就是说的 URL.

1.域名
服务器地址可以是一个IP地址,但是IP地址是点分十进制的字符串,为了方便记忆就有了和IP地址一 一对应的域名。
例如:
- 112.29.213.131 —— www.JD.com
- 36.155.132.55 —— www.baidu.com
2.urlencode和urldecode
像 / ? : 等这样的字符, 已经被url当做特殊意义理解了. 因此这些字符不能随意出现.
比如, 某个参数中需要带有这些特殊字符, 就必须先对特殊字符进行转义.
转义的规则如下:
将需要转码的字符转为16进制,然后从右到左,取4位(不足4位直接处理),每2位做一位,前面加上%,编码成%XY格式,这个过程就是urlencode。

"+" 被转义成了 "%2B"。
urldecode就是urlencode的逆过程。
三.HTTP协议格式
1.请求格式http

见一见http请求:
部分测试代码:
编写一个服务器,服务器多线程接受网络数据,使用浏览器在url栏框中输入服务端车程序的IP和端口,然后回车。此时浏览器就会构建一个http请求发送给我们的服务端程序,服务端程序直接将收到的数据直接以字符串的形式输出到终端。
void serverIO(int fd){string message;char buff[102400];// 读取一个完整的http请求报文int n = recv(fd, buff, sizeof(buff), 0);message = buff;// 直接将该请求以字符串的形式输出cout << "得到一个HTTP请求" << endl;cout << message << endl;close(fd);}
得到的http请求:

2.响应格式

见一见http响应:
使用telnet 向百度模拟发送一个http请求,接受返回的http响应。

HTTP协议的格式大致有四部分组成:
- 首行:HTTP请求——[ 方法 ]+[ url ]+[ 版本 ];HTTP响应——[ 版本 ]+[ 状态码 ]+[ 描述 ];其中请求中url实际上就是服务器上的请求的资源路径。
- Header:请求/响应 的属性,冒号分割的键值对;每组属性之间使用\n分隔;遇到空行表示Header部分结束。例如:Content-Length:8899,标识 请求/响应 的有效载荷长度,有效载荷的长度是8899。
- 空行:用来分隔Header和Body。
- Body:就是有效载荷部分,空行后面的内容都是Body. Body允许为空字符串. 如果Body存在, 则在Header中会有一个Content-Length属性来标识Body的长度;
四.HTTP响应状态码
| 状态码 | 类别 | 描述 |
| 1XX | lnformational(信息性状态码) | 接收的请求正在处理 |
| 2XX | Success(成功状态码) | 请求正常处理完毕 |
| 3XX | Redirection(重定向状态码) | 需要进行附加操作以完成请求 |
| 4XX | Client Error(客户端错误状态码) | 服务器无法处理请求 |
| 5XX | Server Error(服务器错误状态码) | 服务器处理请求出错 |
说明:
Client Error:
- 客户端连接的端口错了。
- 客户端连接的域名或者IP地址错误。
- 如果客户端使用了域名连接,域名可能指向了错误的服务器。
- 当客户端发送了一个无效请求时,服务器可能会因为无法处理而返回 Client Error。
lnformational:
- 主要作用是告知客户端请求已经被接受 。
Redirection:
- 是服务器在处理客户端请求时,为了保证流程的顺利进行而发出的一种信号。
- 当客户端发送一个请求到服务器,服务器会根据需要将请求重定向到另一个URL。
Success:
- 表示客户端与服务器之间的通信已经成功完成,并且服务器已经处理了客户端的请求。
Server Error:
- 表示服务器在处理客户端请求时发生了错误。
- 服务器遇到了一个未知的错误,无法完成请求的处理。
- 服务器当前无法处理请求,因为过载或维护。
五.HTTP常见Header
Header是以K/V形式存储的字符串,主要是一些协议的属性说明等。
- Content-Type: 数据类型(text/html等)
- Content-Length: Body的长度
- Host: 客户端告知服务器, 所请求的资源是在哪个主机的哪个端口上;
- User-Agent: 声明用户的操作系统和浏览器版本信息;
- referer: 当前页面是从哪个页面跳转过来的;
- location: 搭配3xx(重定向)状态码使用, 告诉客户端接下来要去哪里访问;
- Cookie: 用于在客户端存储少量信息. 通常用于实现会话(session)的功能;
介绍Content-Type:表明此次http报文的body传输的是什么内容。
对于服务器上的每一种资源,都是以文件的形式存在的,文件都会有自己的类型,例如(网页文件).html,(音频文件).mp3,(图片).jpg/.png,(视频).mp4。
每一种文件类型,都会有自己对应的Content-Type类型:
- text/html:HTML 文档
- text/css:CSS 样式表
- text/javascript:JavaScript 脚本
- image/jpeg:JPEG 图像
- image/png:PNG 图像
- image/gif:GIF 图像
Content-Type 对照表
六.简单的HTTP服务器
编写一个服务器,多线程处理请求,对于请求的处理,解析一个http请求反序列化,根据http的请求的资源,构建响应并返回。
Sock.hpp
#pragma once
#include <iostream>
#include <cstdio>
#include <cstring>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include "Log.hpp"
#define TCP SOCK_STREAM
#define UDP SOCK_DGRAM
const static int backlog = 32;enum
{SOCK_ERR = 10,BING_ERR,LISTEN_ERR,CONNECT_ERR
};class Udp
{
public:Udp(int SOCK){_listensock = socket(AF_INET, SOCK, 0);if (_listensock == -1){Logmessage(Fatal, "socket err ,error code %d,%s", errno, strerror(errno));exit(SOCK_ERR);}}Udp(uint16_t port, int SOCK): _port(port){_listensock = socket(AF_INET, SOCK, 0);if (_listensock == -1){Logmessage(Fatal, "socket err ,error code %d,%s", errno, strerror(errno));exit(10);}}void Bind(){struct sockaddr_in host;host.sin_family = AF_INET;host.sin_port = htons(_port);host.sin_addr.s_addr = INADDR_ANY; // #define INADDR_ANY 0x00000000socklen_t hostlen = sizeof(host);int n = bind(_listensock, (struct sockaddr *)&host, hostlen);if (n == -1){Logmessage(Fatal, "bind err ,error code %d,%s", errno, strerror(errno));exit(BING_ERR);}}int FD(){return _listensock;}~Udp(){close(_listensock);}protected:int _listensock;uint16_t _port;
};class Tcp : public Udp
{
public:Tcp(uint16_t port): Udp(port, TCP){}Tcp(): Udp(TCP){}void Listen(){int n = listen(_listensock, backlog);if (n == -1){Logmessage(Fatal, "listen err ,error code %d,%s", errno, strerror(errno));exit(LISTEN_ERR);}}int Accept(string *clientip, uint16_t *clientport){struct sockaddr_in client;socklen_t clientlen;int sock = accept(_listensock, (struct sockaddr *)&client, &clientlen);if (sock < 0){Logmessage(Warning, "bind err ,error code %d,%s", errno, strerror(errno));}else{*clientip = inet_ntoa(client.sin_addr);*clientport = ntohs(client.sin_port);}return sock;}void Connect(string ip, uint16_t port){struct sockaddr_in server;memset(&server, 0, sizeof(server));server.sin_family = AF_INET;server.sin_port = htons(port);server.sin_addr.s_addr = inet_addr(ip.c_str());socklen_t hostlen = sizeof(server);int n = connect(_listensock, (struct sockaddr *)&server, hostlen);if (n == -1){Logmessage(Fatal, "Connect err ,error code %d,%s", errno, strerror(errno));exit(CONNECT_ERR);}}~Tcp(){}
};
Server.hpp
#pragma once
#include <iostream>
#include <string>
#include <pthread.h>
#include <functional>
#include "Sock.hpp"using fun_t = std::function<string(string &)>;
class Httpserver;
struct Args
{Args(Httpserver *ser, string ip, uint16_t port, int fd): _ip(ip), _port(port), _pserver(ser), _fd(fd){}int _fd;uint16_t _port;string _ip;Httpserver *_pserver;
};class Httpserver
{
public:Httpserver(fun_t func, uint16_t port): _func(func){tcp = new Tcp(port);tcp->Bind();tcp->Listen();cout << "服务器创建成功" << endl;}void start(){while (1){string clientip;uint16_t clientport;cout << "start accept" << endl;int sock = tcp->Accept(&clientip, &clientport);cout << "get a new connect" << endl;// 多线程处理请求pthread_t t;Args *args = new Args(this, clientip, clientport, sock);pthread_create(&t, nullptr, ThreadRun, args);}}~Httpserver(){delete tcp;}private:static void *ThreadRun(void *args){pthread_detach(pthread_self());Args *ts = static_cast<Args *>(args);ts->_pserver->serverIO(ts->_fd);delete ts;return nullptr;}void serverIO(int fd){string message;char buff[102400];// 1.确信,读取一个完整的http请求报文int n = recv(fd, buff, sizeof(buff), 0);message = buff;string re = _func(message);send(fd, re.c_str(), re.length(), 0);close(fd);}private:Tcp *tcp;fun_t _func;
};
Server.cc
#include <sstream>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/socket.h>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <string>
#include <vector>
#include "Server.hpp"
#include "util.hpp"const string wwwroot = "./html/3";
const string defaupath = "/index.html";class HttpRequest
{
public:HttpRequest(){}~HttpRequest() {}void Print(){cout << method_ << ":" << url_ << ":" << httpVersion_ << endl;for (auto &e : body_)cout << e << endl;cout << "suffix:" << suffix_ << endl;cout << "path:" << path_ << endl;}public:std::string method_; // 请求方法std::string url_; // 资源地址std::string httpVersion_; // 协议版本std::vector<std::string> body_; // 报头std::string path_; // 请求资源路径std::string suffix_; // 资源类型
};HttpRequest Deserialize(string &message)
{HttpRequest req;// 1.拿到请求行string oneline = HeadOneLine(message, SEP);// 2.解析请求行DisposeOneLine(oneline, &req.method_, &req.url_, &req.httpVersion_);// 3.解析反序列化报头while (!message.empty()){string mes = HeadOneLine(message, SEP);req.body_.push_back(mes);}// 4.设置请求资源路径 url:/a/b/cif (req.url_[req.url_.length() - 1] == '/'){req.path_ = wwwroot + defaupath; //./html/index.html}else{req.path_ = wwwroot + req.url_; //./html/a/b/c}// 5.设置请求资源类型auto pos = req.url_.find('.');if (pos == string::npos)req.suffix_ = ".html";elsereq.suffix_ = req.url_.substr(pos);return req;
}string Dispose(string &message)
{// 这里我们一定读取的是一个完整的报文// 一个网页会有很多的资源,每一个资源(网页,图片,视频),都需要一次http请求来得到// 所以我们需要知道,每次请求的资源是什么,即需要知道请求的url是什么,url的类型是什么// 反序列化请求HttpRequest req = Deserialize(message);req.Print();// 响应————最简单的一个响应// 4.有效载荷string body = Readfile(req.path_) + SEP;// 1.响应的状态行————"HTTP版本 状态码 状态描述\r\n"string request_head = string("HTTP/1.0 200 OK") + SEP;// 2.响应报头————Content-Length,Content-Typerequest_head += string("Content-Length: ") + to_string(body.length()) + SEP;request_head += GetContentType(req.suffix_) + SEP;// 3.空行request_head += SEP;// 整体的响应报文string responce = request_head + body;return responce;
}void daemonize()
{// 1.忽略SIGPIPE信号signal(SIGPIPE, SIG_IGN);// 2.更改进程的工作目录// chdir();// 3.让自己不要成为进程组组长if (fork() > 0)exit(0);// 4.设置自己是一个独立的会话setsid();// 5.重定向0,1,2int fd = 0;if (fd = open("dev/null", O_RDWR) != -1){dup2(fd, STDIN_FILENO);dup2(fd, STDOUT_FILENO);dup2(fd, STDERR_FILENO);// 6.关闭掉不需要的fdif (fd > STDERR_FILENO){close(fd);}}
}int main(int argc, char *argv[])
{daemonize();uint16_t port = atoi(argv[1]);Httpserver httpser(Dispose, port);httpser.start();return 0;
}
Util.hpp
#pragma once
#include <iostream>
#include <unistd.h>
#include <string>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>#define SEP "\r\n"
using namespace std;string Readfile(const string path)
{// 1. 获取文件本身的大小string fileContent;struct stat st;int n = stat(path.c_str(), &st);if (n < 0)return "";int size = st.st_size;// 2. 调整string的空间fileContent.resize(size);// 3. 读取int fd = open(path.c_str(), O_RDONLY);if (fd < 0)return "";read(fd, (char *)fileContent.c_str(), size);close(fd);return fileContent;
}string HeadOneLine(string &message, const string &sep)
{auto pos = message.find(sep, 0);if (pos == string::npos)return "";string oneline = message.substr(0, pos);message.erase(0, pos + sep.size());return oneline;
}void DisposeOneLine(const string &oneline, string *method, string *url, string *httpVersion)
{stringstream line(oneline);line >> *method >> *url >> *httpVersion;
}string GetContentType(const string &suffix)
{std::string content_type = "Content-Type: ";if (suffix == ".html" || suffix == ".htm")content_type + "text/html";else if (suffix == ".css")content_type += "text/css";else if (suffix == ".js")content_type += "application/x-javascript";else if (suffix == ".png")content_type += "image/png";else if (suffix == ".jpg")content_type += "image/jpeg";else{}return content_type;
}
效果展示:

七.HTTP的方法

HTTP的方法有很多但是最常用的只有两个:GET,POST。
1.GET方法
我们要促使浏览器使用不同的方法进行资源请求,提交,要使用html的表单。
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>CSDN</title>
</head><body><h1>test</h1><form action="/a/b/c.exe" method="get">姓名: <input type="text" name="myname" value=""><br />密码: <input type="password" name="mypasswd"><br /><input type="submit" value="提交"><br /></form></body></html>

尝试提交数据:


2.POST方法

再次尝试提交数据:

区别:
- GET能获取一个静态网页,GET也能提交参数,通过URL的方式提交参数。
- POST请求,提交的参数的时候,是通过正文的部分提交的参数。
- GET方法提交参数,不私密(没有不安全的说法),安全对HTTP来说本身就没有保障。
- POST提交参数比较私密一些。
- 由于GET使用url提交参数,所以大小一般会受限。
- POST使用正文提交参数,正文理论上可以非常大。
相关文章:
Linux网络——HTTP
一.应用层 我们程序员写的一个个解决我们实际问题, 满足我们日常需求的网络程序, 都是在应用层. 我们上一次写的网络版本计算器就是一个应用层的网络程序。 我们约定了数据的读取,一端发送时构造的数据, 在另一端能够正确的进行解析, 就是ok的. 这种约定, 就是应…...
ElasticSearch综合练习题,ES为8版本,使用Kibana运行语句
文章目录 前言一、ES查询集群情况二、ES索引习题查询所有索引查询单个索引 三、ES增删改查数据单条处理批量处理 四、雇员查询练习题五、学生查询练习题六、商品信息联系题其他:一问一答参考文档 前言 ES8版本没有type概念,所以语法可能会与其他版本有差…...
Java方法中不使用的对象应该手动赋值为NULL吗?
在java方法中,不使用的对象是否应该手动赋值为null?我们先来通过一个示例看一下。 垃圾回收示例一 public class GuoGuoTest {public static void main(String[] args) {byte[] placeholder new byte[64 * 1024 * 1024];System.gc();} } 上面代码向内…...
Mysql主从搭建
Mysql主从搭建 1.Mysql下载1.1 查看操作系统2.2 下载mysql安装包 2.Mysql安装2.1 解压2.2 目录重命名2.3 创建data,存储文件2.4 创建用户组2.5 授权用户2.6 配置环境变量2.7 编辑my.cnf2.8 创建相关目录和文件2.9 初始化数据库2.10 复制mysql.server到/etc/init.d/下…...
WPF程序给按钮增加不同状态的图片
首先我们在资源里添加几个图片,Up,Over和Down状态。 然后我们创建一个Style。默认我们的背景设置成Up 然后在Triggers里添加代码,当Property:IsMouseOver为True的时候更换成Over;当Property:IsPressed为Tr…...
Java编程陷阱(三)
陷阱11:不要使用StringBuffer类来拼接字符串 StringBuffer是Java中的一个类,它可以表示一个可变的字符串,也就是可以对字符串进行修改和追加的操作,比如使用append或insert方法来拼接字符串。有时候,我们需要使用StringBuffer类来拼接字符串,比如在循环中动态地构建一个字…...
数据仓库相关
在阿里巴巴的数据体系中,我们建议将数据仓库分为三层,自下而上为:数据引入层(ODS,Operation Data Store)、数据公共层(CDM,Common Data Model)和数据应用层(…...
SpringBoot学习笔记-创建个人中心页面(下)
笔记内容转载自 AcWing 的 SpringBoot 框架课讲义,课程链接:AcWing SpringBoot 框架课。 CONTENTS 1. 实现个人中心页面2. POJO时区修改3. 集成代码编辑器 本节实现个人中心的前端页面,用户能够查看自己的 Bot 信息,并能创建、修改…...
电子秤方案:做一个宠物勺方案设计
养宠物是一件费心劳力的事情,但同时也是能够给你带来快乐和幸福感的事情。就是有时候会怕宠物毫无征兆地生病令人措手不及,所以电子秤方案设计鼎盛合科技分享一个小方案,能够及时了解到宠物的身体状况问题。 蓝牙宠物勺是一种具有记录和称重…...
Debezium-Embedded 实时监控MySQL数据变更
1.Debezium-Embedded 简介 Debezium连接器的操作通常是将它们部署到Kafka Connect服务,并配置一个或多个连接器来监控上游数据库,并为它们在上游数据库中看到的所有更改生成数据更改事件。这些数据更改事件被写入Kafka,在那里它们可以被许多不…...
计算机是如何工作的(简单介绍)
目录 一、冯诺依曼体系 二、CPU基本流程工作 逻辑⻔ 电⼦开关——机械继电器(Mechanical Relay) ⻔电路(Gate Circuit) 算术逻辑单元 ALU(Arithmetic & Logic Unit) 算术单元(ArithmeticUnit) 逻辑单元(Logic Unit) ALU 符号 寄存器(Regis…...
JSP基本表单和Request对象使用例子
表单的jsp; <%page contentType"text/html;charsetgbk" pageEncoding"UTF-8"%> <!DOCTYPE html> <html><head><meta http-equiv"Content-Type" content"text/html; charsetUTF-8"><titl…...
【Redux】Redux 基本使用
1. Redux 快速上手 Redux 是 React 最常用的集中状态管理工具,类似于Vue中的Pinia(Vuex),可以独立于框架运行。 <button id"decrement">-</button> <span id"count">0</span> <…...
多线程Thread(初阶一:认识线程)
目录 一、引用线程的原因 二、线程的概念 三、进程和线程的区别 四、多线程编程 一、引用线程的原因 多任务操作系统,希望系统能同时运行多个任务。所以会涉及到进程,需要对进程进行管理、调度等。 而单任务操作系统,就完全不涉及到进程…...
系列五、GC垃圾回收【四大垃圾算法-复制算法】
一、堆的内存组成 二、复制算法 2.1、发生位置 复制算法主要发生在新生代,发生在新生代的垃圾回收也被叫做Minor GC。 2.2、 Minor GC的过程 复制>清空》交换 1、eden、from区中的对象复制到to区,年龄1 首先,当eden区满的时候会触发第一…...
LeetCode(24)文本左右对齐【数组/字符串】【困难】
目录 1.题目2.答案3.提交结果截图 链接: 文本左右对齐 1.题目 给定一个单词数组 words 和一个长度 maxWidth ,重新排版单词,使其成为每行恰好有 maxWidth 个字符,且左右两端对齐的文本。 你应该使用 “贪心算法” 来放置给定的单…...
Spring-Spring之事务底层源码解析
EnableTransactionManagement工作原理 开启Spring事务本质上就是增加了一个Advisor,但我们使用EnableTransactionManagement注解来开启Spring事务是,该注解代理的功能就是向Spring容器中添加了两个Bean: AutoProxyRegistrarProxyTransactio…...
后端面经学习自测(三)
文章目录 1、ArrayList和Linkedlist区别?2、ArrayList扩容机制?3、ArrayList和Linkedlist分别能做什么场景?4、事务特性?MySQL事务Redis事务Spring事务5、在Spring中事务失效的场景?6、Java泛型?7、泛型擦除…...
力扣labuladong——一刷day40
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、力扣341. 扁平化嵌套列表迭代器 前言 N叉树的结构,构造迭代器 一、力扣341. 扁平化嵌套列表迭代器 /*** // This is the interface that allo…...
在VS Code中使用VIM
文章目录 安装和基本使用设置 安装和基本使用 VIM是VS Code的强大对手,其简化版本VI是Linux内置的文本编辑器,堪称VS Code问世之前最流行的编辑器,也是VS Code问世之后,我仍在使用的编辑器。 对VIM无法割舍的原因有二࿰…...
大话软工笔记—需求分析概述
需求分析,就是要对需求调研收集到的资料信息逐个地进行拆分、研究,从大量的不确定“需求”中确定出哪些需求最终要转换为确定的“功能需求”。 需求分析的作用非常重要,后续设计的依据主要来自于需求分析的成果,包括: 项目的目的…...
Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility
Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility 1. 实验室环境1.1 实验室环境1.2 小测试 2. The Endor System2.1 部署应用2.2 检查现有策略 3. Cilium 策略实体3.1 创建 allow-all 网络策略3.2 在 Hubble CLI 中验证网络策略源3.3 …...
vue3 字体颜色设置的多种方式
在Vue 3中设置字体颜色可以通过多种方式实现,这取决于你是想在组件内部直接设置,还是在CSS/SCSS/LESS等样式文件中定义。以下是几种常见的方法: 1. 内联样式 你可以直接在模板中使用style绑定来设置字体颜色。 <template><div :s…...
反射获取方法和属性
Java反射获取方法 在Java中,反射(Reflection)是一种强大的机制,允许程序在运行时访问和操作类的内部属性和方法。通过反射,可以动态地创建对象、调用方法、改变属性值,这在很多Java框架中如Spring和Hiberna…...
HTML前端开发:JavaScript 常用事件详解
作为前端开发的核心,JavaScript 事件是用户与网页交互的基础。以下是常见事件的详细说明和用法示例: 1. onclick - 点击事件 当元素被单击时触发(左键点击) button.onclick function() {alert("按钮被点击了!&…...
华为云Flexus+DeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建
华为云FlexusDeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建 前言 如今大模型其性能出色,华为云 ModelArts Studio_MaaS大模型即服务平台华为云内置了大模型,能助力我们轻松驾驭 DeepSeek-V3/R1,本文中将分享如何…...
如何理解 IP 数据报中的 TTL?
目录 前言理解 前言 面试灵魂一问:说说对 IP 数据报中 TTL 的理解?我们都知道,IP 数据报由首部和数据两部分组成,首部又分为两部分:固定部分和可变部分,共占 20 字节,而即将讨论的 TTL 就位于首…...
Rapidio门铃消息FIFO溢出机制
关于RapidIO门铃消息FIFO的溢出机制及其与中断抖动的关系,以下是深入解析: 门铃FIFO溢出的本质 在RapidIO系统中,门铃消息FIFO是硬件控制器内部的缓冲区,用于临时存储接收到的门铃消息(Doorbell Message)。…...
USB Over IP专用硬件的5个特点
USB over IP技术通过将USB协议数据封装在标准TCP/IP网络数据包中,从根本上改变了USB连接。这允许客户端通过局域网或广域网远程访问和控制物理连接到服务器的USB设备(如专用硬件设备),从而消除了直接物理连接的需要。USB over IP的…...
A2A JS SDK 完整教程:快速入门指南
目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库ÿ…...
