套接字通信(附带单线程TCP套接字通信代码)

套接字-Socket

1. 概念

1.1 局域网和广域网

局域网(LAN)和广域网(WAN)是两种不同范围的计算机网络,它们用于连接多台计算机以实现数据共享和通信。

  1. 局域网(LAN):
    • 定义: 局域网是一个较小范围内的网络,通常限定在某个地理区域,比如一个办公室、学校或者家庭。
    • 范围: LAN 的范围通常在几百米到几千米之间。
    • 连接设备: 局域网连接的设备可以是计算机、打印机、服务器等,通过局域网内的设备可以方便地共享资源和信息。
    • 传输速度: 由于较小的范围,局域网通常具有较高的传输速度和较低的延迟。
  2. 广域网(WAN):
    • 定义: 广域网是一个覆盖范围更广泛的网络,可以连接跨越城市、国家甚至是全球的多个局域网。
    • 范围: WAN 的范围较大,可以覆盖从几千千米到全球范围。
    • 连接设备: 广域网连接的设备可以是分布在不同地理位置的局域网,通过 WAN,这些设备可以进行远程通信和数据交换。
    • 传输速度: 由于覆盖较大范围,广域网的传输速度通常相对较慢,而且可能存在较高的延迟。
  3. 连接方式:
    • 局域网: 通常通过以太网技术、Wi-Fi等局域网技术进行连接。
    • 广域网: 使用各种通信技术,包括光纤、卫星、电话线等,以连接不同地理位置的网络。
  4. 应用场景:
    • 局域网: 用于组织内部、学校、家庭等相对小范围的网络需求。
    • 广域网: 用于连接分布在不同城市、国家或全球范围内的组织和机构,实现远程通信和资源共享。

总的来说,局域网和广域网在范围、连接设备、传输速度以及应用场景上有明显的区别,它们在网络体系中协同工作,为不同规模和需求的组织提供了灵活的网络解决方案。

1.2 IP

IP,或称为Internet Protocol(互联网协议),是一种**在计算机网络中用于标识和定位设备(如计算机、路由器、服务器等)的通信协议。**IP地址是在Internet Protocol中使用的标识符,用于唯一标识网络中的每个设备。

  • IPv4: 使用一个32位的整形数描述一个IP地址,4个字节,int型
  • IPv6: 使用一个128位的整形数描述一个IP地址,16个字节
  • 查看IP地址:
# linux
$ ifconfig

# windows
$ ipconfig

# 测试网络是否畅通
# 主机a: 192.168.1.11
# 当前主机: 192.168.1.12
$ ping 192.168.1.11     # 测试是否可用连接局域网
$ ping www.baidu.com    # 测试是否可用连接外网

# 特殊的IP地址: 127.0.0.1  ==> 和本地的IP地址是等价的
# 假设当前电脑没有联网, 就没有IP地址, 又要做网络测试, 可用使用 127.0.0.1 进行本地测试
1.3 端口

端口是计算机网络中用于**标识进程或服务的抽象概念。在一台计算机上,可以同时运行多个网络应用程序或服务,而端口就是用来区分它们的一种方式**。端口通过数字来标识,范围从0到65535。

  1. 端口号:
    • 端口号是一个16位的数字,用于唯一标识计算机上运行的特定服务或应用程序。端口号范围从0到65535,其中0到1023是被称为"知名端口",用于一些常见的服务,如HTTP(80端口)和HTTPS(443端口)等。
  2. TCP和UDP端口:
    • 端口分为TCP端口和UDP端口,这取决于应用程序所使用的传输协议。TCP(传输控制协议)和UDP(用户数据报协议)是两种常见的传输协议,它们使用不同的端口范围。例如,HTTP通常使用TCP的80端口,而DNS服务通常使用UDP的53端口。
1.4 网络分层模型

