【网络】socket——预备知识 | 套接字 | UDP网络通信

🐱作者:一只大喵咪1201
🐱专栏:《网络》
🔥格言:你只管努力,剩下的交给时间!
图

在前面本喵对网络的整体轮廓做了一个大概的介绍,比如分层,协议等等内容,现在我们直接进入socket(套接字)编程,先来感受到网络编程。

UDP套接字

  • 🍚预备知识
    • 🥣源IP地址和目的IP地址
    • 🥣端口号port
      • 网络通信的本质
    • 🥣认识TCP/UDP协议
    • 🥣网络字节序
      • 主机和网络的字节序转换函数
  • 🍚socket套接字
    • 🥣socket常见系统调用
    • 🥣sockaddr结构体
  • 🍚UDP网络编程
    • 🥣服务端实现
    • 🥣客户端实现
  • 🍚用户层与网络的解耦
  • 🍚总结

🍚预备知识

🥣源IP地址和目的IP地址

我们知道,在网络通信中,存在两套地址,一套是IP地址,另一套是MAC地址。

  • IP地址:标识计算机在网络中的唯一性。

而IP地址又分为源IP地址和目的IP地址:

  • 源IP地址:标识网络通信发起方。
  • 目的IP地址:标识网络通信的接收方。

在网络通信的报文中,其中报头包含着源IP和目的IP

🥣端口号port

图
如上图所示,报文从用户A的计算机传送到了用户B的计算机,但是网络通信的目的就是将报文从一台计算机传送到另一台计算机吗?

  • 将数据从计算机A传送到计算机B是手段,并不是网络通信的目的。
  • 真正进行通信的是用户A和用户B,也就是计算机A上的某个应用程序和计算机B上的某个应用程序之间在通信

网络通信的目的就是让两台计算机上的两个进程在进行通信。

IP地址可以标识两台计算机的唯一性,但是每台计算机上会存在大量的进程,如何保证计算机A某个进程发送的数据能让计算机B指定的进程接收到呢?

换句话说,如何标识一台计算机上进程的唯一性呢?

采用端口号port来标识计算机上进程的唯一性

  • 端口号是一个2字节16位的整数。
  • 端口号用来标识一个进程,告诉操作系统要把数据交给哪一个进程。
  • 一个端口号只能被一个进程占用。

现在我们有用来标识计算机在网络中唯一性的IP地址,又有用来标识进程在计算机中唯一性的端口号port。

  • 全网唯一进程 = IP地址(全网主机唯一性) + 端口号port(该主机上进程唯一性)
  • socket(套接字) = IP地址 + 端口号port。

所以要想两个进程间实现通信,必须各自有各自的套接字。

网络通信的本质

网络通信实际上是两台计算机或者多台计算机上的进程之间在通信,和我们之前Linux学习的进程间通信的区别在于进程位于不同的计算机上。

  • 网络通信的本质:进程间通信。
  • 要实现进程间通信,必须有共享资源,而网络通信中的网络就是共享资源。
  • 网络通信其实就是在做IO,我们上网的所有行为就两种:a. 把数据发出去。 b. 把数据读回来。
  • Linux下一切皆文件,所以网络在系统中也是一个"文件",也有struct结构体,也有文件描述符。

我们知道,每个进程都有一个pid来标识它在当前计算机上的唯一性,为什么网络中还需要一个端口号port来标识进程的唯一性呢?不能用pid吗?

在技术实现上是完全可以用pid的,所以就需要考虑为什么偏偏就用了端口号port

  • 系统是系统,网络是网络,系统使用pid,网络使用port来标识进程的唯一性,实现了系统与网络的解耦
  • 不是所有进程都提供网络服务或者网络请求的,但是所有的进程都需要pid,只有需要网络的进程才会分配一个port
  • 客户端需要能够直接找到服务器的进程,服务器进程的唯一性不能做任何改变。

