linux系统编程 socket part2

报式套接字

    • 1.动态报式套接字
    • 2.报式套接字的广播
    • 3.报式套接字的多播
    • 4.UDP协议分析
      • 4.1.丢包原因
      • 4.2.停等式流量控制

接linux系统编程 socket part1

1.动态报式套接字

在之前的例子上,发送的结构体中的名字由定长改变长。可以用变长结构体
变长结构体是由gcc扩展的一种技术,它是指其最后一个成员的长度不固定(flexible array member,也叫柔性数组)。
使用范围:数据长度不固定,例如协议对接中有固定的头结构体,数据结构体不固定。

struct Var_Len_Struct
{int nsize;char buffer[0];// 或者不指定大小 char buffer[];
};

结构体中的最后一个元素:一个没有元素的数组(柔性数组)。我们可以通过动态开辟一个比结构体大的空间,然后让buffer去指向那些额外的空间,这样就可以实现可变长的结构体了。更为巧妙的是,我们甚至可以用nsize存储字符串buffer的长度。

修改代码如下

proto.h
定义NAMEMAX接收名字的最大长度,因为接收方不知道大小,需要按照最大长度接收
使用变长数组,最后一个元素为0或者为空

#ifndef __PROTO_H_
#define __PROTO_H_#define RECVPORT 1986
#define NAMEMAX (512-8-8) // 512为udp包推荐的字节数,8为udp的报头大小,8为结构体中固定长度的大小,即math和chinesestruct msg_t
{uint32_t chinese;uint32_t math;//变长uint8_t name[0];
}__attribute__((packed));# endif

snder.cpp
1.发送的结构体改为结构体指针
2.计算发送的结构体大小 sizeof(struct) + strlen(name)
3.动态申请内存malloc
4.sendto函数相应修改

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <string.h>
#include <arpa/inet.h>#include "proto.h"int main(int argc, char **argv) {int sd;//结构体改为结构体指针msg_t* sendmssg;struct sockaddr_in raddr;if (argc < 3) {perror("Usage");exit(1);}//strlen()不包括字符串结尾的空字符 '\0'//sizeof(argv[2]) 返回的是指针的大小,而不是字符串的长度if (strlen(argv[2]) > NAMEMAX) {std::cout << "name id too long" << std::endl;exit(1);}//创建socketsd = socket(AF_INET, SOCK_DGRAM, 0);if (sd < 0) {perror("socker()");exit(1);}//本地绑定(可以省略)//填写发送消息//变长,先计算结构体的长度int size = sizeof (msg_t) + strlen(argv[2]);//申请内存sendmssg = (msg_t*)malloc(size);if (sendmssg == NULL) {perror("malloc()");exit(1);}memcpy(sendmssg->name, argv[2], strlen(argv[2])+1);sendmssg->chinese = ntohs(100);sendmssg->math = ntohs(100);//对端地址raddr.sin_family = AF_INET;raddr.sin_port = ntohs(RECVPORT);inet_pton(AF_INET, argv[1], &raddr.sin_addr);//发送if (sendto(sd, sendmssg, size, 0, (const sockaddr*)&raddr, sizeof(raddr)) == -1) {perror("sendto()");exit(1);}//关闭close(sd);
}

