[C++ 网络协议] 套接字和地址族、数据序列

news2025/6/18 15:20:57

目录

1. 套接字

1.1 在Linux平台下构建套接字

1.1.1 用于接听的套接字(服务器端套接字)

1.1.2 用于发送请求的套接字(客户端套接字)

1.2 在Windows平台下构建套接字

1.2.1 Winsock的初始化

1.2.2 用于接听的套接字(服务器端套接字)

1.2.3 用于发送请求的套接字(客户端套接字)

1.3 Linux和Windows套接字的区别

1.4 套接字特性

1.4.1 socket函数

1.4.1.1 协议族信息(domain形参)

1.4.1.2  套接字类型(Type形参)

1.4.1.2.1 面向连接的套接字(SOCK_STREAM)

1.4.1.2.2 面向消息的套接字(SOCK_DGRAM)

1.4.1.3 协议的最终选择(protocol形参)

2. 地址族和数据序列

2.1 网络地址

2.1.1 IPv4(常用)

2.1.1.1 网络地址和主机地址

2.1.2 端口号

2.1.3 bind函数

2.1.3.1 sockaddr_in结构体

2.1.4 网络字节序

2.1.5 字节序转换

2.1.6 网络地址的初始化和分配

2.1.6.1 inet_addr函数

2.1.6.2 inet_aton函数(Windows不存在此函数)

2.1.6.3 inet_ntoa函数(和inet_aton函数相反)

2.1.6.4 INADDR_ANY常数

2.1.6.5 WSAStringToAddress函数(只有Windows平台有,不利于兼容性)

2.1.6.6 WSAAddressToString函数(只有Windows平台有,不利于兼容性)

2.1.6.7 服务器端初始化IP地址时非常明确,为什么还要进行IP的初始化呢?


网络编程:编写程序使两台连网的计算机进行数据交换。

1. 套接字

操作系统提供名为套接字的部件,套接字是网络数据传输用的软件设备,它能够连接到因特网上,与远程计算机进行数据传输。

1.1 在Linux平台下构建套接字

对于Linux而言,socket操作与文件操作没有区别。如:close函数不仅可以关闭文件也可以关闭套接字。

1.1.1 用于接听的套接字(服务器端套接字)

第一步:调用socket函数创建套接字

#include<sts/socket.h>
int socket(int domain,int type,int protocol);
成功返回文件描述符,失败返回-1

第二步:调用bind函数分配IP地址和端口号

#include<sts/socket.h>
int bind(int sockfd,struct sockaddr* myaddr,socklen_t addrlen);
成功返回0,失败返回-1

第三步:调用listen函数转为可接收请求状态

#include<sts/socket.h>
int listen(int sockfd,int backlog);
成功返回0,失败返回-1

第四步:调用accept函数受理连接请求

#include<sts/socket.h>
int accept(int sockfd,struct sockaddr* addr,socklen_t* addrlen);
成功返回文件描述符,失败返回-1

accpet函数一直等待,直到有连接请求时,才会有返回值。

第五步:调用write函数发送数据

#include<unistd.h>
 
ssize_t write(int fd,const void* buf,size_t nbytes);
成功则返回写入的字节数,失败返回-1

fd:文件描述符参数

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

nbytes:要传输数据的字节数

第六步:关闭套接字

#include<unistd.h>
     
int close(int fd);
成功返回0,失败返回-1

fd:文件描述符参数。 

close函数不仅可以关闭文件也可以关闭套接字。 

1.1.2 用于发送请求的套接字(客户端套接字)

第一步:调用socket函数创建套接字

如上。

第二步:调用connect函数连接服务器端

#include<sts/socket.h>
int connect(int sockfd,struct sockaddr* serv_addr,socklen_t addrlen);
成功返回0,失败返回-1

第三步:调用read函数读取服务器传输的信息

#include<unistd.h>
 
ssize_t read(int fd,void *buf,size_t nbytes);
成功则返回接收的字节数(但遇到文件结尾则返回0),失败返回-1

fd:数据接收对象的文件描述符参数

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

nbytes:要接收数据的字节数

第四步:关闭套接字

如上。

1.2 在Windows平台下构建套接字

在Windows平台下构建套接字要先进行Winsock的初始化。

1.2.1 Winsock的初始化

初始化版本库

#include<winsock2.h>

int WSAStartup(WORD wVersionRequested,LPWSADATA lpWSAData);
成功返回0,失败返回非0的错误代码值