比如我们平时使用的QQ,我们手机上的QQ都是客户端,我们打开QQ使用都是在向服务器上的QQ进程发起网络请求,而这个服务器位腾讯公司,服务进程根据用户的网络请求再做出对应的反馈交给用户。

  • 我们下载了某个应用程序以后,该程序里就绑定了服务端对应进程的IP地址和端口号。
  • 所以使用应用程序的时候,就能精准的和服务端上对应的进程进行网络通信。

服务器的IP地址并不会随意变化,为了保证客户端每次都能找到服务端的进程,服务端的port也不能变化。

  • 如果使用pid来代替端口号的话,服务器每重启一次,服务进程的pid值就会改变,客户端就无法找到服务进程了。

绑定了port的进程PCB会被维护在一个哈希表中,port就是key值,操作系统能够根据key值找到对应的PCB,然后再执行它。

🥣认识TCP/UDP协议

这两个协议的具体原理和细节在后面本喵会详细讲解,这里仅需要大概了解一下它两的特定即可。

TCP协议:(Transmission Control Protocol 传输控制协议)。

  • 传输层协议。
  • 需要通信双方建立连接。
  • 是一种可靠传输,不会发生丢包等问题。
  • 面向字节流。

UDP协议:(User Datagram Protocol 用户数据报协议)。

  • 传输层协议。
  • 不需要通信双方建立连接,直接发生即可。
  • 不可靠传输,可能会发生丢包等问题。
  • 描写数据报。

具体这些特点是什么意思,以后会讲解到,这里只需要记住以上内容即可。

🥣网络字节序

我们的计算机分为大端机和小端机,不同的电脑型号就不一样,两台计算机大小端不同,接收到的数据解释出来意义也不同。

  • 规定:网络中的字节序都采用大端

如果你的计算机是大端机,那么就可以直接向网络中发数据和从网络中接收数据,不用做转换。

如果你的计算机是小端机,那么在向网络中发送数据时,需要先将数据转换成大端,再发送到网络中。从网络中接收下来的数据,需要先转换成小端再使用。

此时就存在两个问题:

  • 自己的电脑是大端还是小端?还需要自己去判断一下。
  • 如果自己的电脑是小端,需要自己去将数据转换成大端。

这两个问题虽然我们自己能解决,但是比较繁琐,而且很容易出错,所以操作系统提供了相应的接口来进行大小端转换:

主机和网络的字节序转换函数

#include <arpa/inet.h>//必须包含的头文件
// 主机序列转网络序列
uint32_t htonl(uint32_t hostlong);//将主机上unsigned int类型的数据转换成对应网络字节序
uint16_t htons(uint16_t hostshort);//将主机上unsigned short类型的数据转换成对应网络字节序
// 网络序列转主机序列
uint32_t ntohl(uint32_t netlong);//将从网络中读取的unsigned int类型的数据转换成当前计算机字节序
uint16_t ntohs(uint16_t netshort);//将从网络中读取的unsigned short类型的数据转换成当前计算机字节序
  • 这些函数名很好记,h表示host,代表着主机,n表示network,代表着网络,s表示unit16_t,l表示uint32_t
  • 如果主机是小端字节序,这些函数将参数做相应的大小端转换然后返回。
  • 如果主机是大端字节序,这些 函数不做转换,将参数原封不动地返回。

🍚socket套接字

🥣socket常见系统调用

  1. socket:

图
socket系统调用专门用来创建套接字,在创建的时候指定使用哪种通信协议。

参数解释:

  • int domain

这是地址族,用来指定创建的套接字进行的是网络通信还是本地通信。

图
该参数可以填上图所示中的任何一个,经常使用的是AF_INET表示使用IPv4的网络套接字进行网络通信

  • int type

这是用来指定socket提供的能力类型,比如是面向字节流还是面向用户数据报。

图
该参数可以使用上图中的任何一个,其中画红色框的是面向字节流和面向用户数据报,也就是TCP和UDP。

  • int protocol

该参数是用来指定具体的协议名的,比如指定TCP或者DUP,但是根据前两个参数就可以确定使用哪个协议了,这个一般设置为0即可。

  • 返回值 int
  • 成功返回一个int类型的值,其实就是一个文件描述符sockfd
  • 失败返回-1,并且设置错误码errno

  1. bind