网络分层模型是一种将计算机网络功能划分为不同层次的概念性框架,以简化网络设计、管理和维护。其中最经典和广泛使用的分层模型是OSI(开放系统互联)模型和TCP/IP模型。以下是这两个模型的概述:

  1. OSI模型(开放系统互联模型): OSI模型是由国际标准化组织(ISO)定义的一种七层模型,每一层都执行特定的功能,且每一层的功能都建立在下一层提供的服务之上。这七个层次从下到上依次是:

    • 物理层(Physical Layer): 处理物理连接和传输介质,例如电缆、光纤等。
    • 数据链路层(Data Link Layer): 负责将物理层的数据划分成帧,并提供数据的可靠传输。
    • 网络层(Network Layer): 处理数据包的路由和转发,实现不同网络之间的通信。
    • 传输层(Transport Layer): 提供端到端的通信控制,包括数据的分段、重组和错误检测。
    • 会话层(Session Layer): 管理不同应用程序之间的对话和会话。
    • 表示层(Presentation Layer): 处理数据的格式转换、加密和压缩等。
    • 应用层(Application Layer): 提供网络服务和应用程序之间的接口。
  2. TCP/IP模型: TCP/IP模型是互联网上广泛使用的模型,它包含四个层次,从下到上依次是:

  • 网络接口层(Network Interface Layer): 类似于OSI的物理层和数据链路层,处理硬件设备和网络的连接。

  • 网络层(Internet Layer): 类似于OSI的网络层,负责数据包的路由和转发。(IP)

  • 传输层(Transport Layer): 类似于OSI的传输层,提供端到端的通信控制。(TCP, UDP)

  • 应用层(Application Layer): 同样对应OSI的应用层,提供网络服务和应用程序之间的接口。(HTTP, FTP, DNS)

在这里插入图片描述

1.5 数据封装

在这里插入图片描述

2. socket编程

与套接字相关的函数被包含在头文件sys/socket.h中。

2.1 字节序

字节序(Byte Order)指的是在计算机中,多字节数据类型的存储顺序(字符串就没有)。具体来说,它指定了在内存中多字节值的字节排列顺序。在多字节数据类型中,比如16位、32位或64位的整数,字节序定义了它们在内存中的存储方式。

有两种主要的字节序:大端序(Big Endian)和小端序(Little Endian)。

  1. 大端序(Big Endian):
    • 在大端序中,多字节数据的最高有效字节(Most Significant Byte,MSB)存储在最低的内存地址,而最低有效字节(Least Significant Byte,LSB)存储在最高的内存地址。
    • 举例来说,对于十六进制值0x12345678
      • 大端序:12 34 56 78
  2. 小端序(Little Endian):
    • 在小端序中,多字节数据的最低有效字节存储在最低的内存地址,而最高有效字节存储在最高的内存地址。
    • 对于同样的十六进制值0x12345678
      • 小端序:78 56 34 12
// 有一个16进制的数, 有32位 (int): 0xab5c01ff
// 字节序, 最小的单位: char 字节, int 有4个字节, 需要将其拆分为4份
// 一个字节 unsigned char, 最大值是 255(十进制) ==> ff(16进制) 
                 内存低地址位                内存的高地址位
--------------------------------------------------------------------------->
小端:         0xff        0x01        0x5c        0xab
大端:         0xab        0x5c        0x01        0xff

在进行跨平台数据交换时,需要考虑字节序的问题,通常使用网络字节序(也称为大端序)来确保数据的正确传输。

2.2 主机字节序和网络字节序的转换函数(端口)

从主机字节序到网络字节序的转换函数:htons、htonl;从网络字节序到主机字节序的转换函数:ntohs、ntohl

  • htons():主机字节序到网络字节序的16位整数转换。
  • htonl():主机字节序到网络字节序的32位整数转换。
#include <arpa/inet.h>

uint16_t hostShort = 0x1234;
uint32_t hostLong = 0x12345678;