wVersionRequested:WORD是通过typedef定义的unsigned short类型,这个参数是提供套接字版本信息。可借助MAKEWORD宏函数来构建版本信息,如:

MAKEWORD(1,2);       //主版本为1,副版本为2,返回0x0201
MAKEWORD(2,2);       //主版本为2,副版本为2,返回0x0202

lpWSAData:传入WSADATA型结构体变量地址(LPWSADATA是WSADATA的指针类型),调用完函数后会将相关参数,填充到这个参数里。

WSADATA wsaData;
if(WSAStartup(MAKEWORD(2,2),&wsaData)!=0)
{
    ......
}

注销版本库

#include<winsock2.h>

int WSACleanup(void);
成功返回0,失败返回SOCKET_ERROR

销毁Winsock相关库,无法再调用Winsock相关函数。

1.2.2 用于接听的套接字(服务器端套接字)

 第一步:调用socket函数创建套接字

#include <winsock2.h>
SOCKET socket(int af,int type,int protocol);
成功返回套接字句柄,失败返回INVALID_SOCKET

第二步:调用bind函数分配IP地址和端口号

#include <winsock2.h>
int bind(SOCKET s,const struct sockaddr* name,int namelen);
成功返回0,失败返回SOCKET_ERROR

第三步:调用listen函数转为可接收请求状态

#include <winsock2.h>
int listen(SOCKET s,int backlog);
成功返回0,失败返回SOCKET_ERROR

第四步:调用accept函数受理连接请求

#include <winsock2.h>
SOCKET accept(SOCKET s,struct sockaddr* addr,int* addrlen);
成功返回文件描述符,失败返回INVALID_SOCKET

accpet函数一直等待,直到有连接请求时,才会有返回值。

第五步:调用send函数发送数据

#include<winsock2.h>
int send(SOCKET s,const char* buf,int len,int flags);
成功返回传输字节数,失败返回SOCKET_ERROR

 s:表示数据传输对象连接的套接字句柄值

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

len:要传输的字节数

flags:传输数据时用到的多种选项信息

第六步:关闭套接字

#include <winsock2.h>
int closeconnect(SOCKET s);
成功返回0,失败返回SOCKET_ERROR

1.2.3 用于发送请求的套接字(客户端套接字)

第一步:调用socket函数创建套接字

如上。

第二步:调用connect函数连接服务器端

#include <winsock2.h>
int connect(SOCKET s,const struct sockaddr* name,int namelen);
成功返回0,失败返回SOCKET_ERROR

第三步:调用recv函数,接收服务器端传来的数据

#include <winsock2.h>
int recv(SOCKET s,const char* buf,int len,int flags);
成功返回接收的字节数(收到EOF时为0),失败返回SOCKET_ERROR

 s:表示数据接收对象连接的套接字句柄值

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

len:要接收的最大字节数

flags:接收数据时用到的多种选项信息

第四步:关闭套接字

如上。

1.3 Linux和Windows套接字的区别

  1. 文件描述符和句柄的区别:

    在Linux中,文件描述符是不区分文件和套接字的,即两个都是一样的

    在Windows中,句柄是区分文件和套接字的,并不完全一样。

    比较两个系统的socket、listen和accept函数,可以发现,其实Linux的int sockfd就对应于Windows的SOCKET s,即SOCKET这个类型,就存有套接字句柄整形值,也类似于一种编号。

  2. write和send的区别:

         在Linux中,有write也有send函数,来传输数据。

        在windows中,send函数只是比Linux中的write函数多了最后的flag参数。

1.4 套接字特性

1.4.1 socket函数

int socket(
int domain,    //套接字中使用的协议族(Protocol Family)信息
int type,      //套接字数据传输类型信息
int protocol   //计算机间通信中使用的协议信息
);
成功返回文件描述符,失败返回-1

 一个socket套接字=协议族+套接字类型+最终协议。

1.4.1.1 协议族信息(domain形参)

协议族:套接字通信中协议的分类。

名称协议族
PF_INET(常用)IPv4互联网协议族
PF_INET6IPv6互联网协议族
PF_LOCAL本地通信的UNIX协议族
PF_PACKET底层套接字的协议族
PF_IPXIPX Novell协议族

1.4.1.2  套接字类型(Type形参)

套接字类型:套接字的数据传输方式。