图
bind用来将IP地址和端口号port创建的socket套接字绑定,也就是将IP地址和端口号port和系统绑定。

参数解释:

  • int sockfd

使用socket()返回的文件描述符sockfd,用来指定绑定哪个套接字。

  • const struct sockaddr * addr

struct sockaddr是一个结构体。

  • socklen_t addrlen

这个参数是表示sockaddr结构体大小的,单位是字节,socklen_t本质是unsigned int类型的32位变量。

  • 返回值int

成功返回0,失败返回-1,并且设置错误码errno


  1. 其他几个接口
// 开始监听socket (TCP, 服务器)
int listen(int socket, int backlog);
// 接收请求 (TCP, 服务器)
int accept(int socket, struct sockaddr* address,
socklen_t* address_len);
// 建立连接 (TCP, 客户端)
int connect(int sockfd, const struct sockaddr *addr,
socklen_t addrlen);

这几个接口的是TCP协议才会用到,后面本喵再详细讲解。

🥣sockaddr结构体

套接字有很多种类型,常见的有三种:

  • 网络套接字:用户跨主机之间的通信,也能支持本地通信。
  • 原始套接字:可以跨过传输层(TCP/UDP)访问底层的数据。
  • 域间套接字:只能在本地通信。

这些套接字的应用场景完全不同,所以不同种类的套接字就对应一套系统调用接口,所以三套就会对应三套不同的接口。

网络套接字:

struct sockaddr_in {short int sin_family;           // 地址族,一般为AF_INETunsigned short int sin_port;    // 端口号,网络字节序struct in_addr sin_addr;        // IP地址unsigned char sin_zero[8];      // 用于填充,使sizeof(sockaddr_in)等于16
};

通过sockaddr_in结构体,将IP地址,端口号,以及网络通信AF_INET通过系统调用bind与系统绑定,从而进行网络通信。

域间套接字:

struct sockaddr_un {sa_family_t sun_family;       /* AF_UNIX */char sun_path[108];    /* 带有路径的文件名 */
};

sockaddr_un只有域间通信方式AF_UNIX以及域间通信的路径名。


而设计者为了方便使用,无论是网络通信还是域间通信,都使用一套接口,通过设置不同参数来解决所有通信场景。

图
sockaddr_insockaddr_un是用于网络通信和域间通信两个不同的通信场景,它们的区别就在于结构体起始处的16位地址类型不同,网络通信使用AF_INET,域间通信使用AF_UNIX

  • 但由于要使用一套接口,所以此时无论哪种通信,都使用sockaddr结构体。
  • 在填充IP地址,端口号,以及地址类型的时候,仍然是对sockaddr_in进行填充。
  • 在使用bind系统调用时,将sockaddr_in强转成sockaddr类型,在函数内部它会根据前两个字节自行判断是什么类型的通信,然后再强制转回去。

可以将sockaddr看成是基类,把sockaddr_insockaddr_un看出是派生类,此时就构成了多态体系。


🍚UDP网络编程

网络通信一定是双方的,一端是服务端(Server)接收数据,另一端是客户端(Client)发送数据。

🥣服务端实现

网络通信首先就是要有套接字,也就是要有IP地址和端口号port,所以我创建的服务器中必须有这两项。

class udpSever
{
private:uint16_t _port;//服务进程端口号string _ip;//服务器ip地址int _sockfd;//socket返回值
};

使用系统调用socket()时,相当于打开了服务器的网卡,在系统中会创建一个struct file类型的结构体,来描述网卡的信息,和文件操作类型,所以会返回一个sockfd,这其实就是一个文件描述符。所以服务器的成员变量有上面代码所示的三个。

图

在构造函数构造服务器对象的时候,需要传入端口号port和IP地址。

  • 端口号port是指定的,一旦指定就不能再更改,这里本喵指定为8080。
  • IP地址是服务器的IP地址。

图
shell上使用指令ifconfig,可以看到服务器的IP信息,如上图所示,红色框中的inet:127.0.0.1是本地环回,使用这个IP地址不会经过物理层将数据发出去,而且从链路层又返回到了当前计算机。

