《TCP/IP网络编程》学习笔记 | Chapter 1:理解网络编程和套接字

《TCP/IP网络编程》学习笔记 | Chapter 1:理解网络编程和套接字

  • 《TCP/IP网络编程》学习笔记 | Chapter 1:理解网络编程和套接字
    • 基本概念
      • 服务端
      • 客户端
    • 基于 Linux 平台的 "Hello world!" 服务端和客户端
    • 基于 Linux 的文件操作
      • 打开文件
      • 关闭文件
      • 写文件
      • 读文件
    • 基于 Windows 平台的实现
      • Winsock 的初始化
      • 注销 Winsock 相关库
      • 基于 Windows 的套接字相关函数
      • 创建基于 Windows 的服务端和客户端
      • 基于 Windows 的 I/O 函数
    • 习题
      • (1)套接字在网络编程中的作用是什么?为什么称它为套接字?
      • (2)在服务器端创建套接字后,会依次调用listen函数和accept函数。请比较并说明两者作用。
      • (3)Linux中,对套接字数据进行I/O时可以直接使用I/O相关函数;而在Windows中则不可以。原因为何?
      • (4)创建套接字后一般会给它分配地址,为什么?为了完成地址分配需要调用哪些函数?
      • (5)Linux中的文件描述符与Windows的句柄实际上非常类似。请以套接字为对象说明他们的含义。
      • (6)底层文件I/O函数与ANSI标准定义的文件I/O函数之间有何区别?
      • (7)参考本书给出的示例low_open.c和low_read.c,分别利用底层文件I/O和ANSI标准I/O编写文件复制程序。可任意指定复制程序的使用方法。

《TCP/IP网络编程》学习笔记 | Chapter 1:理解网络编程和套接字

基本概念

网络编程是什么?

编写程序使两台联网的计算机相互交换数据。

服务端

步骤 1:创建套接字

int socket(int domain, int type, int protocol);

成功时返回文件描述符,失败时返回-1。

步骤 2:绑定IP地址和端口号

int bind(int socket, const struct sockaddr *address, socklen_t address_len);

成功时返回0,失败时返回-1

步骤 3:使转化为可接受请求状态

int listen(int sockfd, int backlog);

成功时返回文件描述符,失败时返回-1。

步骤 4:受理请求连接

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

成功时返回文件描述符,失败时返回-1。

客户端

步骤 1:创建socket

步骤 2:发起连接请求

int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

成功时返回0,失败返回-1。

基于 Linux 平台的 “Hello world!” 服务端和客户端

服务端程序:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>void error_handling(char* message);int main(int argc,char* argv[])
{int sock;struct sockaddr_in serv_addr;char message[30];int str_len;if(argc!=3){printf("Usage:%s <IP> <port>\n",argv[0]);exit(1);}sock = socket(PF_INET,SOCK_STREAM,0);if(sock==-1){error_handling("socket() error!");}memset(&serv_addr,0,sizeof(serv_addr));serv_addr.sin_family = AF_INET;serv_addr.sin_addr.s_addr = inet_addr(argv[1]);serv_addr.sin_port=htons(atoi(argv[2]));if(connect(sock,(struct sockaddr*)&serv_addr,sizeof(serv_addr))==-1){error_handling("connect() error!");}str_len = read(sock,message,sizeof(message)-1);if(str_len==-1){error_handling("read() error!");}printf("Message from server:%s \n",message);close(sock);return 0;
}void error_handling(char* message)
{fputs(message,stderr);fputc('\n',stderr);exit(1);
}

客户端程序:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>void error_handling(char* message);int main(int argc,char* argv[])
{int sock;struct sockaddr_in serv_addr;char message[30];int str_len;if(argc!=3){printf("Usage:%s <IP> <port>\n",argv[0]);exit(1);}sock = socket(PF_INET,SOCK_STREAM,0);if(sock==-1){error_handling("socket() error!");}memset(&serv_addr,0,sizeof(serv_addr));serv_addr.sin_family = AF_INET;serv_addr.sin_addr.s_addr = inet_addr(argv[1]);serv_addr.sin_port=htons(atoi(argv[2]));if(connect(sock,(struct sockaddr*)&serv_addr,sizeof(serv_addr))==-1){error_handling("connect() error!");}str_len = read(sock,message,sizeof(message)-1);if(str_len==-1){error_handling("read() error!");}printf("Message from server:%s \n",message);close(sock);return 0;
}void error_handling(char* message)
{fputs(message,stderr);fputc('\n',stderr);exit(1);
}