1.4.1.2.1 面向连接的套接字(SOCK_STREAM)

特点:

  1. 传输过程中数据不会丢失
  2. 按序传输数据
  3. 传输的数据不存在数据边界
  4. 套接字连接必须一一对应

总结:可靠的、按序传递的、基于字节的面向连接的数据传输方式的套接字注意接收和发送数据大小要相等。

特点:传输过程中数据不会丢失、传输的数据不存在数据边界,解释:

        在接收的套接字内部,有一个由字节数组组成的缓冲区,从传输端传过来的数据会先存储到这个缓冲区里,如果缓冲区满了,那么传输端就会停止传输,等待缓冲区中的数据被读取完,再继续传输。其中传输出错,也会进行重传服务,除特殊情况外,不会有数据丢失。

1.4.1.2.2 面向消息的套接字(SOCK_DGRAM)

特点:

  1. 快速传输
  2. 传输的数据可能丢失、损毁
  3. 传输的数据有数据边界
  4. 限制每次传输的大小

总结:不可靠的,不按序传递的、以数据的高速传输为目的的套接字,不存在连接的概念注意接收和发送数据次数要相等。

特点:传输的数据具有数据边界,解释:

        每次传输都有大小限制,如果超过了这个限制,那么就得分批发送,即意味着接收数据的次数应和传输次数相同。而面向连接的套接字,没有这个要求。

1.4.1.3 协议的最终选择(protocol形参)

第三个参数的意义:同一协议族中存在多个数据传输方式相同的协议

与套接字类型对应的:

  1. 面向连接的套接字:TCP套接字(IPPROTO_TCP),注意接收和发送数据大小要相等。
  2. 面向消息的套接字:UDP套接字(IPPROTO_UDP),注意接收和发送数据次数要相等。

2. 地址族和数据序列

IP(Internet Protocol网络协议):为收发网络数据而分配给计算机的值。

端口号:区分程序中创建的套接字而分配给套接字的序号。

2.1 网络地址

分为两类:IPv4(4字节地址族)、IPv6(16字节地址族)。

2.1.1 IPv4(常用)

IPv4标准的4字节IP地址,由网络地址主机地址组成。

2.1.1.1 网络地址和主机地址

IPv4分为如下A、B、C、D四种类型:

通过首字节可以判断其属于哪种类型:

首字节范围类型
0~127A
128~191B
192~223C

向对应IP地址主机传输数据,是先通过网络地址,查找到对应的路由器或交换机,再由路由器或交换机,根据主机ID将数据分发到主机上。如图:将数据发送到203.211.172.103上,会先找到网络地址为203.211.172的路由器,路由器再通过主机ID:103将数据传输给对应主机。

2.1.2 端口号

端口号由16位构成,可分配端口号范围为0~65535,但0~1023是知名端口号,会分配给特定应用程序,所以应当分配此范围之外的值。另外,虽然端口号不能重复,但TCP套接字和UDP套接字不会共用端口号,所以允许重复。例如:某TCP套接字用了9130端口,则其余TCP套接字不能使用此端口,但UDP套接字可以使用9130端口。

2.1.3 bind函数

#include<sts/socket.h>
int bind(int sockfd,struct sockaddr* myaddr,socklen_t addrlen);
成功返回0,失败返回-1

2.1.3.1 sockaddr_in结构体

sockaddr_in:保存IPv4地址信息的结构体

struct sockaddr_in
{
    sa_family_t    sin_family;    //地址族
    uint16_t       sin_port;      //16位TCP/UDP端口号
    struct in_addr sin_addr;      //32位IP地址
    char           sin_zero[8];   //不使用
}

struct in_addr
{
    in_addr_t      s_addr;        //32位IPv4地址
}

struct sockaddr
{
    sa_family_t    sin_family;        //地址族
    char           sa_data[14];       //地址信息
}

数据类型是POSIX(可移植操作系统接口),POSIX是为UNIX系列操作系统设立的标准。

1.sin_family成员

2.sin_port成员

保存16位端口号,是以网络字节序保存的。

3.sin_addr成员

保存32位IP地址信息,也是以网络字节序保存的。

4.sin_zero成员

无特殊含义。只是为了使结构体sockaddr_in和sockaddr结构体大小保持一致插入的成员。

为什么我们平常的使用,要先填充 sockaddr_in结构体,再转换为sockaddr结构体,而不直接填充sockaddr结构体呢?