图

如上图所示,数据从当前计算机上的客户端进程流向了当前计算机上的服务的进程。所以可以使用本地环回IP地址来进行测试。

但是我们知道,每台计算机在网络中都有一个公网IP,这个IP和本地回环不一样,还有局域网IP等等。存在这么多IP,都标识着服务器这一台计算机。

如果服务器仅仅绑定本地换行的IP地址,当另一台计算机的服务端想要通过公网IP地址发起申请的时候,由于两个IP地址不一样,所以就会忽略客户端的申请。

  • 为了能够让服务端接收所有的网络请求,将服务器的IP地址绑定为0.0.0.0,转换成uint32_t类型就是0。

其实每台计算机绑定的都不止一个IP,当使用bind绑定的IP地址是0.0.0.0的时候,这台计算机收到的所有网络请求都会接收,并且根据相应的端口进行处理。

所以本喵将udpSever中构造函数IP地址形参设为缺省值:

static const string defaultIP = "0.0.0.0";
//构造函数
udpSever(const uint16_t &port, const string &ip = defaultIP): _port(port), _ip(ip), _sockfd(-1)
{}

initSever()

在这个初始化函数中创建socket,并且和操作系统进行绑定bind

图

  • 使用socket()系统调用创建套接字,并且进行判断,创建失败打印相应错误信息并且退出进程。
  • 填充sockaddr_in结构体:

首先需要对该结构体进行初始化,也就是清0和填充,使用函数bzero进行初始化:

图
这是一个库函数,需要包含头文件<strings.h>,该函数的作用和memset一样,不同之处在于bzero只能清零,第一个参数是目标地址,第二个参数是要清零的字节数。

在填充sockaddr_in结构体的时候,将地址类型sin_family填充为AF_INET表示网络通信。

在填充端口号sin_port的时候,需要使用htons()函数,将主机字节序转换成网络字节序,然后再进行填充。


我们平时看到的IP地址是都是点分十进制的,如127.0.0.1,这是一个字符串,这是为了方便用户阅读,其实在网络中,IP地址是一个uint32_t类型的数据。

所以在填充IP地址地址的时候,需要先将点分十进制的IP地址,使用函数inet_addr()转换成网络类型的uint32_t类型,然后再进行填充。

图
形参是const char* cp,也就是点分十进制的IP地址,返回类型是in_addr_t

typedef uint32_t in_addr_t;

其实就是uint32_t类型,只是重命名成了in_addr_t


再使用bind将IP地址和端口号和系统绑定,在绑定之前,sockaddr_in是在栈区上的,操作系统根本不知道设的值是什么,只有使用bind之后,才真正将IP地址和端口号绑定到了操作系统中。

在绑定完成后进行判断,如果失败,打印相应错误信息,并且退出进程。

图
这里使用枚举来列举错误码,在创建套接字和绑定的时候,如果发生了错误,在进程退出时给与相关的错误码。

至此,UDP服务器网络通信的预备工作全部完成,此时就可以进行网络通信了。


start()

在预备工作做好以后,还需启动服务器,服务器进程是一个常驻内存的进程,也就是一个while(1)的死循环,在这个循环中进行网络数据的接收,处理,以及发送。

图
上图所示的系统调用recvfrom()用来接收网络中发过来的数据,也就是从套接字中接收。

  • 第一个参数是sockfd,是创建套接字时返回的文件描述符fd
  • 第二个参数buf是用来存储从网络中读取下来的数据的。
  • 第三个参数是buf缓冲区的大小。
  • 第四个参数flags是读取的方式,一般设置为0,即阻塞读取数据。
  • 第五个参数sockaddr* src_addr是一个输出型参数,同样传参sockaddr_in结构体,系统会自动对这个结构体进行填充,可以获取数据的来源,包括发送方的地址类型,端口号port以及IP地址。
  • 第六个参数addrlen是第五个输出型结构体变量的大小所在的地址,注意类型是socklen_t*的,和bind的时候不一样。
  • 返回值ssize_t,返回读取到的数据个数,单位是字节,如果读取失败则返回-1。

