网络基础:socket套接字
文章目录
- 1. 前导知识
- 1.1 源MAC地址和目的MAC地址
- 1.2 源IP地址和目的IP地址
- 1.3 MAC地址和IP地址的配合
- 1.4 源端口号和目的端口号
- 1.5 Socket
- 1.6 UCP协议和TCP协议
- 1.7 网络字节序
- 高低位
- 高低地址
- 大端和小端
- 网络字节序
- 常用转换函数
- 2. socket 网络编程
- 2.1 socket 常见接口
- 创建套接字
- 绑定
- 监听套接字
- 接收请求
- 建立连接
- 2.2 常见套接字
- 域间套接字
- 原始套接字
- 网络套接字
- 2.3 sockaddr 结构体
- 3. 实践
- 实现简易UDP网络程序
- 实现简易TCP网络程序
1. 前导知识
友情链接:网络基础入门
1.1 源MAC地址和目的MAC地址
MAC地址(Media Access Control Address, 局域网地址)在OSI模型的第二层数据链路层发挥作用,标识本地网络上的设备物理地址。
对于处于同一局域网的多台主机,它们直接向局域网发送的数据是被所有主机共享的(包括发送的主机自己),也就相当于广播,但是只有特定的主机才会处理它(虽然所有主机都收到了信息)。这是因为主机发送的数据中包含了指定主机的MAC地址,除此之外,为了校验数据的完整性,还包含了发生数据的主机本身的MAC地址,以供主机在发送信息后再接收校验。
其中,发送信息的主机的MAC地址叫做源MAC地址,接收信息的主机的MAC地址叫做目的MAC地址。
1.2 源IP地址和目的IP地址
IP地址(Internet Protocol, 互联网协议)在OSI模型的第三层网络层发挥作用,它是一个逻辑地址,用于唯一标识互联网连接设备。
MAC地址标识着设备的全球唯一性,但是仅靠MAC地址无法完成不同网络中数据的传输。我们知道,数据传输是通过网络协议栈传输的,数据自上而下传输时会被每一层协议封装一个报头信息,当数据自下而上传输时,每一层协议会解封装,直到应用层取到数据本身。但是不同的网络可能在某些层的协议有所区别,因此报头的封装和解封装的过程就不像局域网那样对称,因此需要配合IP地址在不同的网络中跳转。
1.3 MAC地址和IP地址的配合
在不同网络中,路由器起着“指路人”的作用,实际上数据在传输过程中可能会经过多个不同网络,那么报头信息中的两个MAC地址一直在随着路由器(路由器也是硬件)的变化而变化,但是源IP地址和目的IP地址不会改变。这就像唐僧每到一个地方都会说“自东土大唐而来,去西天取经”,出发点和目的地是不应该被改变的(在某些特殊情况源IP可能会被改变,但是目的IP绝对不会被改变),但是遇到的好心人听到这句话以后都会告诉唐僧下一个地方应该怎么走,这就是MAC地址和IP地址在不同网络中配合数据传输的过程。
1.4 源端口号和目的端口号
端口号(PORT)的主要作用是表示一台计算机中的特定(特指网络服务)进程所提供的服务,它在传输层发挥作用,标识主机上进程的唯一性。言外之意是一个端口号只能被一个进程使用,而一个进程可以使用多个端口号。
端口号是一个16位的无符号整数,范围从0到65535。在Internet上,端口号用于识别不同的网络服务。例如,Web服务器通常使用端口号80,SMTP服务器使用端口号25等 。
结合进程相关知识,数据本身是被运行起来的进程处理的,因此数据通过网络传输到不同主机中只是一个搬运的过程。因此可以认为数据是在不同主机中的不同进程之间传输,也就是网络层面上的进程间通信。端口号的名字很形象,现实中的港口(port)也是类似的。主机中各种不同的进程就好像一个个蓄势待发的货船,它们在不同编号的位置等待货物,一旦货物就绪,一个个进程就会对其处理。
IP地址标识了公网中主机的唯一性,端口号标识主机上进程的唯一性,那么IP地址+端口号就标识了网络上某台主机中的进程的唯一性。和IP地址类似,端口号会在传输层被封装进报头信息中。
既然PID和端口号都能表示主机上进程的唯一性,为什么不用PID进行网络传输?
端口号标识的进程是PID标识的进程的子集,它们标识的范围不同。PID就像每个人的身份证,虽然它能表示我们在这片土地上的唯一性,但是我们很多时候不使用它,而是使用范围合适、便于管理的标识,例如在教室用座位号、在学校用学号、在高考中用准考证和在银行里用身份证等等。使用PID当然可以,但是这样会增加筛选所有进程中的网络服务进程的负担,也会增加其他非网络服务进程的安全风险。这也是一种解耦的做法,单独用一种标识表示特定种类的元素,能省去筛选的成本。
1.5 Socket
Socket(套接字)是计算机网络中的一个软件结构,它用于在计算机网络中的节点之间发送和接收数据。套接字的结构和属性由网络架构的应用程序编程接口(API)定义。它允许应用程序将I/O插入到网络中,并与网络中的其他应用程序进行通信。简单来说,Socket是计算机之间进行通信的一种约定或一种方式。
Socket这个词在计算机网络中的翻译为“套接字”,原意指的是插座或者插槽。在计算机网络中,它被用来描述两个程序之间建立连接的端点。就像电器插头需要插入插座才能通电一样,两个程序之间也需要一个“插座”来建立连接。因此,这个词被引申为“套接字”。
Socket函数是应用程序与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部。它将底层复杂的协议体系、执行流程进行了封装,封装完的结果就是一个SOCKET了,也就是说,SOCKET是我们调用协议进行通信的操作接口。
Socket起源于Unix,而Unix/Linux基本哲学之一就是“一切皆文件”,都可以用“打开open –> 读写write/read –> 关闭close”模式来操作。Socket就是该模式的一个实现,socket即是一种特殊的文件,一些socket函数就是对其进行的操作(读/写IO、打开、关闭)。
在实践过程中,其实不必要关心它的各种定义,可以简单地理解为它就是一个数据包,是包含各种通信相关属性的结构体。内置的库中有许多函数,它们会在函数内部对这个数据包中的属性处理。值得注意的是,socket本质是一个按照某种规则(协议)构造出来的一个文件,只要通信两端都按照约定好的规则使用它其中的数据,就能实现通信过程。
友情链接:
- socket是什么?套接字是什么?
- SOCK、SOCKET和TCP_SOCK之间的关系
1.6 UCP协议和TCP协议
下面简单介绍UCP协议和TCP协议。
TCP(Transmission Control Protocol,传输控制协议)提供的是面向连接,可靠的字节流服务。即客户和服务器交换数据前,必须现在双方之间建立一个TCP连接,之后才能传输数据。并且提供超时重发,丢弃重复数据,检验数据,流量控制等功能,保证数据能从一端传到另一端。
UDP(User Datagram Protocol,用户数据报协议)是一个简单的面向数据报的运输层协议。它不提供可靠性,只是把应用程序传给IP层的数据报发送出去,但是不能保证它们能到达目的地。由于UDP在传输数据报前不用再客户和服务器之间建立一个连接,且没有超时重发等机制,所以传输速度很快。
简单地说,TCP就像打电话,首先要通信信道才能进行通信。
为什么UDP不提供可靠性,还要使用它?
尽管UDP不提供可靠性,但它的优点在于传输速度快。由于UDP在传输数据报前不用再客户和服务器之间建立一个连接,且没有超时重发等机制,所以传输速度很快 。这对于一些对实时性要求较高的应用程序来说非常重要,例如在线游戏、实时音视频传输等。在这些情况下,使用UDP协议能够提供更快的响应速度。一般情况下,为了数据安全都使用TCP,在特殊场景下(例如直播和视频)可能会使用UDP。在优秀的通信算法中,常常会同时使用TCP和UDP,根据实际情况调度策略。
实际上,这里的“可靠”是相对的,是中性词。也就是说,TCP为了达到“可靠”,付出了很多代价,例如协议更复杂、维护难度高,因此它的传输速度没有UDP快。其“可靠”与否是协议本身的特点。如果它们会说话的话,那么UDP可能会对TCP说“何必这么累呢?跟我一样直接把数据甩给对面不就好了?”
1.7 网络字节序
高低位
对于任意一个十进制的数值,它可以用多项式 1 0 n 10^n 10n的和表示,例如 123 = 1 × 1 0 2 + 2 × 1 0 1 + 3 × 1 0 0 123 = {1×10^2} + {2×10^1} + {3×10^0} 123=1×102+2×101+3×100,字节的高低对应着权值的大小。例如,对于整数0x12345678,0x12是最高位字节,它的权值是16的三次方;0x78是最低位字节,它的权值是16的零次方。
高低地址
内存地址的高低是指内存地址的数值大小。比如,0x1000是一个比0x0100更高的地址。
简单地说,就是左边低,右边高。
大端和小端
- 小端:数据的高权值位对应高地址处。
- 大端:反之。
假设我们有一个16位的整数0x1234,它占用两个字节。在大端字节序的计算机中,这个整数将按照0x12 0x34的顺序存储在内存中。也就是说,最高位字节0x12存储在内存的低地址处,最低位字节0x34存储在内存的高地址处。
而在小端字节序的计算机中,这个整数将按照0x34 0x12的顺序存储在内存中。也就是说,最低位字节0x34存储在内存的低地址处,最高位字节0x12存储在内存的高地址处。
只要记住大端更符合我们现代人从左到右的读写习惯即可。
网络字节序
接收数据的主机知道对方主机是大端还是小端吗?
不知道。因为主机的大小端是不确定的,因此如果接收数据的主机必须要知道对方主机是大端还是小端。否则就会出现数据读取错误。
发送数据的主机将它的大小端属性特征字段放进报头信息中不就好了?
找到属性字段的前提是接收数据的主机已经知道了发送数据的主机是大端还是小端,这样就矛盾了。
所以网络字节序直接规定了使用大端。因此主机在发送数据和接收数据时,都要对数据进行字节序转换。
转换什么?
- 数据在发送前,需要从主机字节序转换为网络字节序;
- 数据在接收后,需要从网络字节序转换为主机字节序。
常用转换函数
这个转换的工作已经由C标准库完成,实际上,Windows也使用的是相同的一套函数。
#include <arpa/inet.h>uint32_t htonl(uint32_t hostlong);
uint16_t htons(uint16_t hostshort);
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);
命名解读:
- h:host,表示主机字节序;
- n:net,表示网络字节序;
- l:long,表示32位长整数;
- s:short,表示16位短整数。
通常情况下,不论测试机是大端还是小端,为了可移植性都要调用这些函数进行转换,如果机器本身是大端,那么这些函数将直接返回。
编码习惯:虽然有时候某些步骤在理论上是不必要的,但实际应用中可能会出现各种各样的问题,所以为了保险起见都会多执行一步。
2. socket 网络编程
2.1 socket 常见接口
TCP是面向连接的,通过socket实现通信的步骤是:
- 创建套接字(服务端和客户端)
- 绑定端口号(服务端)
- 监听套接字(服务端)
- 建立连接(客户端)
UDP是面向字节流的,它的步骤比较简单:
- 创建套接字(服务端和客户端)
- 绑定端口号(服务端)
其中,TCP和UDP的服务端都要创建套接字并绑定端口号,这些步骤将在实践中介绍,仅通过接口的数量就能看到TCP比UDP多做了不少工作。
在此,由于知识的局限,某些参数无法作详细的解释,将在TCP/UDP专题中介绍。
通过man + [函数名]
能很方便地查询函数相关信息。
它们的头文件都是:
#include <sys/types.h>
#include <sys/socket.h>
创建套接字
socket()
函数用于创建套接字。
int socket(int domain, int type, int protocol);
参数:
- domain(域):指定套接字家族,简单地说就是指定通信的方式是本地还是网络:
AF_UNIX, AF_LOCAL
:本地通信。AF_INET
:网络通信。- …
- type:指定套接字的类型,即传输方式:
SOCK_STREAM
:面向连接的套接字/流格式套接字。SOCK_DGRAM
:无连接的套接字/数据报套接字。
- protocol(协议):指定传输协议,默认为
0
,常用的有:IPPROTO_TCP
:表示TCP传输协议。IPPTOTO_UDP
:表示UDP传输协议。
绑定
bind()
函数用于将套接字与指定的IP地址和端口号绑定。通常在TCP协议或UDP协议的服务端设置。
int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
参数:
- sockfd:要绑定的套接字文件描述符,它的本质是一个数组下标。
- addr:是一个指向
struct sockaddr
类型结构体的指针,该结构体中包含了要绑定的IP地址和端口号。 - addrlen 是
addr
所指向的地址结构体的大小。
监听套接字
listen()
函数用于将套接字转换为被动监听状态。通常在TCP协议的服务端设置。
int listen(int sockfd, int backlog);
参数:
- sockfd:要监听的套接字文件描述符。
- backlog:未完成连接队列的最大长度,即允许等待连接的客户端数量 。
接收请求
accept()
函数用于从监听套接字的未完成连接队列中提取第一个连接请求,创建一个新的已连接套接字,并返回一个指向该套接字的文件描述符。通常在TCP协议的服务端设置。
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
参数:
- sockfd:监听套接字的文件描述符。
- addr:是一个指向 struct sockaddr 类型结构体的指针,用于存储客户端的地址信息。
- addrlen:是一个指向 socklen_t 类型变量的指针,用于存储客户端地址结构体的大小。
建立连接
connect()
函数用于建立与指定套接字的连接。通常在TCP协议的服务端设置。
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
参数:
- sockfd 是要连接的套接字文件描述符。
- addr 是一个指向
struct sockaddr
类型结构体的指针,该结构体中包含了要连接的服务器的地址信息。 - addrlen 是
addr
所指向的地址结构体的大小。
2.2 常见套接字
套接字是一种通信机制,用于在不同主机或同一主机上的进程间通信。套接字有多种类型,包括流式套接字(SOCK_STREAM)、数据报套接字(SOCK_DGRAM)和原始套接字(SOCK_RAW)等。在这里,我们讨论的是网络套接字。
域间套接字
域间套接字(Domain Socket)是一种特殊类型的套接字(socket)。套接字是一种通信机制,用于在不同主机或同一主机上的进程间通信。套接字有多种类型,包括流式套接字(SOCK_STREAM)、数据报套接字(SOCK_DGRAM)和原始套接字(SOCK_RAW)等。域间套接字是其中的一种类型,用于在同一台主机上的进程间通信。
简单来说,域间套接字是套接字的一种类型,它与其他类型的套接字共享相似的API和通信机制,但是它专门用于在同一台主机上的进程间通信。
原始套接字
原始套接字(Raw Socket)是一种特殊类型的套接字,它允许直接发送和接收IP协议数据包,而不需要任何传输层协议格式。这意味着使用原始套接字时,应用程序需要自己处理传输层协议的相关细节。
原始套接字通常用于安全相关的应用程序,如nmap,或用于在用户空间实现新的传输层协议。它也常用于网络设备上的路由协议,例如IGMPv4、开放式最短路径优先协议 (OSPF)、互联网控制消息协议 (ICMP)。
网络套接字
网络套接字(Network Socket)是一种用于在不同主机上的进程间通信的套接字。它使用了网络协议栈,如TCP/IP协议栈,来实现跨网络的通信。网络套接字使用IP地址和端口号来标识通信端点。
网络套接字有两种类型:流式套接字(SOCK_STREAM)和数据报套接字(SOCK_DGRAM)。流式套接字使用TCP协议进行数据传输,提供可靠的、面向连接的通信服务。数据报套接字使用UDP协议进行数据传输,提供无连接的、不可靠的通信服务。
2.3 sockaddr 结构体
在介绍socket网络套接字的接口时,曾多次提到sockaddr
结构体,它是一个通用的套接字地址结构,用于在套接字编程中传递不同协议族的地址信息。它的定义如下:
struct sockaddr {
sa_family_t sa_family; /* 地址族 */
char sa_data[14]; /* 地址数据 */
};
-
sa_family字段表示地址族(address family),用于指定地址的类型。常见的地址族有AF_INET(IPv4地址)、AF_INET6(IPv6地址)和AF_UNIX(Unix域地址)等。
-
sa_data字段表示协议地址,其长度和内容取决于地址族。例如,对于IPv4地址,它包含了IP地址和端口号;对于Unix域地址,它包含了文件系统中的路径名。
由于sockaddr结构并不能很好地表示各种类型的地址,因此通常会使用特定于地址族的结构来表示套接字地址,例如sockaddr_in(用于IPv4地址)和sockaddr_un(用于Unix域地址)。这些结构与sockaddr结构具有相同的大小和对齐方式,可以相互转换。
因此,这个结构体的唯一目的是为了将不同协议族的地址结构体指针转换为一个“通用”类型,以避免编译器警告。例如,对于IPv4协议族的地址结构体sockaddr_in,它的定义如下:
struct sockaddr_in {
sa_family_t sin_family; /* AF_INET */
in_port_t sin_port; /* 端口号 */
struct in_addr sin_addr; /* IPv4地址 */
};
这个结构体比sockaddr结构体更具体,它包含了IPv4协议族所需的地址信息。当我们调用套接字函数时,例如bind(2),我们需要将sockaddr_in结构体指针强制转换为sockaddr结构体指针,如下所示:
struct sockaddr_in addr;
/* 初始化addr */
bind(sockfd, (struct sockaddr *)&addr, sizeof(addr));
这样做是为了让套接字函数能够根据sa_family字段来判断实际的地址类型,并进行相应的处理。同样的道理,对于其他协议族,例如IPv6或UNIX域套接字,也有各自的地址结构体,例如sockaddr_in6和sockaddr_un,它们都可以转换为sockaddr结构体指针。
因此,我们可以认为sockaddr结构体是一个抽象的接口,它隐藏了不同协议族地址结构体之间的差异,让我们可以使用统一的方式来操作套接字。