uint16_t networkShort = htons(hostShort);
uint32_t networkLong = htonl(hostLong);
  • ntohs():网络字节序到主机字节序的16位整数转换。
  • ntohl():网络字节序到主机字节序的32位整数转换。
#include <arpa/inet.h>

uint16_t networkShort = 0x3412;
uint32_t networkLong = 0x78563412;

uint16_t hostShort = ntohs(networkShort);
uint32_t hostLong = ntohl(networkLong);
2.3 IP地址转换

主机字节序的IP地址是字符串, 网络字节序IP地址是整形

虽然IP地址本质是一个整形数,但是在使用的过程中都是通过一个字符串来描述,下面的函数描述了如何将一个字符串类型的IP地址进行大小端转换:

// 主机字节序的IP地址转换为网络字节序
int inet_pton(int af, const char *src, void *dst); 
  • af:地址族,可以是 AF_INET 表示IPv4,或者 AF_INET6 表示IPv6。
  • src:以字符串形式表示的IP地址。
  • dst:用于存储转换后的二进制地址的缓冲区。

函数的返回值是一个整数,如果转换成功,则返回 1,如果提供的地址无效,则返回 0,如果发生错误,则返回 -1。

  • 将计算机内部使用的二进制格式的IPv4和IPv6地址表示转换为人类可读形式的字符串表示法的函数
#include <arpa/inet.h>
// 将大端的整形数, 转换为小端的点分十进制的IP地址        
const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);
  • af:地址族,可以是 AF_INET 表示IPv4,或者 AF_INET6 表示IPv6。
  • src:指向包含二进制格式地址的指针。
  • dst:用于存储转换后的字符串的缓冲区。
  • size:缓冲区的大小。

函数的返回值是一个指向存储在 dst 中的字符串的指针,失败返回 NULL 并设置 errno

3. 套接字函数

3.1 sockaddr数据结构

sockaddr 是一个通用的套接字地址结构,用于在网络编程中表示网络地址信息

// 在写数据的时候不好用
struct sockaddr {
	sa_family_t sa_family;       // 地址族协议, ipv4
	char        sa_data[14];     // 端口(2字节) + IP地址(4字节) + 填充(8字节)
}

typedef unsigned short  uint16_t;
typedef unsigned int    uint32_t;
typedef uint16_t in_port_t;
typedef uint32_t in_addr_t;
typedef unsigned short int sa_family_t;
#define __SOCKADDR_COMMON_SIZE (sizeof (unsigned short int))

struct in_addr
{
    in_addr_t s_addr;
};  

// sizeof(struct sockaddr) == sizeof(struct sockaddr_in)
struct sockaddr_in
{
    sa_family_t sin_family;		/* 地址族协议: AF_INET */
    in_port_t sin_port;         /* 端口, 2字节-> 大端  */
    struct in_addr sin_addr;    /* IP地址, 4字节 -> 大端  */
    /* 填充 8字节 */
    unsigned char sin_zero[sizeof (struct sockaddr) - sizeof(sin_family) -
               sizeof (in_port_t) - sizeof (struct in_addr)];
};  

这些结构体用于在套接字编程中表示网络地址,通过将 sockaddr_in 结构体的地址转换为 sockaddr 结构体的地址,可以在函数参数中使用通用的 sockaddr 结构。例如,在调用套接字创建函数时,可以将一个 sockaddr_in 结构体的地址强制转换为 sockaddr 结构体的地址,以便在不同的网络函数中使用。

3.2 套接字函数

使用套接字通信函数需要包含头文件<arpa/inet.h>,包含了这个头文件<sys/socket.h>就不用在包含了。

  • 创建套接字函数
// 创建一个套接字
int socket(int domain, int type, int protocol);