图
如上图所示代码,服务端启动后便常驻内存,网络中有数据便读,没有数据便阻塞等待。

读取数据时,除了数据本身,还有发送方的数据,都在sockaddr_in类型的结构体peer中。

从网络中获取到发送方的IP地址是uint32_t类型的,所以需要使用inet_ntoa()函数将其转换成点分十进制的,方便用户阅读。

图
红色框中所示就是inet_ntoa的函数声明,以字符串的形式返回点分十进制的IP地址,参数类型是struct in_addr in

图
in_addr结构体中的变量其实就是一个uint32_t类型的,但是这里传参的时候,不需要具体到s_addr,直接传结构体就行,和绑定IP地址时填充sockaddr_in不一样。

此时我们就可以创建服务器对象并且开始使用他了。


udpSever.cpp

图
在运行可执行程序的时候,需要输入命令行参数,由于IP地址设置了缺省值,所以命令行参数只需要一个端口号即可。

如果执行时,命令行参数没有输对,进程就会退出,并且打印使用信息,如果命令行参数输入正确,就向下执行。

图
使用一个智能指针unique_ptr来管理服务器对象,然后再初始化initSever,之后再开始执行服务器进程start

图
此时服务器进程就开始运行了。那么我们怎么知道它是否运行了呢?

图
使用指令sudo netstat -nuap可以查看当前服务器上的网络进程,如上图所示。

  • sudo提权,如果不加,打印的信息不完整。

可以看到,存在一个网络进程,IP地址是0.0.0.0,端口号是8080,进程pid是376,进程名字是udpSever,和我们设定的一样。

至此服务端的工作就做完了,只有客户端发送数据,服务端就可以收到。

🥣客户端实现

class udpClient
{
public://构造函数,初始化服务端IP地址和端口号udpClient(const string& severip, const uint16_t& port):_severip(severip),_severport(severport),_sockfd(-1){}
private:int _socketfd;//套接字文件描述符string _severip;//服务器IP地址uint16_t _severport;//服务器端口号
};

对于客户端,只需要知道服务端计算机的IP地址和端口号port即可,不需要知道自己的,在使用构造函数构建客户端对象的时候,需要传入服务端的IP地址和端口号。

  • 客户端有无数个,但是服务端只有一个。

initClient

图
客户端的初始化中,只需要创建套接字即可,不需要显式bind

  • 对于客户端而言,指定唯一的IP地址和端口号没有意义,除了服务器以外,没有其他用户会向客户端发起网络请求。

run()

tu
在发送数据之前,需要先告诉操作系统要把数据发送到哪里,所以需要指定服务器的IP地址和端口号port,所以同样需要填充sockaddr_in结构体,创建一个sever变量。

  • 指定地址类型为网络通信,将点分十进制的IP地址转换成uint32_t类型,再将端口号转换成网络字节序。

向网络中发送数据的时候使用到的系统调用是sendto()

图

  • 第一个参数sockfd是创建的套接字的文件描述符。
  • 第二个参数buf是要发送的数据所在的缓冲区。
  • 第三个参数len是要发生的数据个数,以字节为单位。
  • 第四个参数flags是发送方式,一般设置为0,表示阻塞发送。
  • 第五个参数dest_addr是存放服务器IP地址和端口号port的sockaddr_in结构体变量,在传参的时候需要强转为struct sockaddr*
  • 第六个参数,是第五个参数中结构体变量的大小,以字节为单位。

在调用sendto向网络中发送数据的时候,操作系统会自动将客户端的IP地址和端口号绑定,并且一起发送出去。

  • 由于客户端不需要指定端口号,IP地址也是固定的,所以操作系统会随机给客户端分配一个端口号使用。

在服务端收到客户端的报文中,就包含着客户端的IP地址和端口号,通过从recvfrom填充的sockaddr_in结构体中可以提取客户端操作系统随机分配的那个端口号。

服务端同样可以根据这个IP地址和端口号再给客户端发送消息。