答:因为sockaddr结构体中sa_data[14]数据的填充很麻烦,其中需包含IP地址和端口号,并且其余部分都要填充为0,才能使用。不如直接使用sockaddr_in结构体,再进行转换。填充复杂的原因是sockaddr结构体并不仅仅为IPv4而设计。

2.1.4 网络字节序

不同CPU中,向内存保存数据的方式有两种,一种是正序,直接保存,一种是倒序保存,这意味着,CPU解析数据的方式也分为两种:

  1. 大端序:高位字节存放到低位地址
  2. 小端序:高位字节存放到高位地址

所以,在数据传输时,必须统一方式,这种方式就称为网络字节序,即统一为大端序。即先把数据统一转化为大端序的格式,再进行网络传输,所以在填充sin_addr成员sin_port成员时需要以网络字节序保存。

2.1.5 字节序转换

主机字节序和网络字节序的相互转换,被称为字节序转换。有以下函数进行转换:

unsigned short htons(unsigned short);    //把short类型数据从主机字节序转换为网络字节序
unsigned short ntohs(unsigned short);    //把short类型数据从网络字节序转换为主机字节序
unsigned long htonl(unsigned long);      //把long类型数据从主机字节序转换为网络字节序
unsigned long ntohl(unsigned long);       //把long类型数据从网络字节序转换为主机字节序

htons中的h表示主机(host)字节序。

htons中的n表示网络(network)字节序。

htons中的s指的是short(short占2个字节,所以常用于端口号的转换)。

htonl中的l值得是long(Linux中long类型占4个字节,所以常用于IP地址的转换)。

2.1.6 网络地址的初始化和分配

2.1.6.1 inet_addr函数

#include <arpa/inet.h>
in_addr_t inet_addr(const char *string);
成功则返回32位大端序整数型值,失败则返回INADDR_NONE

这个函数帮助我们将字符串形式的IP地址转换为32位整数型数据,同时也会进行网络字节序转换。 同时它也会检测无效的IP地址

2.1.6.2 inet_aton函数(Windows不存在此函数)

inet_aton函数和inet_addr函数功能上相同。

#include <arpa/inet.h>
int inet_aton(const char *string,struct in_addr* addr);
成功则返回1,失败则返回0

string:含有需转换的IP地址信息的字符串地址值。

addr:将保存转换结果的in_addr结构体变量的地址值。

2.1.6.3 inet_ntoa函数(和inet_aton函数相反)

#include <arpa/inet.h>
char* inet_ntoa(struct in_addr* addr);
成功则返回转换的字符串地址值,失败则返回-1

将网络字节序32位整数型IP地址转换为字符串形式

注意:在使用此函数时,返回的结果是一个指针,指向字符串信息的地址,当第二次使用这个函数时,这个地址存有的字符串信息会被覆盖掉,所以在使用时,需要立即拷贝保存地址存有的字符串信息

2.1.6.4 INADDR_ANY常数

struct sockaddr_in addr;
memset(&addr,0,sizeof(addr));
...
addr.sin_addr.s_addr=htonl(INADDR_ANY);

INADDR_ANY常数:采用这种方式,会自动获取运行服务器端的计算机的IP地址,不必亲自输入,并且,若同一计算机中分配有多个IP地址(路由器这种),则只要端口号一致,就可以从不同IP地址里接收数据。所以服务器端优先考虑这种方式。

2.1.6.5 WSAStringToAddress函数(只有Windows平台有,不利于兼容性)

各种类型都是针对默认类型的typedef声明。

#include <winsock2.h>
INT WSAStringToAddress
(
    LPTSTR AddressString,INT AddressFamily,LPWSAPROTOCOL_INFO lpProtocolInfo,
    LPSOCKADDR lpAddress,LPINT lpAddressLength
);
成功返回0,失败返回SOCKET_ERROR

AddressString:含有IP地址和端口号的字符串地址值

AddressFamily:第一个参数中地址所属的地址族信息

lpProtocolInfo:设置协议提供者(Provider),默认为NULL
lpAddress:保存地址信息的结构体变量地址值

lpAddressLength:第四个参数中传递的结构体长度所在的变量地址值。

2.1.6.6 WSAAddressToString函数(只有Windows平台有,不利于兼容性)

各种类型都是针对默认类型的typedef声明。