参数:

  • domain: 使用的地址族协议
    • AF_INET: 使用IPv4格式的ip地址
    • AF_INET6: 使用IPv4格式的ip地址
  • type:
    • SOCK_STREAM: 使用流式的传输协议(TCP)
    • SOCK_DGRAM: 使用报式(报文)的传输协议(UDP)
  • protocol: 一般写0即可, 使用默认的协议
    • SOCK_STREAM: 流式传输默认使用的是tcp
    • SOCK_DGRAM: 报式传输默认使用的udp

返回值:

  • 成功: 可用于套接字通信的文件描述符
  • 失败: -1

函数的返回值是一个文件描述符,通过这个文件描述符可以操作内核中的某一块内存,网络通信是基于这个文件描述符来完成的。

  • 绑定端口
// 将文件描述符和本地的IP与端口进行绑定   
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

参数:

  • sockfd: 监听的文件描述符, 通过socket()调用得到的返回值
  • addr: 传入参数, 要绑定的IP和端口信息需要初始化到这个结构体中,IP和端口要转换为网络字节序
  • addrlen: 参数addr指向的内存大小, sizeof(struct sockaddr)

返回值:成功返回0,失败返回-1

  • 设置监听
// 给监听的套接字设置监听
int listen(int sockfd, int backlog);

参数:

  • sockfd: 文件描述符, 可以通过调用socket()得到,在监听之前必须要绑定 bind()
  • backlog: 同时能处理的最大连接要求,最大值为128

返回值:函数调用成功返回0,调用失败返回 -1

  • 等待并接受客户端的连接请求
// 等待并接受客户端的连接请求, 建立新的连接, 会得到一个新的文件描述符(通信的)		
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

参数:

  • sockfd: 监听的文件描述符
  • addr: 传出参数, 里边存储了建立连接的客户端的地址信息
  • addrlen: 传入传出参数,用于存储addr指向的内存大小

返回值:函数调用成功,得到一个文件描述符, 用于和建立连接的这个客户端通信,调用失败返回 -1

这个函数是一个阻塞函数,当没有新的客户端连接请求的时候,该函数阻塞;当检测到有新的客户端连接请求时,阻塞解除,新连接就建立了,得到的返回值也是一个文件描述符,基于这个文件描述符就可以和客户端通信了。

  • 接收数据
// 接收数据
ssize_t read(int sockfd, void *buf, size_t size);
ssize_t recv(int sockfd, void *buf, size_t size, int flags);

参数:

  • sockfd: 用于通信的文件描述符, accept() 函数的返回值
  • buf: 指向一块有效内存, 用于存储接收是数据
  • size: 参数buf指向的内存的容量
  • flags: 特殊的属性, 一般不使用, 指定为 0

返回值:

  • 大于0:实际接收的字节数
  • 等于0:对方断开了连接
  • -1:接收数据失败了

如果连接没有断开,接收端接收不到数据,接收数据的函数会阻塞等待数据到达,数据到达后函数解除阻塞,开始接收数据,当发送端断开连接,接收端无法接收到任何数据,但是这时候就不会阻塞了,函数直接返回0。

  • 发送数据
// 发送数据的函数
ssize_t write(int fd, const void *buf, size_t len);
ssize_t send(int fd, const void *buf, size_t len, int flags);

参数:

  • fd: 通信的文件描述符, accept() 函数的返回值
  • buf: 传入参数, 要发送的字符串
  • len: 要发送的字符串的长度
  • flags: 特殊的属性, 一般不使用, 指定为 0

返回值:

  • 大于0:实际发送的字节数,和参数len是相等的
  • -1:发送数据失败了

成功连接服务器之后, 客户端会自动随机绑定一个端口

// 服务器端调用accept()的函数, 第二个参数存储的就是客户端的IP和端口信息
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

参数:

  • sockfd: 通信的文件描述符, 通过调用socket()函数就得到了
  • addr: 存储了要连接的服务器端的地址信息: iP 和 端口,这个IP和端口也需要转换为大端然后再赋值
  • addrlen: addr指针指向的内存的大小 sizeof(struct sockaddr)