udpClient.cpp

图
在运行udpClient的时候,需要传入两个命令行参数,一个是服务器的IP地址,一个是服务器的端口号port。

同样使用unique_ptr智能指针来管理客户端对象,创建好后进行初始化,然后开始运行。

图
由于本喵是在一台服务器上测试客户端和服务端,所以使用的是本地环回,本地环回的IP地址就是127.0.0.1,所以第一个命令行参数就是这个,第二个命令行参数是服务器指定的端口号,前面本喵指定的是8080

  • IP地址使用公网IP,局域网IP,还有本地环回IP,服务端都可以收到客户端的请求,因为服务端绑定的是0.0.0.0

可以看到,在客户端运行起来以后,打印信息socket success: 3,打印的这个数字就是套接字的文件描述符,之所以是3,是因为0,1,2被标准输入输出以及标准错误占用了。

  • 更进一步说明了,套接字创建好后,在操作系统中就是一个文件,也是一个结构体。

此时客户端和服务端都执行起来了,双方就可以进行通信了:

图
运行客户端进程,并且输入要发送的数据内容,如上图所示。

图
可以看到,客户端发送的内容,服务端收到了,并且还有客户端的IP地址和端口号。

图
重新运行客户端程序,发送数据,可以看到,客户端新收到的数据中,端口号变了,从45839变成了47530,这是因为客户端的端口号是由操作系统分配的,并不是自己指定的,所以每次运行时端口号都不一样。

🍚用户层与网络的解耦

上面我们成功的让客户端和服务端建立起了连接,并且能正常进行网络通信,现在我们让服务端用户层和网络进行解耦。

图
在服务端中增加回调函数_callback,使用function包装,回调函数的类型是void(int, string, uint16_t, string)

现在我们实现一个英汉互译的词典,客户端输入英文单词,服务端查它对应的汉语,并且返回给客户端。

图

  • 先在当前路径下创建一个dict.txt文件,里面放入英文和对应的汉语。
  • main函数中,加载词典,调用initDict()函数。
  • 在初始化函数中,使用ifstream类打开dict.txt词典文本,再调用cutString()将文本中的英文和中文分开。
  • 将分开的英文和中文以键值对的形式插入全局变量unordered_map中。

此时我们的词典就建成了,本喵只是简单的写了几个英文单词。

服务器用户层的回调函数:

图
在回调函数中,使用从网络中接收到的客户端请求,也就是英文单词,在unordered_map中查找对应的中文意思,如果找到了,将中文赋值给response_message,如果没有找到,则将unkonwn赋值给response_message

然后将查询的结构response_message通过网络发送给客户端。

  • 可以看到,此时就实现了用户层和网络的解耦,用户要进行的操作完全由用户自己在回调函数中实现即可。
  • 网络底层的配置不用做任何改变。

由于客户端还要接收服务端的反馈信息,所以客户端的网络底层需要做一些修改:

图
在客户端发送完数据以后,便开始等待服务端的反馈,如果服务端发送来信息则接收,并且打印在屏幕上。

这个例子中,打印的就是客户端发送英文单词对应的中文意思。

tu
客户端程序运行起来后,输入英文单词,如上图所示红色框,就会得到对应的中文,如上图绿色框所示。

  • 翻译的过程是由服务器完成的,客户端只需要将英文单词交给服务器即可。

图
服务端可以看到客户端发来的英文单词,如上图绿色框中所示。具体的翻译逻辑是在回调函数中实现的。

如此一来我们英汉互译词典的功能就实现了。

还可以做一些相关的改进,此时的客户端,发送数据和读取数据都是阻塞的,在发送完毕后只能等数据到来再去读取,程序不会执行下去。可以将发送和读取弄成两个线程去执行,此时发送和读取就不不干涉了。

🍚总结

UDP协议的网络通信非常简单,只需要使用socket()创建套接字,服务器的话需要显式bind,客户端不需要显式bind,还有就是需要使用recvfrom从网络中(套接字)中读取数据,以及使用sendto向网络中(套接字)中发送数据。

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

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