rcver.cpp
1.接收的结构体改结构体指针
2.按最大长度NAMEMAX计算接收结构体的长度
3.动态分配内存
4.recvfrom函数相应修改

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <string.h>
#include <arpa/inet.h>#include "proto.h"
#define IPSTRSIZE        64int main() {// 套接字描述符int sd;// laddr -- local address -- 本机地址// raddr -- remote address -- 对端地址sockaddr_in laddr, raddr;socklen_t raddr_len;// 结构体指针,存储接收到的结构体msg_t* mssg;// 存储对端地址,点分式char ipstr[IPSTRSIZE];//创建socket,创建协议为ipv4的报式套接字,0为默认协议,即UDPsd = socket(AF_INET, SOCK_DGRAM, 0);if (sd < 0) {perror("socker()");exit(1);}//填写本机的地址信息laddr.sin_family = AF_INET;//ip地址和网络端口号是要通过网络发送过去的,所以需要考虑字节序的问题,也就是htonsladdr.sin_port = htons(RECVPORT);// 因为本机的ip地址有可能会变化,为了避免ip地址每一次变化,都要进来修改,所以给它匹配一个万能地址0.0.0.0// 对"0.0.0.0"的定义是any address.就是说在当前绑定阶段,本机的ip地址是多少,这四个0就会自动换成当前的ip地址.inet_pton(AF_INET, "0.0.0.0", &laddr.sin_addr.s_addr);//绑定接收的ip地址和端口号if (bind(sd, (const sockaddr*)&laddr, sizeof(laddr)) < 0) {perror("sendto()");exit(1);}// 接收// !!!!这里一定要初始化对端地址的大小!!!raddr_len = sizeof(raddr);//不知道对端的地址大小,按最大的来接int size = sizeof(msg_t) + NAMEMAX - 1; mssg = (msg_t*)malloc(size);while (1) {if (recvfrom(sd, mssg, size, 0, (sockaddr*)&raddr, &raddr_len) < 0) {perror("recvfrom()");exit(1);}inet_ntop(AF_INET, &raddr.sin_addr, ipstr, IPSTRSIZE);std::cout << "---------recive message from " << std::string(ipstr) << ":" << ntohs(raddr.sin_port) << "---------" << std::endl;// 单字节传输不涉及到大端小端的存储情况std::cout << "name" << ":" << mssg->name << std::endl;std::cout << "math" << ":" << ntohs(mssg->math) << std::endl;std::cout << "chinese" << ":" << ntohs(mssg->chinese) << std::endl;}//关闭close(sd);exit(1);
}
vratdrh7771.rsv.ven.veritas.com [60]: ./snder 10.85.171.130 "hahhaahha"
vratdrh7771.rsv.ven.veritas.com [61]: ./snder 10.85.171.130 "44kkkkk"vratdrh7771.rsv.ven.veritas.com [71]: ./rcver
---------recive message from 10.85.171.130:33261---------
name:hahhaahha
math:100
chinese:100
---------recive message from 10.85.171.130:36716---------
name:44kkkkkha
math:100
chinese:100

2.报式套接字的广播

在使用TCP/IP 协议的网络中,主机标识段host ID 为全1 的 IP 地址为广播地址。

广播数据有如下特点:

  • TCP/IP协议栈中,传输层只有UDP可以广播,TCP没有广播的概念
  • UDP广播不需要经过路由器转发,因为路由器不会转发广播数据

套接字机制提供了两个套接字选项接口来控制套接字行为。一个接口用来设置选项,另一个接口可以查询选项的状态。

GETSOCKOPT(2)                                          Linux Programmer's Manual                                         GETSOCKOPT(2)NAMEgetsockopt, setsockopt - get and set options on socketsSYNOPSIS#include <sys/types.h>          /* See NOTES */#include <sys/socket.h>int getsockopt(int sockfd, int level, int optname,void *optval, socklen_t *optlen);int setsockopt(int sockfd, int level, int optname,const void *optval, socklen_t optlen);DESCRIPTIONgetsockopt()  and  setsockopt() manipulate options for the socket referred to by the file descriptor sockfd.  Options may existat multiple protocol levels; they are always present at the uppermost socket level.
  • level: 标识了选项应用的协议。
    • 如果选项是通用的套接字层次选项,则 level 设置成SOL_SOCKET。否则,level设置成控制这个选项的协议编号
    • 对于TCP,level是IPPROTO_TCP
    • 对于IP,level是IPPROTO_IP
  • optname: 需设置的选项
  • optval:根据选项的不同指向一个数据结构或者一个整数。一些选项是on/off开关。如果整数非0,则启用选项。如果整数为0,则禁止选项。
  • optlen:指定了optval指向的对象的大小。

代码示例