返回值:连接成功返回0,连接失败返回-1

4. TCP通信流程

TCP是一个**面向连接的,可靠的,流式传输协议,这个协议是一个传输层协议**。它确保数据在发送和接收之间按顺序、可靠地传输。

  • 面向连接:是一个双向连接,通过三次握手完成,断开连接需要通过四次挥手完成。
  • 安全:tcp通信过程中,会对发送的每一数据包都会进行校验, 如果发现数据丢失, 会自动重传
  • 流式传输:发送端和接收端处理数据的速度,数据的量都可以不一致

在这里插入图片描述

4.1 服务器端通信流程
  1. 创建用于监听的套接字, 这个套接字是一个文件描述符**socket()**
  2. 将得到的监听的文件描述符和本地的IP 端口进行绑定 bind()
  3. 设置监听(成功之后开始监听, 监听的是客户端的连接) listen()
  4. 等待并接受客户端的连接请求, 建立新的连接, 会得到一个新的文件描述符(通信的),没有新连接请求就阻塞 accept()
  5. 通信,读写操作默认都是阻塞的 read()/recv() write()/send()
  6. 断开连接, 关闭套接字 close()

在tcp的服务器端, 有两类文件描述符

监听的文件描述符

  • 只需要有一个
  • 不负责和客户端通信, 负责检测客户端的连接请求, 检测到之后调用accept就可以建立新的连接

通信的文件描述符

  • 负责和建立连接的客户端通信
  • 如果有N个客户端和服务器建立了新的连接, 通信的文件描述符就有N个,每个客户端和服务器都对应一个通信的文件描述符

在这里插入图片描述

文件描述符对应的内存结构:

  • 一个文件文件描述符对应两块内存, 一块内存是读缓冲区, 一块内存是写缓冲区
  • 读数据: 通过文件描述符将内存中的数据读出, 这块内存称之为读缓冲区
  • 写数据: 通过文件描述符将数据写入到某块内存中, 这块内存称之为写缓冲区

服务器端和客户端用文件描述夫建立连接和发送接收数据的流程:

监听的文件描述符:

  • 客户端的连接请求会发送到服务器端监听的文件描述符的读缓冲区中
  • 读缓冲区中有数据, 说明有新的客户端连接
  • 调用accept()函数, 这个函数会检测监听文件描述符的读缓冲区
    • 检测不到数据, 该函数阻塞
    • 如果检测到数据, 解除阻塞, 新的连接建立

通信的文件描述符:

  • 客户端和服务器端都有通信的文件描述符
  • 发送数据:调用函数 write() / send(),数据进入到内核中
    • 数据并没有被发送出去, 而是将数据写入到了通信的文件描述符对应的写缓冲区中
    • 内核检测到通信的文件描述符写缓冲区中有数据, 内核会将数据发送到网络中
  • 接收数据: 调用的函数 read() / recv(), 从内核读数据
    • 数据如何进入到内核程序猿不需要处理, 数据进入到通信的文件描述符的读缓冲区中
    • 数据进入到内核, 必须使用通信的文件描述符, 将数据从读缓冲区中读出即可
4.2 客户端的通信流程

在单线程的情况下客户端通信的文件描述符有一个, 没有监听的文件描述符

  1. 创建一个通信的套接字 socket()
  2. 连接服务器, 需要知道服务器绑定的IP和端口 connect()
  3. 通信 read()/recv() write()/send()
  4. 断开连接, 关闭文件描述符(套接字) close()
4.3 通信代码

从通信流程中可以看出, 客户端在connect()的时候, 需要知道服务器的IP和端口号, 所以必须要先启动服务器端(bind()函数绑定), 才能进行通信

基于tcp的服务器端通信代码
// server.cpp
// Created by 47468 on 2024/1/19.
//
#include <iostream>
#include "arpa/inet.h"
using namespace std;
#include "string.h"
#include "unistd.h"