相关文章

Unity 之 超级详细的隐私问题解决方案

Unity 之 助力游戏增长 -- 解决隐私问题 一&#xff0c;平台测试隐私问题二&#xff0c;解决方式一2.1 勾选自定义Mainifest2.2 修改自定义Mainifest2.3 隐私协议弹窗逻辑 三&#xff0c;解决方式二3.1 导出安卓工程3.2 创建上层Activity3.3 配置AndroidManifest 四&#xff0…

第一百零六天学习记录:数据结构与算法基础:单链表(王卓教学视频)

线性表的链式表示和实现 结点在存储器中的位置是任意的&#xff0c;即逻辑上相邻的数据元素在物理上不一定相邻 线性表的链式表示又称为非顺序映像或链式映像。 用一组物理位置任意的存储单元来存放线性表的数据元素。 这组存储单元既可以是连续的&#xff0c;也可以是不连续的…

论文笔记--Goat: Fine-tuned LLaMA Outperforms GPT-4 on Arithmetic Tasks

论文笔记--Goat: Fine-tuned LLaMA Outperforms GPT-4 on Arithmetic Tasks 1. 文章简介2. 文章概括3 文章重点技术3.1 LLM的选择3.2 算数任务的可学习性(learnability)3.3 大模型的加减乘除 4. 数值实验结果5. 文章亮点6. 原文传送门7. References 1. 文章简介 标题&#xff…

java中使用HttpRequest发送请求调用自己的接口

(539条消息) java中使用HttpRequest发送请求_java httprequest_thankful_chn的博客-CSDN博客 <dependency><groupId>com.github.kevinsawicki</groupId><artifactId>http-request</artifactId><version>5.6</version></dependenc…

网络的构成要素【图解TCP/IP(笔记七)】

文章目录 网络的构成要素通信媒介与数据链路网卡中继器网桥/2层交换机路由器/3层交换机4&#xff5e;7层交换机网关各种设备及其对应网络分层概览 网络的构成要素 通信媒介与数据链路 计算机之间通过电缆相互连接。电缆可以分为很多种&#xff0c;包括双绞线电缆、光纤电缆、同…

Java InetAddress类

【InetAddress类】 【相关方法】 【使用方法实例】 【代码结果】

创新涌动于先,PingCAP 用户峰会 2023 成功举办

2023 年 7 月 13 日&#xff0c;企业级开源分布式数据库厂商 PingCAP 在京成功举办 PingCAP 用户峰会 2023。本届峰会以“创新涌动于先”为主题&#xff0c;PingCAP 全面解析了 AI 时代 TiDB 的演进方向&#xff0c;宣布 TiDB Serverless 正式商用。会上&#xff0c;PingCAP 携…

​python接口自动化(二十八)--html测试 报告——下(详解) ​

简介 五一小长假已经结束了&#xff0c;想必大家都吃饱喝足玩好了&#xff0c;那就继续学习吧。一天不学习&#xff0c;自己知道&#xff1b;两天不学习&#xff0c;对手知道&#xff1b;三天不学习&#xff0c;大家知道&#xff1b;一周不学习&#xff0c;智商输给猪。好了开个…

静态路由介绍

目录 静态路由配置方法&#xff08;基本配置&#xff09;&#xff1a; 静态路由的拓展配置 负载均衡 1.环回接口——测试 2.手工汇总——子网汇总 3.路由黑洞&#xff08;黑洞路由) 4.缺省路由 5.空接口——NULL 0 6.浮动静态路由 静态路由配置方法&#xff08;基本配置&#x…

DHorse v1.2.1 发布,基于k8s的发布平台

综述 DHorse是一个简单易用、以应用为中心的云原生DevOps系统&#xff0c;具有持续集成、持续部署、微服务治理等功能&#xff0c;无需安装依赖Docker、Maven、Node等环境即可发布Java、Vue、React应用&#xff0c;主要特点&#xff1a;部署简单、操作简洁、功能快速。 优化内…

「深度学习之优化算法」(十三)蝙蝠算法