为了统一使用接口,Linux内核用结构体的前2个字节标定套接字的类型。即即套接字的类型。sa_family字段是一个sa_family_t类型(无符号整型)的变量,通常占用两个字节。
地址族用于指定地址的类型,它决定了套接字如何解释地址信息。常见的地址族有AF_INET(IPv4地址)、AF_INET6(IPv6地址)和AF_UNIX(Unix域地址)等。不同类型的套接字使用不同的协议来传输数据,因此需要使用不同的地址结构来表示它们的地址信息。
通过在sockaddr结构体中使用一个通用的字段来表示地址族,Linux内核可以统一处理不同类型的套接字地址,简化了套接字API的使用。在使用上的体现就是,不管是何种通信方式,网络还是本地通信,虽然在初始化套接字中的属性时使用的是struct sockaddr_in
或struct sockaddr_un
,但是传参都统一类型转换为sockaddr*
。这样就不用单独为不同的通信方式实现不同的接口了,从而减少了使用成本。
在多线程编程中,我们经常利用
void*
(它可以传递任意类型的数据)来给线程函数传递信息,为什么socket不使用void*
来保存通信相关属性呢?
套接字API的设计可以追溯到20世纪70年代末,当时由贝尔实验室的研究人员开发了BSD Unix操作系统。在当时,C语言和Unix操作系统都处于起步阶段,许多现代编程语言和操作系统的特性还没有出现。
在设计套接字API时,研究人员希望能够提供一种通用的接口,用于支持不同类型的网络协议。为了实现这一目标,他们定义了一组通用的套接字地址结构,用于表示不同类型的网络地址。这些结构体包含了特定的字段,用于存储地址族、协议地址等信息。
虽然使用void*
指针也可以实现类似的功能,但是这样做会使得代码变得更加复杂和难以维护。程序员需要手动管理内存,并且需要使用类型转换来访问指针指向的数据。相比之下,使用特定的结构体类型来表示套接字地址更加简单、直观和安全。
因此,套接字API最终采用了特定的结构体类型来表示套接字地址,而不是使用void*
指针。这一设计决策为套接字API提供了清晰、简洁和易用的接口,并且在后来被广泛采纳。
3. 实践
实际上,有了这些接口,我们便能按照“套路”实现网络程序,到目前为止,这是我觉得除了进程间通信之外最有趣的实验。
由于文章还没写完,所以给出两个权威的规范样例。
实现简易UDP网络程序
-
C socket UDP client
-
C socket UDP server
实现简易TCP网络程序
- C socket TCP client
- C socket TCP server
相关文章:

网络基础:socket套接字
文章目录 1. 前导知识1.1 源MAC地址和目的MAC地址1.2 源IP地址和目的IP地址1.3 MAC地址和IP地址的配合1.4 源端口号和目的端口号1.5 Socket1.6 UCP协议和TCP协议1.7 网络字节序高低位高低地址大端和小端网络字节序常用转换函数 2. socket 网络编程2.1 socket 常见接口创建套接字…...
程序员如何学好PHP?做好这五个方面就够了
今天我想和大家分享一下程序员的第一份工作对自己的意义以及影响。首先,我们都知道第一份工作很重要,因为它决定了你以后的职业生涯的方向。你的第一份工作做的什么方向,很可能就是你以后职业生涯中最主要的方向。对我个人而言,我…...

【开源项目】Build your own X 构建自己的项目
【开源项目】Build your own X 构建自己的项目 简介 Build your own X 是一个精心收集了大量资源的项目指南,可以通过从头开始重新创建我们最喜爱的技术来掌握编程。 项目地址: https://github.com/codecrafters-io/build-your-own-x这些项目里的资源…...

在.NET Core中正确使用HttpClient的方式
HttpClient 是 .NET Framework、.NET Core 或 .NET 5以上版本中的一个类,用于向 Web API 发送 HTTP 请求并接收响应。它提供了一些简单易用的方法,如 GET、POST、PUT 和 DELETE,可以很容易地构造和发送 HTTP 请求,并处理响应数据。…...