snder.cpp:设置套接字,打开广播选项,并向广播地址255.255.255.255发送数据报

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <string.h>
#include <arpa/inet.h>#include "proto.h"int main() {int sd;msg_t sendmssg;struct sockaddr_in raddr;//创建socketsd = socket(AF_INET, SOCK_DGRAM, 0);if (sd < 0) {perror("socker()");exit(1);}//本地绑定(可以省略)//设置套接字,打开广播//不同的层面封装了不同的属性,可以用man 7查看//man 7 socket 找 socket option//man 7 udp udp层可以改进的socket option//man 7 ip...//man 7 tcpint val = 1;if(setsockopt(sd, SOL_SOCKET, SO_BROADCAST, &val, sizeof(val)) < 0) {perror("setsockopt()");exit(1);}//填写发送消息memset(&sendmssg, '\0', sizeof(sendmssg));//strcpy(sendmssg.name, "tracy");memcpy(sendmssg.name, "tracy", sizeof("tracy"));sendmssg.chinese = ntohs(100);sendmssg.math = ntohs(100);//对端地址raddr.sin_family = AF_INET;raddr.sin_port = ntohs(RECVPORT);inet_pton(AF_INET, "255.255.255.255", &raddr.sin_addr);//发送if (sendto(sd, &sendmssg, sizeof(sendmssg), 0, (const sockaddr*)&raddr, sizeof(raddr)) < 0) {perror("sendto()");exit(1);}//关闭close(sd);
}

rcver.cpp:设置套接字,打开广播选项,如果不打开,可能收到,可能收不到

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <string.h>
#include <arpa/inet.h>#include "proto.h"
#define IPSTRSIZE        64int main() {// 套接字描述符int sd;// laddr 本机地址// raddr 对端地址sockaddr_in laddr, raddr;// 存储接收到的结构体msg_t mssg;// 存储对端地址,点分式char ipstr[IPSTRSIZE];// 创建socket,创建协议为ipv4的报式套接字,0为默认协议,即UDPsd = socket(AF_INET, SOCK_DGRAM, 0);if (sd < 0) {perror("socker()");exit(1);}int val = 1;if(setsockopt(sd, SOL_SOCKET, SO_BROADCAST, &val, sizeof(val)) < 0) {perror("setsockopt()");exit(1);}// 填写本机的地址信息laddr.sin_family = AF_INET;// ip地址和网络端口号是要通过网络发送过去的,所以需要考虑字节序的问题,也就是htonsladdr.sin_port = htons(RECVPORT);// 因为本机的ip地址有可能会变化,为了避免ip地址每一次变化,都要进来修改,所以给它匹配一个万能地址0.0.0.0// 对"0.0.0.0"的定义是any address.就是说在当前绑定阶段,本机的ip地址是多少,这四个0就会自动换成当前的ip地址.inet_pton(AF_INET, "0.0.0.0", &laddr.sin_addr.s_addr);//绑定接收(本机)的ip地址和端口号if (bind(sd, (const sockaddr*)&laddr, sizeof(laddr)) < 0) {perror("sendto()");exit(1);}// 接收// !!!!这里一定要初始化对端地址的大小!!!socklen_t addr_len = sizeof(raddr);while (1) {if (recvfrom(sd, (void*)&mssg, sizeof(mssg), 0, (sockaddr*)&raddr, &addr_len) < 0) {perror("recvfrom()");exit(1);}inet_ntop(AF_INET, &raddr.sin_addr, ipstr, IPSTRSIZE);std::cout << "---------recive message from " << std::string(ipstr) << ":" << ntohs(raddr.sin_port) << "---------" << std::endl;// 单字节传输不涉及到大端小端的存储情况std::cout << "name" << ":" << mssg.name << std::endl;std::cout << "math" << ":" << ntohs(mssg.math) << std::endl;std::cout << "chinese" << ":" << ntohs(mssg.chinese) << std::endl;}//关闭close(sd);exit(1);
}

proto.h

#ifndef __PROTO_H_
#define __PROTO_H_
#define RECVPORT 1986
#define NAMESIZE 11struct msg_t
{//定长,不可能有负值uint8_t name[NAMESIZE];uint32_t chinese;uint32_t math;
}__attribute__((packed));# endif

注意:如果仍然接收不到,可以查看防火墙