1. 蝙蝠算法简介 (以下描述,均不是学术用语,仅供大家快乐的阅读)   蝙蝠算法(Bat Algorithm)是受蝙蝠回声定位的特性启发而提出的新兴算法,提出时间是2010年,虽然距今(2020)有近10年,但与其它的经典算法相比仍算一个新算法。算法也已有一定规模的研究和应用,但仍…

Android 14适配

Google I/O 2023 发布的 Android beta2 &#xff0c;Android 14 将在2023年第三季度发布。Google Play 已经开始强制要求targetSdkVersion 33适配&#xff0c;所以 targetSdkVersion 34适配也是非常有必要的。 前台服务类型&#xff08;Foreground service types are required&…

PyTorch: 池化-线性-激活函数层

文章和代码已经归档至【Github仓库&#xff1a;https://github.com/timerring/dive-into-AI 】或者公众号【AIShareLab】回复 pytorch教程 也可获取。 文章目录 nn网络层-池化-线性-激活函数层池化层最大池化&#xff1a;nn.MaxPool2d()nn.AvgPool2d()nn.MaxUnpool2d()线性层激…

Java设计模式之结构型-桥接模式(UML类图+案例分析)

目录 一、基础概念 二、UML类图 三、角色设计 四、案例分析 1、支付方式 2、支付渠道 五、总结 一、基础概念 桥接模式&#xff08;Bridge Pattern&#xff09;是一种结构型设计模式&#xff0c;其主要目的是“将抽象部分与实现部分分离&#xff0c;使它们都可以独立地…

[解决Github 克隆错误] unable to access ‘xxx‘: Recv failure: Connect

1.错误描述&#xff1a; 从GitHub上克隆仓库到本地&#xff0c;出现错误&#xff1a; unable to access https://github.com/xxxx: Recv failure: Connection was reset。 克隆失败。 2.第一次解决此问题&#xff1a;从终端输入&#xff1a; git config --global http.sslVer…

GOPATH、GOROOT(VSCode编写第一个go程序)

1. GOROOT和GOPATH GOROOT 和 GOPATH 都是 Go 语言中的环境变量&#xff0c;用于指定 Go 工具链和工作区的路径。 GOROOT 指定了 Go 工具链的安装路径&#xff0c;它包含了 Go 语言的标准库、编译器等工具。在使用 Go 编译器、运行时等工具时&#xff0c;它们会默认从 GOROOT…

LabVIEW开发图像采集和图像处理程序

LabVIEW开发图像采集和图像处理程序 扫描电子显微镜&#xff08;SEM&#xff09;是一种功能强大的工具&#xff0c;广泛用于高分辨率的生物和半导体样品检测。然而&#xff0c;对于大面积或3D成像&#xff0c;SEM成像是一个耗时的过程。MBSEM旨在通过同时扫描多个像素来减少采…

Vue3使用element-plus实现弹窗效果-demo

使用 <ShareDialog v-model"isShow" onChangeDialog"onChangeDialog" /> import ShareDialog from ./ShareDialog.vue; const isShow ref(false); const onShowDialog (show) > {isShow.value show; }; const onChangeDialog (val) > {co…

关于 Eclipse 的一场 “三角关系”

上个世纪 90 年代&#xff0c;世界上的计算机要么不联网&#xff0c;要么在企业内部联网。但是&#xff0c;在互联网的概念下&#xff0c;计算机之间共享信息和资源的需求成为了必要。 1995 年 5 月&#xff0c;Java 横空出世。Java 的父亲是当时凭借 Solaris 操作系统风头正盛…

【朱颜不曾改,芳菲万户香。AIGC人物图片创作---InsCode Stable Diffusion 美图活动一期】

【朱颜不曾改&#xff0c;芳菲万户香。AIGC人物图片创作 ---InsCode Stable Diffusion 美图活动一期】 本文目录&#xff1a; 一、 Stable Diffusion 模型在线使用 1.1、模板运行环境配置 1.2、运行InsCode平台的Stable Diffusion模板 二、Stable Diffusion主界面功能 2.…