基于 Linux 的文件操作

Linux中一切皆文件,socket自然也是文件。

​ 每当生成文件或socket,操作系统都将返回分配给它们的整数(文件描述符),文件描述符只不过是为了方便的称呼操作系统创建的文件或socket而赋予的数。

​ 分配给标准输入,输出及标准错误的文件描述符。

文件描述符对象
0标准输入 :Standard Input
1标准输出 :Standard Ouput
2标准错误 :Standard Error

其他的文件描述符从3开始的。

打开文件

#include <sys/stat.h>
#include <fcntl.h>int open(const char *path, int fla);

成功时返回文件描述符,失败时返回-1。

参数:

  • path: 文件名的字符串地址

  • flag: 文件打开模式信息,如需传递多个参数,应通过 | 运算符组合。

打开模式含义
O_CREAT必要时创建文件
O_TRUNC删除全部现有数据
O_APPEND维持现有数据,保存到其后面
O_RDONLY只读打开
O_WRONLY只写打开
O_RDWR读写打开

关闭文件

#include <unistd.h>int close(int fildes);

成功时返回0,失败时返回-1。

参数:

  • fildes: 需要关闭的文件或socket的文件描述符

写文件

#include <unistd.h>ssize_t write(int fildes, const void *buf, size_t nbyte);

成功时返回写入的字节数,失败时返回-1。

参数:

  • fildes: 显示数据传输对象的文件描述符

  • buf:保存要传输数据的缓冲地址值

  • nbyte: 要传输数据的字节数

size_t : unsigned int,ssize_t:signed int,这些都是元数据类型,由操作系统定义,通过 typedef 声明。

示例程序:

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>void error_handling(char *message)
{fputs(message, stderr);fputc('\n', stderr);exit(1);
}int main(void)
{int fd;char buf[] = "Let's go!\n";fd = open("data.txt", O_CREAT | O_WRONLY | O_TRUNC);if (fd == 1)error_handling("open() error!");printf("file descriptor: %d\n", fd);if (write(fd, buf, sizeof(buf)) == -1)error_handling("write() error!");close(fd);return 0;
}

运行结果:

在这里插入图片描述

注意:Windows 端可以用 type 命令打印 txt 文件的内容。

读文件

#include <unistd.h>ssize_t read(int fildes, void *buf, size_t nbyte);

成功时返回接收的字节数(但遇到文件结尾则返回0),失败时返回-1。

参数:

  • fildes:显示数据接收对象的文件描述符

  • buf:要保存接收数据的缓冲地址值

  • nbytes:要接收数据的最大字节数

示例程序:

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>#define BUF_SIZE 100void error_handling(char *message)
{fputs(message, stderr);fputc('\n', stderr);exit(1);
}int main(void)
{int fd;char buf[BUF_SIZE];fd = open("data.txt", O_RDONLY);if (fd == -1)error_handling("open() error!");printf("file descriptor: %d\n", fd);if (read(fd, buf, BUF_SIZE) == -1)error_handling("read() error!");printf("file data: %s", buf);close(fd);return 0;
}

运行结果:

在这里插入图片描述

基于 Windows 平台的实现

Windows 套接字,简称 Winsock,大部分参考 BSD 系列 UNIX 套接字设计,和 Linux 套接字类似。

Winsock 的初始化

进行Winsock编程时,首先调用 WSAStartup 函数,设置程序中用到的Winsock版本,并初始化相应版本的库。

int WSAStartup(WORD wVersionRequested,LPWSADATA lpWSAData);

参数:

  • wVersionRequested:Winsock版本信息
  • lpWSAData:WSADATA结构体变量的地址值

Winsock中存在多个版本,应准备WORD(typedef unsigned int WORD;)类型的套接字版本信息,若版本为1.2,则1是主版本号,2是副版本号,应传递 0x0201

​ 0x0201 高8位为副版本号,低8位为主版本号。这里借助 MAKEWORD 宏函数来传递版本信息号。

MAKEWORD(1,2); // 主版本号是1,副版本号是2,返回0x0201
int main(int argc,char* argv[])
{WSADATA wsaData;....if(WSAStartup(MAKEWORD(1,2), &wsaData) != 0){....}return 0;
}