vratdrh7771.rsv.ven.veritas.com [70]: ./rcver
---------recive message from 10.85.171.130:43497---------
name:tracy
math:100
chinese:100

3.报式套接字的多播

多播地址,也叫组播地址,组播报文的目的地址使用D类IP地址, D类地址不能出现在IP报文的源IP地址字段。组播地址可以分为四类:

  • 224.0.0.0~224.0.0.255为预留的组播地址(永久组地址),地址224.0.0.0保留不做分配,其它地址供路由协议使用;
  • 224.0.1.0~224.0.1.255是公用组播地址,可以用于Internet;
  • 224.0.2.0~238.255.255.255为用户可用的组播地址(临时组地址),全网范围内有效;
  • 239.0.0.0~239.255.255.255为本地管理组播地址,仅在特定的本地范围内有效。

代码示例

proto.h:设置一个约定的多播地址

#ifndef __PROTO_H_
#define __PROTO_H_#define MGROUP   "224.2.2.2"
#define RECVPORT 1986
#define NAMESIZE 11struct msg_t
{//定长,不可能有负值uint8_t name[NAMESIZE];uint32_t chinese;uint32_t math;
}__attribute__((packed));# endif

snder.c:创建多播组

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <string.h>
#include <arpa/inet.h>
#include <net/if.h>#include "proto.h"int main(int argc, char **argv) {int sd;msg_t sendmssg;struct sockaddr_in raddr;if (argc < 2) {perror("uasge()");exit(1);}//创建socketsd = socket(AF_INET, SOCK_DGRAM, 0);if (sd < 0) {perror("socker()");exit(1);}//设置套接字,创建多播组//man 7 ipip_mreqn mreq;//multicast group addressinet_pton(AF_INET, MGROUP, &mreq.imr_multiaddr);//local本机addressinet_pton(AF_INET, "0.0.0.0", &mreq.imr_address);//网络索引号mreq.imr_ifindex = if_nametoindex("ens192");//设置套接字,创建多播组if(setsockopt(sd, IPPROTO_IP, IP_MULTICAST_IF, &mreq, sizeof(mreq)) < 0) {perror("setsockopt()");exit(1);}//填写发送消息memset(&sendmssg, '\0', sizeof(sendmssg));//strcpy(sendmssg.name, "tracy");memcpy(sendmssg.name, argv[1], sizeof(argv[1]) + 1);sendmssg.chinese = ntohs(100);sendmssg.math = ntohs(100);//对端地址raddr.sin_family = AF_INET;raddr.sin_port = ntohs(RECVPORT);inet_pton(AF_INET, MGROUP, &raddr.sin_addr);//发送if (sendto(sd, &sendmssg, sizeof(sendmssg), 0, (const sockaddr*)&raddr, sizeof(raddr)) < 0) {perror("sendto()");exit(1);}//关闭close(sd);
}

其中,可以使用命令查看网络设备的索引号:

ip ad sh

如下,1、2为索引号,lo, ens192为设备名

vratdrh7771.rsv.ven.veritas.com [60]: ip ad sh
1: lo: <LOOPBACK,UP,LOWER_UP> .....
........
2: ens192: <BROADCAST,MULTICAST,UP,LOWER_UP> ..... 
........

或者可以通过下列函数来获取网络设备名的索引编号:

#include <net/if.h>
unsigned int if_nametoindex(const char *ifname);