int main() {
    // 1. 创建监听的套接字
    int lfd = socket(AF_INET, SOCK_STREAM, 0);
    if(lfd == -1){
        perror("socket");
        exit(0);
    }

    // 2. 将socket()返回值和本地的IP端口绑定到一起
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(10000);

    // INADDR_ANY代表本机的所有IP, 假设有三个网卡就有三个IP地址
    // 这个宏可以代表任意一个IP地址
    // 这个宏一般用于本地的绑定操作
    addr.sin_addr.s_addr = INADDR_ANY;

    // inet_pton(AF_INET, "192.168.237.131", &addr.sin_addr.s_addr);

    int ret = bind(lfd, (struct sockaddr*)&addr, sizeof(addr));
    if(ret == -1){
        perror("bind");
        exit(0);
    }

    // 3. 设置监听
    ret = listen(lfd, 128);
    if(ret == -1){
        perror("listen");
        exit(0);
    }

    // 4. 阻塞等待并接受客户端连接
    struct sockaddr_in cliaddr;
    int clilen = sizeof(cliaddr);
    int cfd = accept(lfd, (struct sockaddr*)&cliaddr, (socklen_t*)(&clilen));
    if(cfd == -1){
        perror("accept");
        exit(0);
    }

    // 打印客户端的地址信息
    char ip[24] = {0};
    cout << "客户端的ip地址: " << inet_ntop(AF_INET, &cliaddr.sin_addr.s_addr, ip, sizeof(ip))
         << ", 端口: " << ntohs(cliaddr.sin_port) << endl;

    // 5. 和客户端通信
    while(1){
        // 接收数据
        char buf[1024];
        memset(buf, 0, sizeof(buf));
        int len = read(cfd, buf, sizeof(buf));
        if(len > 0){
            cout << "客户端say: " << buf << endl;
            write(cfd, buf, len);
        } else if (len == 0){
            cout << "客户端断开了连接" << endl;
            break;
        } else {
            perror("read");
            break;
        }
    }
    close(lfd);
    close(cfd);

    return 0;
}
基于tcp通信的客户端通信代码
// client.cpp
// Created by 47468 on 2024/1/19.
//
#include <iostream>
#include "arpa/inet.h"
using namespace std;
#include "string.h"
#include "unistd.h"

int main() {
    // 1. 创建监听的套接字
    int fd = socket(AF_INET, SOCK_STREAM, 0);
    if(fd == -1){
        perror("socket");
        exit(0);
    }

    // 2. 链接服务器
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(10000); // 大端端口
    inet_pton(AF_INET, "192.168.110.129", &addr.sin_addr.s_addr);

    int ret = connect(fd, (struct sockaddr*)&addr, sizeof(addr));
    if(ret == -1){
        perror("connect");
        exit(0);
    }

    // 3. 和服务器通信
    int num = 0;
    while(1){
        // 发送数据
        char buf[1024];
        sprintf(buf, "你好服务器...%d\n", num++);
        write(fd, buf, strlen(buf) + 1);

        // 接收数据
        memset(buf, 0, sizeof(buf));
        int len = read(fd, buf, sizeof(buf));
        if(len > 0){
            cout << "服务器say: " << buf << endl;
        } else if (len == 0){
            cout << "服务器端断开了连接" << endl;
            break;
        } else {
            perror("read");
            break;
        }
        sleep(1);
    }
    close(fd);
    return 0;
}

代码测试图示:

  1. 服务器先开始, 客户端先结束

在这里插入图片描述

在这里插入图片描述

  1. 服务器端先开始, 服务器端先结束

在这里插入图片描述

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【JavaEE】文件操作与IO