注销 Winsock 相关库

#include <Winsock2.h>int WSACleanup(void);

成功时返回0,失败时返回 SOCKET_ERROR。

基于 Windows 的套接字相关函数

创建socket:

SOCKET socket(int af,int type,int protocol);

成功时返回套接字句柄(对应linux中的文件描述符),失败返回 INVALID_SOCKET。

绑定IP和端口号:

int bind(SOCKET s,const struct sockaddr* name,int namelen);

成功返回0,失败返回SOCKET_ERROR。

将服务端设置为可接受请求状态:

int listen(SOCKET s,int backlog);

成功返回0,失败返回SOCKET_ERROR。

受理请求连接(accept):

SOCKET accept(SOCKET s,struct sockaddr* addr,int* addrlen);

成功时返回套接字句柄,失败时返回INVALID_SOCKET。

从客户端发起请求连接:

int connect(SOCKET s,const struct sockaddr* name,int namelen);

成功时返回0,失败时返回SOCKET_ERROR。

关闭套接字:

int closesocket(SOCKET s);

成功时返回0,失败时返回SOCKET_ERROR。

Windows中的句柄相当于linux中的文件描述符,但是Windows中的文件句柄和套接字句柄是有区别的。

创建基于 Windows 的服务端和客户端

服务端:

#include <stdio.h>
#include <stdlib.h>
#include <winsock2.h>void ErrorHanding(char *message)
{fputs(message, stderr);fputc('\n', stderr);exit(1);
}int main(int argc, char *argv[])
{WSADATA wsaData;SOCKET hServerSock, hClientSock;SOCKADDR_IN serverAddr, clientAddr;int szClientAddr;char message[] = "Hello World!";if (argc != 2){printf("Usage: %s <port>\n", argv[0]);exit(1);}if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)ErrorHanding("WSAStartup() 	error!");hServerSock = socket(PF_INET, SOCK_STREAM, 0);if (hServerSock == INVALID_SOCKET)ErrorHanding("socket() 	error!");memset(&serverAddr, 0, sizeof(serverAddr));serverAddr.sin_family = AF_INET;serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);serverAddr.sin_port = htons(atoi(argv[1]));if (bind(hServerSock, (SOCKADDR *)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR)ErrorHanding("bind() error!");if (listen(hServerSock, 5) == SOCKET_ERROR)ErrorHanding("listen() error!");szClientAddr = sizeof(clientAddr);hClientSock = accept(hServerSock, (SOCKADDR *)&clientAddr, &szClientAddr);if (hClientSock == INVALID_SOCKET)ErrorHanding("accept() error!");send(hClientSock, message, sizeof(message), 0);closesocket(hClientSock);closesocket(hServerSock);WSACleanup();return 0;
}

客户端:

#include <stdio.h>
#include <stdlib.h>
#include <winsock2.h>void ErrorHanding(char *message)
{fputs(message, stderr);fputc('\n', stderr);exit(1);
}int main(int argc, char *argv[])
{WSADATA wsaData;SOCKET hSocket;SOCKADDR_IN serverAddr;char message[30];int strLen;if (argc != 3){printf("Usage: %s <IP> <port>\n", argv[0]);exit(1);}if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)ErrorHanding("WSAStartup() 	error!");hSocket = socket(PF_INET, SOCK_STREAM, 0);if (hSocket == INVALID_SOCKET)ErrorHanding("socket() 	error!");memset(&serverAddr, 0, sizeof(serverAddr));serverAddr.sin_family = AF_INET;serverAddr.sin_addr.s_addr = inet_addr(argv[1]);serverAddr.sin_port = htons(atoi(argv[2]));if (connect(hSocket, (SOCKADDR *)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR)ErrorHanding("connect() error!");strLen = recv(hSocket, message, sizeof(message) - 1, 0);if (strLen == -1)ErrorHanding("recv() error!");printf("Message from server: %s\n", message);closesocket(hSocket);WSACleanup();return 0;
}

编译遇到报错:

在这里插入图片描述