rcver.cpp:加入多播组

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <string.h>
#include <arpa/inet.h>
#include <net/if.h>#include "proto.h"
#define IPSTRSIZE        64int main() {// 套接字描述符int sd;// laddr 本机地址// raddr 对端地址sockaddr_in laddr, raddr;// 存储接收到的结构体msg_t mssg;// 存储对端地址,点分式char ipstr[IPSTRSIZE];// 创建socket,创建协议为ipv4的报式套接字,0为默认协议,即UDPsd = socket(AF_INET, SOCK_DGRAM, 0);if (sd < 0) {perror("socker()");exit(1);}//加入多播组ip_mreqn mreq;inet_pton(AF_INET, MGROUP, &mreq.imr_multiaddr);inet_pton(AF_INET, "0.0.0.0", &mreq.imr_address);mreq.imr_ifindex = if_nametoindex("ens192");if(setsockopt(sd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) {perror("setsockopt()");exit(1);}// 填写本机的地址信息laddr.sin_family = AF_INET;// ip地址和网络端口号是要通过网络发送过去的,所以需要考虑字节序的问题,也就是htonsladdr.sin_port = htons(RECVPORT);// 因为本机的ip地址有可能会变化,为了避免ip地址每一次变化,都要进来修改,所以给它匹配一个万能地址0.0.0.0// 对"0.0.0.0"的定义是any address.就是说在当前绑定阶段,本机的ip地址是多少,这四个0就会自动换成当前的ip地址.inet_pton(AF_INET, "0.0.0.0", &laddr.sin_addr.s_addr);//绑定接收(本机)的ip地址和端口号if (bind(sd, (const sockaddr*)&laddr, sizeof(laddr)) < 0) {perror("sendto()");exit(1);}// 接收// !!!!这里一定要初始化对端地址的大小!!!socklen_t addr_len = sizeof(raddr);while (1) {if (recvfrom(sd, (void*)&mssg, sizeof(mssg), 0, (sockaddr*)&raddr, &addr_len) < 0) {perror("recvfrom()");exit(1);}inet_ntop(AF_INET, &raddr.sin_addr, ipstr, IPSTRSIZE);std::cout << "---------recive message from " << std::string(ipstr) << ":" << ntohs(raddr.sin_port) << "---------" << std::endl;// 单字节传输不涉及到大端小端的存储情况std::cout << "name" << ":" << mssg.name << std::endl;std::cout << "math" << ":" << ntohs(mssg.math) << std::endl;std::cout << "chinese" << ":" << ntohs(mssg.chinese) << std::endl;}//关闭close(sd);exit(1);
}

运行结果

vratdrh7771.rsv.ven.veritas.com [109]: ./rcver
---------recive message from 10.85.171.130:48514---------
name:mike
math:100
chinese:100
---------recive message from 10.85.171.130:39871---------
name:hahah
math:100
chinese:100

多播中有一个特殊的 ip 地址(224.0.0.1),它表示,所有支持多播的地址默认都存在这个组当中,并且无法离开。如果 snder 方向这个 ip 地址发送信息,就相当于向 255.255.255.255 上发消息。

4.UDP协议分析

4.1.丢包原因

UDP丢包并不是因为TTL,TTL是当前包的要跳转的路由的个数,linux环境下一般默认为64,Windows一般为128,一般情况下完全足够。丢包其实是由于阻塞造成的。路由有等待队列,并不是我的数据包从本路由到下一个路由是无条件发送的,而是有等待队列,这个等待队列会有丢包的算法实现。比如当前队列已经排列百分之N的容量时,就会随机的丢包等操作。
解决:闭环流控(停等式流控)

4.2.停等式流量控制

问题1 发送端发送后,接收端返回ACK,发送端会在一段时间后才能收到消息
在这里插入图片描述
问题2:发送端发送消息后丢包了,在一定时间(RTT)后没有收到接收端ACK,则重新发送消息
在这里插入图片描述
问题3:发送端发送消息后,接收端收到了数据,并且发送了ACK,但是ACK数据丢了,在一定时间后没有收到接收端ACK,则重新发送消息。接收端如何判断收到的包已经收到过了(data包加编号),则直接放弃该包,直接回复ACK。
在这里插入图片描述
问题4:如图 d2 丢包,ACK1 延迟回复给了发送端,则发送端认为d2发送成功,继续发d3,实际接受端是没有收到过d2的。所以ACK也要加编号,否则就可能出现这类问题。
在这里插入图片描述

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

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

相关文章

【RK android7.1 开机进入主界面前短暂黑屏或者白屏问题】

RK android7.1 开机进入主界面前短暂黑屏或者白屏问题 问题描述解决方法郑重声明:本人原创博文,都是实战,均经过实际项目验证出货的 转载请标明出处:攻城狮2015 Platform: Rockchip OS:Android 7.1.2 Kernel: 3.10 问题描述 开机进入主界面得一瞬间,launcher短暂黑屏或者白屏…