#include <winsock2.h>
INT WSAAddressToString
(
    LPSOCKADDR lpsaAddress,DWORD dwAddressLength,
    LPWSAPROTOCOL_INFO lpProtocolInfo,LPTSTR lpszAddressString,
    LPDWORD lpdwAddressStringLength
);
成功返回0,失败返回SOCKET_ERROR

lpsaAddress:需要转换的地址信息结构体变量地址值

dwAddressLength:第一个参数中结构体的长度
lpProtocolInfo:设置协议提供者(Provider),默认为NULL

lpszAddressString:保存转换结果的字符串地址值
lpdwAddressStringLength:第四个参数中存有地址信息的字符串长度

2.1.6.7 服务器端初始化IP地址时非常明确,为什么还要进行IP的初始化呢?

因为:同一个计算机可能分配有多个IP地址,实际IP地址和计算机安装的NIC数量相等。所以服务器需要决定应接收哪个IP地址传来的数据,所以要服务器端要初始化IP地址。

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

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

相关文章

申请流量卡的时候,你了解过坑吗?

和营业厅办理的手机卡不同&#xff0c;在网上办理流量卡时要考虑的因素很多&#xff0c;比如合约期&#xff0c;优惠期等等&#xff0c;如果如果这几个方面不注意很容易买到套路卡哟。 ​ 所以&#xff0c;我们在办理流量卡是时&#xff0c;不要只看重资费&#xff0c;这几样重…

手机里视频太大怎么压缩?压缩教程分享

现在视频文件的体积越来越大了&#xff0c;动不动就是几个GB起步&#xff0c;如果后期再剪辑处理一下&#xff0c;更是会占据更多的设备空间了&#xff0c;还会导致我们传输受到限制&#xff0c;这时候就需要我们对视频进行压缩处理&#xff0c;下面给大家分享几个简单的方法&a…

Zorin OS 16.3 发布:无缝升级和卓越改进!

导读Zorin OS 团队自豪地宣布了备受期待的 Zorin OS 16.3 版本的发布&#xff0c;这是这个受欢迎的 Linux 发行版的一个里程碑版本。自首次发布以来不到两年时间&#xff0c;Zorin OS 已经获得了庞大的用户群体&#xff0c;截至目前已经有 530 万次下载&#xff0c;而 16.3 版本…

一步步教你实现JWT认证和授权

一步步教你实现JWT认证和授权 前言一、引入二、Token认证与JWT认证的关系三、什么是JWT认证&#xff1f;四、JWT的组成1、头部&#xff08;Header&#xff09;2、载荷&#xff08;Payload&#xff09;3、签名&#xff08;Signature&#xff09; 五、JWT认证的工作流程六、代码举…

Matplotlib 多个子图使用一个图例

1 所有子图的图例相同 **利用函数fig.axe.get_legend_handles_labels()得到图的line和label import matplotlib.pyplot as pltfig plt.figure() axes fig.subplots(nrows2, ncols2)for ax in fig.axes:ax.plot([0, 10], [0, 10], labellinear) # 使用最后一个子图的图例 li…

5V升压到12V2A芯片方案

5V升压到12V2A芯片方案&#xff0c;采用了一款2.7V-18V输入&#xff0c;4.5V-18V输出的峰值10A同步升压芯片&#xff0c;内置了MOS&#xff0c;封装为QFN13。 在电子设备中&#xff0c;经常会遇到需要将低电压提升到较高电压的情况。例如&#xff0c;对于一些需要12V电压供电的…

CAD转kml插件acad2kml分享下载

KML&#xff08;Keyhole Markup Language&#xff09;是一种用于描述地理数据的格式&#xff0c;它由Google公司开发并在2008年成为开放标准。KML使用XML语法&#xff0c;可以用于表示地理点、线、多边形、图像覆盖物以及相关属性信息。 KML是一种用于描述地理数据的开放格式&…

多维时序 | MATLAB实现CNN-BiGRU-Attention多变量时间序列预测

多维时序 | MATLAB实现CNN-BiGRU-Attention多变量时间序列预测 目录 多维时序 | MATLAB实现CNN-BiGRU-Attention多变量时间序列预测预测效果基本介绍模型描述程序设计参考资料 预测效果 基本介绍 MATLAB实现CNN-BiGRU-Attention多变量时间序列预测&#xff0c;CNN-BiGRU-Attent…

如何高效解决“字符串相乘“问题?