作者主页&#xff1a;paper jie_博客 本文作者&#xff1a;大家好&#xff0c;我是paper jie&#xff0c;感谢你阅读本文&#xff0c;欢迎一建三连哦。 本文于《JavaEE》专栏&#xff0c;本专栏是针对于大学生&#xff0c;编程小白精心打造的。笔者用重金(时间和精力)打造&…

0121-1-计算机网络安全

计算机网络安全 1.Get 和 Post 的区别 结构&#xff1a;get 有请求体&#xff0c;post没有请求体 应用场景&#xff1a;get 用于获取数据&#xff0c;post用于提交数据&#xff1b; 缓存&#xff1a;get 的缓存保存在浏览器和web服务器日志中&#xff1b; 传输方式&#x…

typing python 类型标注学习笔记

在Python 3.5版本后引入的typing模块为Python的静态类型注解提供了支持。这个模块在增强代码可读性和维护性方面提供了帮助。 目录 简介为什么需要 Type hints typing常用类型typing初级语法typing基础语法默认参数及 Optional联合类型 (Union Type)类型别名 (Type Alias)子类型…

ESP32-HTTP_webServer库(Arduino)

ESP32-HTTP 介绍 ESP32是一款功能强大的微控制器&#xff0c;具有丰富的网络和通信功能。其中之一就是支持HTTP协议&#xff0c;这使得ESP32可以用于创建Web服务器。 HTTP是什么&#xff1f; HTTP&#xff08;Hyper Text Transfer Protocol&#xff09;&#xff0c;即超文本传…

[Error]连接iPhone调试时提示Failed to prepare the device for development.

环境&#xff1a; iPhone 7 Plus iOS 15.8 Xcode14.2 问题&#xff1a; 连接iPhone设备运行时&#xff0c;设备旁提示如下文案。 Failed to prepare the device for development. 这时强行点击运行按钮&#xff0c;会弹窗提示如下文案。 The run destination ZDMiPhone is n…

CTF show逆向5

1.查壳看看 没有壳&#xff0c;32位文件 同时注意到附件里的dll文件 2.放入IDA里看看 找到主函数 分别看看sub_4020B0 sub_4015BD 这两个函数 我发现一般看到MessageBoxA函数&#xff0c;都需要动态调试 动调看到 这里直接进行了返回,返回到了主函数 执行sub_4015BD函数 步…

力扣hot100 找到字符串中所有字母异位词 滑动窗口 双指针 一题双解

Problem: 438. 找到字符串中所有字母异位词 文章目录 思路滑动窗口 数组滑动窗口 双指针 思路 &#x1f469;‍&#x1f3eb; 参考题解 滑动窗口 数组 ⏰ 时间复杂度: O ( n ) O(n) O(n) &#x1f30e; 空间复杂度: O ( 1 ) O(1) O(1) class Solution { // 滑动窗口 …

【Gradle】Maven-Publishing

使用Java开发完成一个模块或者一个基础框架需要提供给团队项目使用&#xff0c;这个时候有两种方式可提供&#xff0c;一是提供源码&#xff0c;二是提供编译构建好的jar包供使用&#xff0c;这个时候需要讲构建好的包发布到公司的私服&#xff08;公司maven仓库&#xff09;&a…

分布式锁实现(mysql,以及redis)以及分布式的概念

道生一&#xff0c;一生二&#xff0c;二生三&#xff0c;三生万物 我旁边的一位老哥跟我说&#xff0c;你知道分布式是是用来干什么的嘛&#xff1f;一句话给我干懵了&#xff0c;我能隐含知道&#xff0c;大概是用来做分压处理的&#xff0c;并增加系统稳定性的。但是具体如…

C语言第四弹---printf和scanf详解

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】 printf和scanf详解 1、printf和scanf详解介绍1.1 printf1.1.1 基本用法1.1.2 占位符1.1.3 占位符列举1.1.4 输出格式1.1.4.1 限定宽度1.1.4.2 总是显示正负号1.1…

第一篇【传奇开心果系列】WeUI开发原生微信小程序:汽车租赁小程序示例