参考 【三种解决方法】undefined reference to `__imp_WSAStartup‘ 给出的解决办法,手动添加编译参数 -lwsock32:

gcc hello_server_win.c -lwsock32 -o hServerWingcc hello_client_win.c -lwsock32 -o hClientWin

编译就可以成功了:

在这里插入图片描述

我们运行服务端程序,监听 9190 端口:

hServerWin 9190

再运行客户端程序:

hClientWin 127.0.0.1 9190

得到输出:

Message from server: Hello World!

基于 Windows 的 I/O 函数

Linux中socket也是文件,因此可以通过文件I/O函数read和write进行数据传输。而Windows严格区分文件I/O函数和套接字I/O函数。

int send(SOCKET s,const char* buf,int len,int flags);

成功时返回传输字节数,失败时返回SOCKET_ERROR。

参数:

  • s:表示数据传输对象连接的套接字句柄值
  • buf:保存待传输数据的缓冲地址值
  • len:要传输的字节数
  • flags:传输数据时用到的多种选项信息
int recv(SOCKET s, const char* buf, int len, int flags);

成功时返回接收的字节数(收到EOF时为0),失败返回SOCKET_ERROR。

  • s:表示数据接收对象连接的套接字句柄值
  • buf:保存待接收数据的缓冲地址值
  • len:要接收的字节数
  • flags:接收数据时用到的多种选项信息

习题

(1)套接字在网络编程中的作用是什么?为什么称它为套接字?

网络编程就是编写程序让两台联网的计算机相互交换数据。在我们不需要考虑物理连接的情况下,我们只需要考虑如何编写传输软件。操作系统提供了名为“套接字”,套接字是网络传输传输用的软件设备。

socket英文原意是插座,我们把插头插到插座上就能从电网获得电力供给,同样,为了与远程计算机进行数据传输,需要连接到Internet,而变成中的“套接字”就是用来连接该网络的工具。

(2)在服务器端创建套接字后,会依次调用listen函数和accept函数。请比较并说明两者作用。

listen:将套接字转为可接受连接方式(监听套接字)

accept:受理连接请求,并且在没有连接请求的情况调用该函数,不会返回(阻塞)。直到有连接请求为止。二者存在逻辑上的先后关系。

(3)Linux中,对套接字数据进行I/O时可以直接使用I/O相关函数;而在Windows中则不可以。原因为何?

Linux把套接字也看作是文件,所以可以用文件I/O相关函数;而Windows要区分套接字和文件,所以设置了特殊的函数。

(4)创建套接字后一般会给它分配地址,为什么?为了完成地址分配需要调用哪些函数?

要在网络上区分来自不同机器的套接字,所以需要地址信息。分配地址是通过bind()函数实现。

(5)Linux中的文件描述符与Windows的句柄实际上非常类似。请以套接字为对象说明他们的含义。

Linux的文件描述符是为了区分指定文件而赋予文件的整数值(相当于编号)。Windows的文件描述符其实也是套接字的整数值,其目的也是区分指定套接字。

(6)底层文件I/O函数与ANSI标准定义的文件I/O函数之间有何区别?

  1. ANSI标准定义的输入、输出函数是与操作系统(内核)无关的以C标准写成的函数;相反,底层文件I/O函数是操作系统直接提供的。
  2. 标准I/O分为全缓冲,行缓冲,不缓冲三种形式;文件I/O为不带缓冲的I/O。
  3. 文件I/O主要针对文件操作,它操作的是文件描述符;标准I/O针对的是控制台,它操作的是字符流。对于不同设备得特性不一样,必须有不同API访问才最高效。

(7)参考本书给出的示例low_open.c和low_read.c,分别利用底层文件I/O和ANSI标准I/O编写文件复制程序。可任意指定复制程序的使用方法。

用底层I/O编写:

int fd1,fd2;
int count = 0;
char buf[20];fd1 = open("data.txt", O_RDONLY);
if (fd1 == -1)error_handling("open() error!");fd2 = open("data_copy.txt", O_CREAT | O_WRONLY);
if (fd2 == -1)error_handling("open() error!");while ((count = read(fd1, buf, 20)) > 0) // 每次读取20个字符
{write(fd2, buf, count);
}close(fd1);
close(fd2);return 0;

用ANSI标准I/O编写:

#include <stdio.h>
#include <stdlib.h>
#include <winsock2.h>void error_handling(char *message)
{fputs(message, stderr);fputc('\n', stderr);exit(1);
}int main(int argc, char *argv[])
{FILE *fin;    // 源文件FILE *fout;   // 目标文件char buf[20]; // 缓冲区设置为20int count;fin = fopen("data.txt", "r");if (NULL == fin)error_handling("open() error!");fout = fopen("data_copy.txt", "w");if (NULL == fout)error_handling("open() error!");while ((count = fread(buf, 1, 20, fin)) > 0){fwrite(buf, 1, count, fout);}fclose(fin);fclose(fout);return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C#-类:声明类、声明类对象

一&#xff1a;类的声明 class 类名 {//特征——成员变量//行为——成员方法//保护特征——成员属性//构造函数和析构函数//索引器//运算符重载//静态成员 }类名&#xff1a;帕斯卡 同一个语句块中的不同类 不能重名 二&#xff1a;声明类对象 2.1 类的声明 ≠ 类对象的声…

qt QProgressBar详解

1、概述 QProgressBar是Qt框架中的一个控件&#xff0c;专门用于显示任务的进度。它提供了一个可视化的进度条&#xff0c;让用户能够直观地了解任务的完成程度。QProgressBar支持水平和垂直两种显示方向&#xff0c;并且可以通过设置最小值和最大值来指定进度条的范围。此外&…

Node.js 入门指南:从零开始构建全栈应用

​&#x1f308;个人主页&#xff1a;前端青山 &#x1f525;系列专栏&#xff1a;node.js篇 &#x1f516;人终将被年少不可得之物困其一生 依旧青山,本期给大家带来node.js篇专栏内容:node.js-入门指南&#xff1a;从零开始构建全栈应用 前言 大家好&#xff0c;我是青山。作…

基于vue框架的的冷链食品物流信息管理系统v81wb(程序+源码+数据库+调试部署+开发环境)系统界面在最后面。

系统程序文件列表 项目功能&#xff1a;用户,司机,冷链食品,冷链食品订单,冷链车辆,配送信息,订单费用,站点信息,食品种类,省,市,食品质量,县 开题报告内容 基于Vue框架的冷链食品物流信息管理系统开题报告 一、研究背景与意义 随着全球食品贸易的快速发展和消费者对食品品质…

使用GetX实现GetPage中间件

前言 GetX 中间件&#xff08;Middleware&#xff09;是 GetX 框架中的一种机制&#xff0c;用于在页面导航时对用户进行权限控制、数据预加载、页面访问条件设置等。通过使用中间件&#xff0c;可以有效地控制用户的访问流程&#xff0c;并在适当条件下引导用户到所需页面。 这…

你知道Mac也能拥有丰富的右键菜单栏吗?

Mac的右键菜单栏功能少的可怜&#xff0c;和Windows没法比&#xff0c;所以许多朋友在使用Mac会有很多不习惯的地方&#xff0c;但是Mac的右键菜单栏也能够拥有超多功能&#xff0c;甚至丰富程度可以超越Windows&#xff0c;你知道吗 超级右键能够丰富拓展Mac的右键菜单栏&…

Spring Boot 注解大全:全面解析 Spring Boot 常用注解及其应用场景

Spring Boot 注解大全:全面解析 Spring Boot 常用注解及其应用场景 简介 Spring Boot 是一个基于 Spring 框架的简化开发框架,它旨在简化 Spring 应用的初始搭建和开发过程。Spring Boot 提供了一系列的注解,使得开发者可以更加方便地进行应用开发和配置。本文将详细介绍 S…

使用 Elasticsearch 进行语义搜索

Elasticsearch 是一款功能强大的开源搜索引擎&#xff0c;可用于全文搜索、分析和数据可视化。传统上&#xff0c;Elasticsearch 以其执行基于关键字/词汇的搜索的能力而闻名&#xff0c;其中文档基于精确或部分关键字匹配进行匹配。然而&#xff0c;Elasticsearch 已经发展到支…

(一)<江科大STM32>——软件环境搭建+新建工程步骤

一、软件环境搭建 &#xff08;1&#xff09;安装 Keil5 MDK 文件路径&#xff1a;江科大stm32入门教程资料/Keil5 MDK/MDK524a.EXE&#xff0c;安装即可&#xff0c;路径不能有中文。 &#xff08;2&#xff09;安装器件支持包 文件路径&#xff1a;江科大stm32入门教程资料…

【顶刊核心变量】上市公司企业数字创新数据(数字产品、流程、业务模式创新(2001-2023年)

1.资料名称&#xff1a;2023-2001年上市公司企业数字创新数据 2.测算方式&#xff1a;参考《系统工程理论与实践》郑攀攀&#xff08;2024&#xff09;老师的做法&#xff0c;本文基于上市公司年报文本, 结合文本分析和机器学习方法, 测度了企业数字创新(DI) . 具体的测度步骤…

在K8s平台部署个人博客

在K8s平台部署个人博客 实验步骤查看wordpress前端的service配置word press 实验步骤 kubectl create secret generic mysql-pass --from-literalpasswordYOUR_PASSWORD把mysql.tar.gz和wordpress.tar.gz上传到K8s工作节点&#xff0c;手动解压即可&#xff1a; 通过网盘分享的…

Qt项目实战:红绿灯小程序

目录 一.初始化对象 二.捕获并处理特定的事件 三.自定义绘制方法 四.绘制外部边框 五.绘制内部边框 六.绘制按钮的背景色 七.绘制覆盖层&#xff08;高光效果&#xff09; 八.效果 九.代码 1.h 2.cpp 一.初始化对象 1.设置文本、颜色、边框和背景色等默认值。 2.安…

408——计算机网络(持续更新)

文章目录 一、计算机网络概述1.1 计算机网络的概念1.2 计算机网络体系结构1.3 总结 二、物理层2.1 物理层的基本概念2.2 物理层的基本通信技术2.3 总结 一、计算机网络概述 1.1 计算机网络的概念 计算机网络的定义&#xff1a;将地理位置不同的具有独立功能的计算机通过网络线路…

算法简介:K最近邻算法

KNN 1. 最近邻算法1.1 回归 2. 机器学习OCR创建垃圾邮件过滤器预测股票市场 1. 最近邻算法 KNN&#xff08;k-nearest neighbours&#xff09;K最近邻算法&#xff1a;采用此算法进行分类&#xff0c;检索距离该元素最近的几个元素是什么类型&#xff0c;那么该元素即为什么类…

力扣动态规划基础版(矩阵型)

62.不同路径&#xff08;唯一路径问题&#xff09; 62. 不同路径https://leetcode.cn/problems/unique-paths/ 方法一&#xff1a;动态规划 找状态转移方程&#xff0c;也就是说它从左上角走到右下角&#xff0c;只能往右或者往下走&#xff0c;那么设置一个位置为&#xff…

adb 常用命令汇总

目录 adb 常用命令 1、显示已连接的设备列表 2、进入设备 3、安装 APK 文件到设备 4、卸载指定包名的应用 5、从设备中复制文件到本地 6、将本地文件复制到设备 7、查看设备日志信息 8、重启设备 9、截取设备屏幕截图 10、屏幕分辨率 11、屏幕密度 12、显示设备的…

基于大语言模型(LLM)自主Agent 智能体综述

近年来,LLM(Large Language Model)取得了显著成功,并显示出了达到人类智能的巨大潜力。基于这种能力,使用LLM作为中央控制器来构建自助Agent,以获得类人决策能力。 Autonomous agents 又被称为智能体、Agent。指能够通过感知周围环境、进行规划以及执行动作来完成既定任务。…

node.js模块化分析

什么是Node.js模块化 Node.js中的模块化‌是指将一个大文件拆分成独立且相互依赖的多个小模块。每个JS文件被视为一个独立的模块&#xff0c;模块之间是互相不可见的。如果一个模块需要使用另一个模块&#xff0c;则需要使用指定的语法来引入该模块&#xff0c;并且只能使用模块…

openstack之guardian介绍与实例创建过程

运行特征 采集模块&#xff1a;扩展Ceilometer&#xff0c;采集存储网、业务网连通性、nova目录是否可读写&#xff1b; 收集模块&#xff1a;将采集到的数据存储到数据库中&#xff1b; 分析模块&#xff1a;根据采集的结果&#xff0c;分析各节点状态&#xff0c;并进行反向检…

C语言 -- qsort的简单使用

qsort函数 一、介绍二、语法格式三、使用函数从小到大从大到小 四、结语 一、介绍 qsort 函数是 C 标准库中的一个通用排序函数&#xff0c;用于对数组进行快速排序。它定义在 <stdlib.h> 头文件中。这个非常灵活&#xff0c;因为它允许用户指定数组的元素类型、数组的大…