【C++】位运算类题目总结
文章目录 一. 位运算符脑图二. 相关题目1. 统计二进制数中0的个数2. 数组中只出现一次的数字3. 数组中只出现一次的数字 II4. 不用加减乘除做加法 一. 位运算符脑图 二. 相关题目 1. 统计二进制数中0的个数 解题思路:x & (x-1);它的作用是每次循环…...
Node服务端开发【NPM】
文章目录 前言NPM使用NPM使用场景NPM的常用命令NPM命令使用介绍使用NPM安装模块下载三方包全局安装VS本地安装本地安装全局安装全局模块路径查看与路径修改 卸载模块更新模块搜索模块NPM服务器发布包 NPM换源nrm全局安装 nrm:nrm ls 列出来现在已经配置好的所有的原地址nrm use…...

Doris(21):Doris的函数—日期函数
1 CONVERT_TZ(DATETIME dt, VARCHAR from_tz, VARCHAR to_tz) 转换datetime值dt,从 from_tz 由给定转到 to_tz 时区给出的时区,并返回的结果值。 如果参数无效该函数返回NULL。 select convert_tz(2019-08-01 13:21:03, Asia/Shanghai, America/Los_Angeles); select co…...

和月薪5W的阿里程序员聊过后,才知道自己一直在打杂...
前几天和一个朋友聊面试,他说上个月同时拿到了腾讯和阿里的offer,最后选择了阿里。 阿里内部将员工一共分为了14个等级,P6是资深工程师,P7是技术专家。 其中P6和P7就是一个分水岭了,P6是最接近P7的不持股员工&#x…...