传奇开心果博文系列目录 WeUI开发原生微信小程序示例系列博文目录博文目录一、项目目标二、编程思路三、初步实现汽车租赁微信小程序示例代码四、实现汽车租赁微信小程序的登录注册示例代码五、实现汽车租赁微信小程序的订单管理示例代码六、整合实现比较完整的汽车租赁微信小程…

css绘制下拉框头部三角(分实心/空心)

1:需求图: 手绘下拉框 带三角 2:网上查了一些例子,但都是实心的, 可参考,如图: (原链接: https://blog.csdn.net/qq_33463449/article/details/113375804) 3:简洁版的: a: 实心: <view class"angle"/>.angle{width:0;height:0;border-left: 10px solid t…

[晓理紫]每日论文分享(有中文摘要,源码或项目地址)--机器人相关、强化学习

专属领域论文订阅 VX 扫吗关注{晓理紫|小李子}&#xff0c;每日更新论文&#xff0c;如感兴趣&#xff0c;请转发给有需要的同学&#xff0c;谢谢支持 分类: 大语言模型LLM视觉模型VLM扩散模型视觉导航具身智能&#xff0c;机器人强化学习开放词汇&#xff0c;检测分割 [晓理紫…

K8s(七)四层代理Service

Service概述 Service在Kubernetes中提供了一种抽象的方式来公开应用程序的网络访问&#xff0c;并提供了负载均衡和服务发现等功能&#xff0c;使得应用程序在集群内外都能够可靠地进行访问。 每个Service都会自动关联一个对应的Endpoint。当创建一个Service时&#xff0c;Ku…

JS-日期对象

日期对象&#xff1a;用来表示时间的对象 作用&#xff1a;可以得到当前系统时间 实例化 在代码中发现了new关键字时&#xff0c;一般将这个操作称为实例化 创建一个时间对象并获取时间 1&#xff09;获得当前时间 const datenew Date() 2)获得指定时间 const datenew D…

Python项目——计算器(PySide6+Pyinstaller)

1、介绍 使用python编写一个计算器&#xff0c;可以实现基本的运算。【注】该项目最终还有一些细小的bug没有完善&#xff0c;例如符号可以一直输入。 2、实现 使用pyCharm创建一个新的项目。 2.1、设计UI 使用Qt designer设计一个UI界面&#xff0c;保存ui文件&#xff0…

基于docker,k8s 搭建服务(单体docker-compose编排)

1、 yum -y install gcc yum -y instacc gcc-c 2、安装yum 工具 yum install -y yum-utils device-mapper-persistent-data lvm2 --skip-broken 3、设置docker镜像仓库 阿里云 yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.…

四种方法将 Docker Registry 迁移至 Harbor

Registry Docker Distribution Docker Distribution 是第一个是实现了打包、发布、存储和镜像分发的工具&#xff0c;起到 docker registry 的作用。&#xff08;目前 Distribution 已经捐赠给了 CNCF&#xff09;。其中 Docker Distribution 中的 spec 规范后来也就成为了 O…

Leetcode 2788. 按分隔符拆分字符串

我们可以先自己模拟一下分隔字符串的过程。如果只是简单的&#xff0c;遇到分隔符&#xff0c;将分隔符前后的子串加入结果的List&#xff0c;那么很显然并没有考虑到一个String中有多个字符串的情况。一种比较容易想到的方法是&#xff1a; 先对List中每个字符串遍历&#xf…

HBase节点故障的容错方案

HBase节点故障的容错方案 1. Master高可用1.1 选主和HA切换逻辑 2. RS高可用2.1 感知RS节点异常2.2 异常DN上的数据处理 4. 疑问和思考5. 参考文档 本文主要探讨hbase集群的高可用容错方案和容错能力的探讨。涉及Master和RS相关组件&#xff0c;在出现单机故障时相关的容错方案…