网络基础: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…...
Python|GIF 解析与构建(5):手搓截屏和帧率控制
目录 Python|GIF 解析与构建(5):手搓截屏和帧率控制 一、引言 二、技术实现:手搓截屏模块 2.1 核心原理 2.2 代码解析:ScreenshotData类 2.2.1 截图函数:capture_screen 三、技术实现&…...

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析
1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具,该工具基于TUN接口实现其功能,利用反向TCP/TLS连接建立一条隐蔽的通信信道,支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式,适应复杂网…...
Android Wi-Fi 连接失败日志分析
1. Android wifi 关键日志总结 (1) Wi-Fi 断开 (CTRL-EVENT-DISCONNECTED reason3) 日志相关部分: 06-05 10:48:40.987 943 943 I wpa_supplicant: wlan0: CTRL-EVENT-DISCONNECTED bssid44:9b:c1:57:a8:90 reason3 locally_generated1解析: CTR…...
R语言AI模型部署方案:精准离线运行详解
R语言AI模型部署方案:精准离线运行详解 一、项目概述 本文将构建一个完整的R语言AI部署解决方案,实现鸢尾花分类模型的训练、保存、离线部署和预测功能。核心特点: 100%离线运行能力自包含环境依赖生产级错误处理跨平台兼容性模型版本管理# 文件结构说明 Iris_AI_Deployme…...
Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信
文章目录 Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信前言一、网络通信基础概念二、服务端与客户端的完整流程图解三、每一步的详细讲解和代码示例1. 创建Socket(服务端和客户端都要)2. 绑定本地地址和端口&#x…...

HarmonyOS运动开发:如何用mpchart绘制运动配速图表
##鸿蒙核心技术##运动开发##Sensor Service Kit(传感器服务)# 前言 在运动类应用中,运动数据的可视化是提升用户体验的重要环节。通过直观的图表展示运动过程中的关键数据,如配速、距离、卡路里消耗等,用户可以更清晰…...
【JavaSE】多线程基础学习笔记
多线程基础 -线程相关概念 程序(Program) 是为完成特定任务、用某种语言编写的一组指令的集合简单的说:就是我们写的代码 进程 进程是指运行中的程序,比如我们使用QQ,就启动了一个进程,操作系统就会为该进程分配内存…...
MySQL 8.0 事务全面讲解
以下是一个结合两次回答的 MySQL 8.0 事务全面讲解,涵盖了事务的核心概念、操作示例、失败回滚、隔离级别、事务性 DDL 和 XA 事务等内容,并修正了查看隔离级别的命令。 MySQL 8.0 事务全面讲解 一、事务的核心概念(ACID) 事务是…...
Python 训练营打卡 Day 47
注意力热力图可视化 在day 46代码的基础上,对比不同卷积层热力图可视化的结果 import torch import torch.nn as nn import torch.optim as optim from torchvision import datasets, transforms from torch.utils.data import DataLoader import matplotlib.pypl…...
小木的算法日记-多叉树的递归/层序遍历
🌲 从二叉树到森林:一文彻底搞懂多叉树遍历的艺术 🚀 引言 你好,未来的算法大神! 在数据结构的世界里,“树”无疑是最核心、最迷人的概念之一。我们中的大多数人都是从 二叉树 开始入门的,它…...