&#x1f388;个人主页:&#x1f388; :✨✨✨初阶牛✨✨✨ >&#x1f43b;推荐专栏1: &#x1f354;&#x1f35f;&#x1f32f;C语言初阶 &#x1f43b;推荐专栏2: &#x1f354;&#x1f35f;&#x1f32f;C语言进阶 &#x1f511;个人信条: &#x1f335;知行合一 金句分…

rv1126设置静态ip

开发板配网--------------------------------------------------------------------------------------------- 刚拿到的开发板里面的网络配置大多不可用&#xff0c;此时是无法ping通的&#xff0c;这个时候需要重新修改相关的配置文件&#xff1b; Vi /etc/profile 最后面…

如何将苹果彻底删除视频找回?试试这3种方法

如今是短视频时代&#xff0c;大家通常会使用苹果手机来拍摄视频&#xff0c;以此记录生活中的美好日常。但是大家都知道视频是十分占空间的&#xff0c;这也经常会出现iPhone内存不足&#xff0c;磁盘崩溃的问题。 当遇到iPhone内存不足的情况时&#xff0c;大家往往会选择清…

Failed to execute goal org.apache.maven.plugins

原因&#xff1a; 这个文件D:\java\maven\com\ruoyi\pg-student\maven-metadata-local.xml出了问题 解决&#xff1a; 最简单的直接删除D:\java\maven\com\ruoyi\pg-student\maven-metadata-local.xml重新打包 或者把D:\java\maven\com\ruoyi\pg-student这个目录下所有文件…

【QPSK信号生成】生成正交相移键控信号研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

闪马智能又上榜!

近日&#xff0c;上海市经济和信息化委员会公布了2023年度上半年&#xff08;第30批&#xff09;市级企业技术中心拟认定企业名单。凭借在技术创新方面的突出成就&#xff0c;闪马智能上榜其中。 本次认定由上海市经济和信息化委员会组织开展&#xff0c;综合企业的地位和作用、…

Kubernetes Service 工作原理

本文介绍了 Kubernetes Service 的概念、原理和具体使用。 作者&#xff1a;沈亚军 爱可生研发团队成员&#xff0c;负责公司 DMP 产品的后端开发&#xff0c;爱好太广&#xff0c;三天三夜都说不完&#xff0c;低调低调… 本文来源&#xff1a;原创投稿 爱可生开源社区出品&am…

MAUI+Blazor 如何开启浏览器调试工具

文章目录 前言如何开启调试模式输入快捷键打开浏览器有什么意义&#xff1f; 前言 MAUIBlazor其实就是浏览器套壳&#xff0c;我觉得很有意义&#xff0c;因为现在性能已经不是主要的限制了&#xff0c;很多时候讲究的快速开发。而且MAUIBlazor跨平台的未来感觉实在是太香了。…

基于Gradio的GPT聊天程序

网上很多别人写的&#xff0c;要用账号也不放心。就自己写了一个基于gradio的聊天界面&#xff0c;部署后可以本地运行。 特点&#xff1a; 可以用openai的&#xff0c;也可以用api2d&#xff0c;其他api可以自己测试一下。使用了langchain的库 可以更改模型&#xff0c;会的…

Semantic Kernel 入门系列: Planner 规划器

Semantic Kernel 的一个核心能力就是实现“目标导向”的AI应用。 目标导向 “目标导向”听起来是一个比较高大的词&#xff0c;但是却是实际生活中我们处理问题的基本方法和原则。 顾名思义&#xff0c;这种方法的核心就是先确定目标&#xff0c;然后再寻找实现目标的方法和…

基于R做宏基因组结果的PCoA分析

写在前面 因为公司给的PCA结果效果不佳&#xff0c;决定从中重新挑选部分样本进行再分析 步骤 表格结果预处理 在属水平genus参考原本结果已有的PCA图&#xff0c;尽可能挑选距离较远且聚团的样本 选取不同样本属水平的丰度数据&#xff0c;整理成逗号分隔的csv文件 代码…

Android:自定义沿着曲线轨迹移动

前言 前几天&#xff0c;后台有老铁留言&#xff0c;说有个需求&#xff0c;画两条曲线&#xff0c;中间是一个小球&#xff0c;沿着两条线中间的轨迹从左往右移动&#xff0c;让提供个思路&#xff0c;做为一个极度宠粉的博主&#xff0c;思路不仅要提供&#xff0c;实现方案也…