【python从入门到精通】--第一战:安装python

&#x1f308; 个人主页&#xff1a;白子寰 &#x1f525; 分类专栏&#xff1a;python从入门到精通&#xff0c;魔法指针&#xff0c;进阶C&#xff0c;C语言&#xff0c;C语言题集&#xff0c;C语言实现游戏&#x1f448; 希望得到您的订阅和支持~ &#x1f4a1; 坚持创作博文…

MySQL中的基本SQL语句

文章目录 MySQL中的基本SQL语句查看操作创建与删除数据库和表修改表格数据库用户管理 MySQL中的基本SQL语句 查看操作 1. 查看有哪些数据库 show databases; 2.切换数据库 use 数据库名;比如切换至 mysql数据库 use mysql;3.查看数据库中的表 show tables;4.查看表中…

Linux_进程概念_冯诺依曼_进程概念_查看进程_获取进程pid_创建进程_进程状态_进程优先级_环境变量_获取环境变量三种方式_3

文章目录 一、硬件-冯诺依曼体系结构二、软件-操作系统-进程概念0.操作系统做什么的1.什么叫做进程2.查看进程3.系统接口 获取进程pid- getpid4.系统接口 获取父进程pid - getppid5.系统接口 创建子进程 - fork1、手册2、返回值3、fork做了什么4、基本用法 6.进程的状态1、进程…

GAMES101 学习4

材质和外观 材质 BRDF 漫反射 任何方向的光进来都会被均匀的反射到周围各个不同的方向上去 假设能量守恒&#xff0c;那么 Li Lo&#xff0c;这之后BRDF就 &#xff0c;就可以定义一个反照率 &#xff08;Albeo&#xff09; - &#xff0c;在&#xff08;0 - 1&#xff0…

国产大模型KimiChat起飞了!200万字内测开启,AI助手能力大提升!

会议之眼 快讯 Kimi Chat是北京月之暗面科技有限公司推出的支持输入20万汉字的智能助手产品。其背后的技术是一个体量为千亿参数的大模型。Kimi Chat的推出是月之暗面“登月计划”的一部分&#xff0c;旨在为未来的多模态版本产品提供基础&#xff0c;并最终在大模型领域打造面…

Spring Security之认证过滤器

前言 上回我们探讨了关于Spring Security&#xff0c;着实复杂。这次咱们聊的认证过滤器就先聊聊认证功能。涉及到多方协同的功能&#xff0c;咱分开聊。也给小伙伴喘口气&#xff0c;嘻嘻。此外也是因为只有登录认证了&#xff0c;才有后续的更多功能集成的可能。 认证过滤器…

ES的集群节点发现故障排除指南(1)

本文是ES官方文档关于集群节点发现与互联互通的问题排查指南内容。 英文原文&#xff08;官网&#xff09; 集群节点发现是首要任务 集群互连&#xff0c;重中之重&#xff01; 在大多数情况下&#xff0c;发现和选举过程会迅速完成&#xff0c;并且主节点会长时间保持当选状…

生骨肉冻干真的对猫身体好吗?排行榜靠前对猫身体好的生骨肉冻干推荐

随着科学养猫知识的广泛传播&#xff0c;生骨肉冻干喂养正逐渐受到养猫人士的青睐。生骨肉冻干真的对猫身体好吗&#xff1f;生骨肉冻干不仅符合猫咪的饮食天性&#xff0c;还能提供全面均衡的营养&#xff0c;有助于维护猫咪的口腔和消化系统健康。然而&#xff0c;许多猫主人…

Open CASCADE学习|最小二乘法拟合直线

最小二乘法&#xff0c;又称最小平方法&#xff0c;起源于十八世纪的大航海探索时期&#xff0c;发展于天文领域和航海领域。其历史可以追溯到法国科学家马里勒让德于1805年首次提出这一概念&#xff0c;而1809年&#xff0c;高斯在他的著作《天体运动论》中也提出了最小二乘法…

xilinx FPGA 除法器ip核(divider)的学习和仿真(Vivado)