西门子PLC沿脉冲类指令汇总
S7-1200CPU提供了四种沿脉冲指令供用户使用,分别为:扫描操作数信号边沿指令、在信号边沿置位操作数的指令、扫描RLO的信号边沿指令以及检测信号边沿指令。 信号从0--1的时刻称为上升沿,信号从1--0的时刻称为下降沿,不管是上升沿还…...

软件多语言文案脚本自动化方案
开发高效提速系列目录 软件多语言文案脚本自动化方案 软件多语言文案脚本自动化方案 背景目标整体方案1. 创建文案资源文件2. python脚本开发3. Python脚本执行与管理4. 人员职责分配 PyCharm使用说明1. PyCharm下载2. PyCharm安装配置3. 异常情况解决 总结 博客创建时间&…...

C++017-C++文件读写应用
文章目录 C017-C文件读写应用C文件读写应用CSP-J目标1. 文件的基本概念、文本文件的基本操作2.文本文件类型与二进制文件类型文本文件类型二进制文件类型二进制查看工具 3.文件重定向、文件读写等操作关闭文件文件操作-写入文本文件文件操作-读取文本文件文件操作-写入二进制文…...

计算机网络 实验二
⭐计网实验专栏,欢迎订阅与关注! ★观前提示:本篇内容为计算机网络实验。内容可能会不符合每个人实验的要求,因此以下内容建议仅做思路参考。 一、实验目的 (1)掌握IP地址的基本结构(网络部分与主机部分的…...

Unity 3D 学习笔记(1)
文章目录 1.Unity 3D 概述2.Unity的安装过程3.Unity 3D 的项目管理4.Unity 3D 中的场景5.Unity 3D 的界面组成 1.Unity 3D 概述 Unity 3D简介:Unity 3D是虚拟现实行业中使用率较高的一款开发引擎,由Unity Technology公司开发。通过Unity,开发…...
P1050 [NOIP2005 普及组] 循环
题目描述 乐乐是一个聪明而又勤奋好学的孩子。他总喜欢探求事物的规律。一天,他突然对数的正整数次幂产生了兴趣。 众所周知,22 的正整数次幂最后一位数总是不断的在重复 2,4,8,6,2,4,8,6…2,4,8,6,2,4,8,6… 我们说 22 的正整数次幂最后一位的循环长度…...

软考算法-排序篇-上
数据排序 一:故事背景二:直接插入排序2.1 概念2.2 画图表示2.3 代码实现2.4 总结提升 三:希尔排序3.1 概念3.2 画图表示3.3 代码实现3.4 总结提升 四:直接选择排序4.1 概念4.2 画图表示4.3 代码实现4.4 总结提升 五:堆…...

总结836
学习目标: 4月(复习完高数18讲内容,背诵21篇短文,熟词僻义300词基础词) 学习内容: 暴力英语:背诵《keep your direction》,默写,英语语法 高等数学:刷题&a…...
ginbuilder 工具快速创建
ginbuilder github 地址 快速创建一个ginweb项目: 目前apps下只有http服务,如果后续有需要的话,会添加上rpc服务,websocket服务后边如果有需要会添加上swagger 创建完成的目录结构 ├── apps │ ├── apis // 所有的apis…...
【Java基础面试宝典】堆、栈、方法区分别都存储了那些内容?wait 和 sleep 方法的区别?
目录 堆、栈、方法区分别都存储了那些内容? 堆(heap) 栈(stack) 方法区(method) 在 java 中 wait 和 sleep 方法的区别? 堆、栈、方法区分别都存储了那些内容? 堆&a…...

古剑飞仙手游Linux系统服务器架设教程
安装宝塔直接运行命令即可。 yum install -y wget && wget -O install.sh http://download.bt.cn/install/install_6.0.sh && sh install.sh 搭建环境: centos 7以上系统服务器 宝塔面板安装应用如下: Nginx1.14 mysql5.7 php5.6 1…...
python实战应用讲解-【numpy数组篇】常用函数(十)(附python示例代码)
目录 Python Numpy MaskedArray.ravel()函数 Python Numpy MaskedArray.reshape()函数 Python Numpy MaskedArray.resize()函数 Python Numpy MaskedArray.std()函数 Python Numpy MaskedArray.sum()函数 Python Numpy MaskedArray.swapaxes()函数 Python Numpy MaskedA…...
conda相比python好处
Conda 作为 Python 的环境和包管理工具,相比原生 Python 生态(如 pip 虚拟环境)有许多独特优势,尤其在多项目管理、依赖处理和跨平台兼容性等方面表现更优。以下是 Conda 的核心好处: 一、一站式环境管理:…...

云启出海,智联未来|阿里云网络「企业出海」系列客户沙龙上海站圆满落地
借阿里云中企出海大会的东风,以**「云启出海,智联未来|打造安全可靠的出海云网络引擎」为主题的阿里云企业出海客户沙龙云网络&安全专场于5.28日下午在上海顺利举办,现场吸引了来自携程、小红书、米哈游、哔哩哔哩、波克城市、…...
Qt Widget类解析与代码注释
#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this); }Widget::~Widget() {delete ui; }//解释这串代码,写上注释 当然可以!这段代码是 Qt …...

CMake基础:构建流程详解
目录 1.CMake构建过程的基本流程 2.CMake构建的具体步骤 2.1.创建构建目录 2.2.使用 CMake 生成构建文件 2.3.编译和构建 2.4.清理构建文件 2.5.重新配置和构建 3.跨平台构建示例 4.工具链与交叉编译 5.CMake构建后的项目结构解析 5.1.CMake构建后的目录结构 5.2.构…...
AtCoder 第409场初级竞赛 A~E题解
A Conflict 【题目链接】 原题链接:A - Conflict 【考点】 枚举 【题目大意】 找到是否有两人都想要的物品。 【解析】 遍历两端字符串,只有在同时为 o 时输出 Yes 并结束程序,否则输出 No。 【难度】 GESP三级 【代码参考】 #i…...
连锁超市冷库节能解决方案:如何实现超市降本增效
在连锁超市冷库运营中,高能耗、设备损耗快、人工管理低效等问题长期困扰企业。御控冷库节能解决方案通过智能控制化霜、按需化霜、实时监控、故障诊断、自动预警、远程控制开关六大核心技术,实现年省电费15%-60%,且不改动原有装备、安装快捷、…...
浅谈不同二分算法的查找情况
二分算法原理比较简单,但是实际的算法模板却有很多,这一切都源于二分查找问题中的复杂情况和二分算法的边界处理,以下是博主对一些二分算法查找的情况分析。 需要说明的是,以下二分算法都是基于有序序列为升序有序的情况…...

九天毕昇深度学习平台 | 如何安装库?
pip install 库名 -i https://pypi.tuna.tsinghua.edu.cn/simple --user 举个例子: 报错 ModuleNotFoundError: No module named torch 那么我需要安装 torch pip install torch -i https://pypi.tuna.tsinghua.edu.cn/simple --user pip install 库名&#x…...

中医有效性探讨
文章目录 西医是如何发展到以生物化学为药理基础的现代医学?传统医学奠基期(远古 - 17 世纪)近代医学转型期(17 世纪 - 19 世纪末)现代医学成熟期(20世纪至今) 中医的源远流长和一脉相承远古至…...

人机融合智能 | “人智交互”跨学科新领域
本文系统地提出基于“以人为中心AI(HCAI)”理念的人-人工智能交互(人智交互)这一跨学科新领域及框架,定义人智交互领域的理念、基本理论和关键问题、方法、开发流程和参与团队等,阐述提出人智交互新领域的意义。然后,提出人智交互研究的三种新范式取向以及它们的意义。最后,总结…...