在设计中&#xff0c;经常出现除法运算&#xff0c;实现方法&#xff1a; 1、移位操作 2、取模取余 3、调用除法器IP核 4、查找表 简单学习除法器IP。 网上很多IP翻译文档&#xff0c;不详细介绍&#xff0c;记录几个重要的点&#xff1a; 1、三种算法模式(不同模式所消耗的资…

【Linux 进程概念】

【Linux 进程概念】 冯诺依曼体系结构冯诺依曼结构简要解释&#xff1a;你用QQ和朋友聊天时数据的流动过程 操作系统(OperatorSystem)概念设计OS的目的定位操作系统的上下层都分别是什么如何理解“管理"总结 进程基本概念描述进程-PCBtask_ struct内容 组织进程查看进程通…

大模型围剿战:Kimi如何在免费与盈利之间找到平衡?

文 | 大力财经 在近期的互联网科技领域&#xff0c;一款名为Kimi的国产大型AI模型引起了广泛关注。随着Kimi的火爆&#xff0c;国内的大型科技公司纷纷开始关注并投入到长文本处理技术的竞争中。 阿里巴巴、360等知名企业纷纷宣布了他们的长文本处理能力&#xff0c;分别达到…

网络——套接字编程UDP

目录 端口号 源端口号和目的端口号 认识TCP协议和UDP协议 网络字节序 socket编程接口 socket常见接口 sockaddr结构 UDP socket bind recvfrom sendto 编写客户端 绑定INADDR_ANY 实现聊天功能 端口号 在这之前我们已经说过源IP地址和目的IP地址&#xff0c;还有…

微信小程序的页面制作---常用组件及其属性2

一、标签栏taBar 在全局配置文件app.json中添加taBar配置&#xff0c;可实现标签栏配置。标签栏最少2个&#xff0c;最多5个 &#xff08;1&#xff09;如何配置标签栏&#xff1f; 1》先建多个文件&#xff0c;&#xff08;以我的index&#xff0c;list&#xff0c;myform文…

最近很火的游戏,人渣/SCUM(更新V0.9.517.81845)

包含DLC • SCUM Deluxe • SCUM Deluxe 2 • SCUM Danny Trejo • SCUM Hair Deluxe 1 • SCUM Luis Moncada • SCUM Charms 1 • SCUM Weapon Skins 1 中文设置 OPTIONS-LANGUAGE-中文(简体) 特别提示 • 通过“\SCUM\Binaries\Win64\SCUM.exe”启动游戏 • 如果…

Microsoft Excel 快捷键 (keyboard shortcut - hotkey)

Microsoft Excel 快捷键 [keyboard shortcut - hotkey] References 表格内部换行快捷键 Alt Enter 快速将光标移到表末 Ctrl End 快速将光标移到表首 Ctrl Home References [1] Yongqiang Cheng, https://yongqiang.blog.csdn.net/

人工智能(Educoder)-- 搜索技术 -- 盲目式搜索

第1关&#xff1a;盲目搜索之宽度优先搜索算法 任务描述 本关任务&#xff1a;给定迷宫地图以及在迷宫中的起始位置&#xff0c;利用宽度优先搜索算法求解走出迷宫的最短路径长度&#xff0c;走出迷宫意味着达到迷宫地图的边界&#xff08;所有位置下标0开始&#xff09;。 …

水电站泄洪预警广播系统方案

一、行业背景 近年来由于危险河道管理措施不到位&#xff0c;调峰电站泄水风险长期存在&#xff0c;信息通报制度缺失以及民众安全警觉性不高等因素导致的水电站在泄洪时冲走下游河道游客以及人民财产的事故频发。 我司通过物联网、云计算、大数据、人工智能等技术手段&#x…

不能从所选图层建立3d模型--模大狮模型网

在Revit中&#xff0c;从所选图层直接创建3D模型并不是一个常规的操作方式。通常情况下&#xff0c;你需要手动创建文字或者图形&#xff0c;然后将其转换为3D模型。 如果你有一个平面上的文字或图形&#xff0c;想要将其转换为3D模型&#xff0c;你可以使用以下步骤&#xff1…