Linux基础-socket详解、TCP/UDP

文章目录

  • 一、Socket 介绍
  • 二、Socket 通信模型
  • 三、Socket 常用函数
    • 1 创建套接字
    • 2 绑定套接字
    • 3、监听连接
    • 4、接受连接
    • 5、接收和发送数据
      • 接收数据
      • 发送数据
    • 6、关闭套接字
  • 四、Socket编程试验
    • 1、源码
      • server.c
      • client.c
    • 2、编译:
    • 3、执行结果
  • 五、补充TCP和UDP协议的Socket流程对比
    • 1、TCP 和 和 UDP区别
    • 2、TCP工作流程图
    • 3、UDP工作流程图


一、Socket 介绍

所谓socket通常也称作 “套接字”,用于描述IP地址和端口,是一个通信链的句柄。应用程序通常通过 “套接字” 向网络发出请求或者应答网络请求 。
Socket 是计算机网络编程中一个重要的概念,它是在应用层和传输层之间提供的一种抽象接口,用于实现应用程序之间的数据交换。Socket 允许程序员使用一种通用的接口来访问底层传输协议,如 TCP 和 UDP,以便进行网络通信。
Socket 是一种编程接口,它提供了一种标准化的方式来创建网络连接,并允许应用程序在网络上发送和接收数据。Socket API 提供了一组函数,这些函数可以用于创建和配置套接字,建立连接,发送和接收数据,以及关闭连接等操作。
Socket 包括流式 Socket(基于 TCP)数据报式 Socket(基于 UDP),其中,TCP面向连接,可靠性较高,可实现有序、零差错的传输;而 UDP 不能确保传输的数据按序、及时到达,因此,UDP 主要出现在数据可靠性要求较低的场合。常见的 Socket 编程相关术语进行介绍:

相关术语介绍
IP 地址唯一标识了网络上的一台主机
端口号是一个 16 位数字,用于标识一个应用程序在主机上的具体位置
套接字用于标识一条网络连接的两端,包含 IP 地址和端口号
服务器在网络上提供服务的主机
客户端与服务器进行通信的主机

一 个Socket 主要由5个信息所构成,分别为:协议,本地地址,本地端口号,远地地址,远地端口号。

  • 协议指定了socket所使用的的通讯协议,一般有TCP或者UDP等。
  • 本地IP地址即本地主机的地址。
  • 本地端口号用以和本地运行的其他程序所区分。
  • 远地IP地址即依照网络协议分配给远程主机的网络地址。
  • 远地端口号用以和远程主机运行的其他程序所区分。

二、Socket 通信模型

Socket 编程通常分为两个部分:服务器端和客户端
服务器端监听一个指定的端口,等待客户端连接。一旦客户端连接到服务器端,服务器端将创建一个新的套接字来处理该客户端的请求。服务器可以同时处理多个客户端请求,每个客户端都会有自己的套接字连接。
客户端首先创建一个套接字,然后连接到服务器端的指定 IP 地址和端口号。一旦连接建立,客户端可以通过套接字发送和接收数据。客户端通常是一次性连接,一旦任务完成就关闭套接字。
在这里插入图片描述
Socket 编程可以用于各种不同的应用程序,例如聊天程序、文件传输、在线游戏等。Socket编程还可以用于创建网络服务器,提供 Web 服务、FTP 服务、邮件服务等。

三、Socket 常用函数

socket 编程的系统调用常用函数如下所示:

  • 创建套接字 socket(domain, type, protocol)
  • 绑定套接字 bind(sockfd, addr, addrlen)
  • 监听连接 listen(sockfd, backlog)
  • 接受连接 accept(sockfd, addr, addrlen)
  • 接收和发送数据 recv(sockfd, buf, len, flags)、send(sockfd, buf, len, flags)
  • 关闭套接字 close(sockfd)

1 创建套接字

在 Linux socket 编程中,创建套接字是构建网络应用程序的第一步。套接字可以理解为应用程序和网络之间的桥梁,用于在网络上进行数据的收发和处理。在 Linux 中,可以使用 socket 系统调用创建套接字。该系统调用的原型和所需头文件如下所示:

#include <sys/types.h>
#include <sys/socket.h>
int socket( (int domain, int type, int protocol );

其中,domain 参数指定了套接字的协议族,type 参数指定了套接字的类型,protocol 参数指定了套接字所使用的具体协议。下面分别介绍这三个参数的含义:

  • 协议族
    协议族指定了套接字所使用的协议类型,常用的协议族包括 AF_INET、AF_INET6、AF_UNIX等。其中,AF_INET 表示 IPv4 协议族,AF_INET6 表示 IPv6 协议族,AF_UNIX 表示 Unix 域协议族。
  • 套接字类型
    套接字类型指定了套接字的数据传输方式,常用的套接字类型包括 SOCK_STREAM、SOCK_DGRAM、SOCK_RAW 等。其中,SOCK_STREAM 表示面向连接的流套接字,主要用于可靠传输数据,例如 TCP 协议。SOCK_DGRAM 表示无连接的数据报套接字,主要用于不可靠传输数据,例如 UDP 协议。SOCK_RAW 表示原始套接字,可以直接访问底层网络协议。
  • 协议类型
    协议类型指定了套接字所使用的具体协议类型,常用的协议类型包括 IPPROTO_TCP、IPPROTO_UDP、IPPROTO_ICMP 等。其中,IPPROTO_TCP 表示 TCP 协议,IPPROTO_UDP 表示 UDP协议,IPPROTO_ICMP 表示 ICMP 协议,通常使用 0 表示由系统自动选择适合的协议。
    例如可以使用以下代码创建一个新的套接字:
int sockfd = = socket(AF_INET, SOCK_STREAM, 0);

2 绑定套接字

创建套接字后,需要将其与一个网络地址绑定,以便其他计算机可以访问该套接字。在 Linux系统下,可以使用 bind()系统调用绑定套接字和地址。该系统调用的原型和所需头文件如下所示:

#include <sys/types.h>
#include <sys/socket.h>
int bind( (int sockfd, const struct sockaddr *addr, socklen_t addrlen);

其中,sockfd 参数指定了需要绑定的套接字描述符,addr 参数指定了需要绑定的地址信息,可以是 struct sockaddr_in 或 struct sockaddr_in6 等结构体类型,addrlen 参数指定了地址信息的长度。使用以下代码将套接字和地址绑定:

// bind port 
// 创建一个 sockaddr_in 结构体类型的 servaddr 变量用于存储服务器的地址信息,并将其清零。
struct sockaddr_in bindaddr;
memset (&bindaddr, 0, sizeof(bindaddr);
bindaddr.sin_family = AF_INET;//指定使用 IPv4 协议(AF_INET)
bindaddr.sin_addr.s_addr = htonl(INADDR_ANY);//监听本地任意可用的 IP 地址(INADDR_ANY)
bindaddr.sin_port = htons(3000);//使用指定的端口号(port)
// 将套接字 listenfd 绑定到指定的地址 bindaddr上,bind() 函数返回值为 0 表示绑定成功
if(0 != bind(listenfd, (struct sockaddr *)&bindaddr, sizeof(bindaddr))) {printf("bind error\n");return -1;
}

在初始化 sockaddr_in 结构体时,用到了以下函数:

  • memset() :用来将 sockaddr_in 结构体的各个成员变量初始化为 0,这是一个常用的初始化方式。其函数原型如下:
 #include <string.h> // s 参数是需要被初始化的内存区域指针,c 参数是填充字符,n 参数是需要填充的内存字节数。void *memset( void *s, int c, size_t n ); 
  • htonsl()和 和 htons():用于将本机字节序的端口号转换为网络字节序的端口号。其函数原型如下:
 #include <arpa/inet.h> 
uint32_t htonl(uint32_t hostlong );
uint16_t htons(uint16_t hostshort);

其中,hostshort 和 hostlong 参数是本机字节序的端口号,函数返回值是网络字节序的端口号。

3、监听连接

绑定套接字后,需要开始监听连接请求,以便其他网络上的客户端能够与该套接字建立连接。这一步骤通常在服务器端完成。在 Linux 系统下,可以使用 listen()系统调用监听套接字。该系统调用的原型如下:

#include <sys/socket.h> 
int listen(int socket, int backlog);

其中,sockfd 参数指定了需要监听的套接字描述符,backlog 参数指定了连接队列的长度,即等待接受的连接数。例如可以使用以下代码开始监听连接.

// start listen
if (listen(listenfd, 2) != 0) {printf("listem error\n");return -1;
}

4、接受连接

当有客户端请求连接时,需要接受该连接并进行处理。在 Linux 系统下,可以使用 accept(),系统调用接受连接请求。该系统调用的原型和所需头文件如下所示:

#include <sys/socket.h>
int accept (int __fd, __SOCKADDR_ARG __addr, socklen_t *__restrict __addr_len);

其中,sockfd 参数指定了需要接受连接的套接字描述符,addr 参数用于存储客户端的地址信息,addrlen 参数用于存储地址信息的长度。使用以下代码接受连接请求:

// 定义一个 sockaddr_in 结构体,用于存储客户端的 IP 地址和端口号
struct sockaddr_in clientaddr;
// 定义一个 socklen_t 类型的变量 clientaddrlen ,用于存储客户端地址结构体的长度
socklen_t clientaddrlen = sizeof(clientaddr);// 调用 accept() 系统调用,接受客户端的连接请求,并返回一个新的套接字描述符 connfd,用于与客户端进行通信。
// accept() 函数会阻塞程序,直到有客户端连接到服务器端。
// listenfd 是服务端的监听套接字, clientaddr 是指向 sockaddr_in 结构体的指针,用于存储客户端的地址信息。
// clientaddrlen 是客户端地址结构体的长度,accept() 函数会将实际接受到的客户端地址长度存储到该变量中。
int clientfd = accept(listenfd, (struct sockaddr *)&clientaddr, &clientaddrlen);
if (clientfd >= 0) { // 判断 accept() 函数的返回值,判断客户端连接是否失败// 处理接收数据} else{printf("accept error\n");
}

5、接收和发送数据

在 Linux socket 编程中,接收和发送数据是套接字编程的核心步骤之一。当套接字绑定并且处于监听状态,已经成功接受了客户端的连接请求后,接下来就是进行数据的收发。下面将详细介绍如何在 Linux 系统中实现接收和发送数据的过程。

接收数据

在接收数据之前,需要先了解数据在网络传输中的一些基本概念。在 TCP 协议中,发送方发送的数据被分割成一个个 TCP 报文段,每个报文段都包含一个 TCP 首部和数据部分。TCP首部中包含了一些控制信息,如序号、确认号、窗口大小等,用来保证数据的可靠传输。而数据部分则是发送方发送的应用层数据,如 HTTP 报文、FTP 文件等。
在 Linux socket 编程中,接收数据的过程分为两步:先接收 TCP 首部,再接收数据部分。具体步骤如下:
(1)创建一个缓冲区用于接收数据。缓冲区的大小一般为数据部分的大小。
(2)调用 recv() 系统调用接收数据。其函数原型和所需头文件如下:

#include <sys/socket.h> 
ssize_t recv(int sockfd, void *buffer, size_t length, int flags );

其中,sockfd 参数是需要接收数据的套接字描述符,buf 参数是用于存储接收数据的缓冲区指针,len 参数是需要接收的数据的最大长度,flags 参数是接收标志,通常为 0。函数返回值为实际接收到的字节数,如果返回值为 0,表示对端已经关闭连接。
(3)在调用 recv() 系统调用时,会先接收 TCP 首部,然后再接收数据部分。如果数据部分比较大,可能需要多次调用 recv() 系统调用才能接收完整的数据。因此,需要使用一个循环来不断接收数据,直到接收到全部数据或者出现错误为止。另外,需要注意的是,recv() 系统调用是一个阻塞调用,即程序会一直等待直到接收到数据或者出现错误才会返回。如果不希望阻塞调用,可以使用非阻塞 I/O 或者多路复用技术。
(4) 处理接收到的数据。在数据接收完成后,需要对接收到的数据进行处理。具体处理方式根据具体的应用场景而定,如将接收到的数据显示在终端上、将数据写入文件等。

发送数据

发送数据的步骤如下:
(1)定义数据缓冲区:需要定义一个用于存储待发送数据的缓冲区,比如 char buf[MAXLINE]。
(2)将数据拷贝到缓冲区:将需要发送的数据拷贝到缓冲区中,可以使用 strcpy()、memcpy() 等函数进行拷贝操作。
(3)使用 send() 函数发送数据:send() 函数用于向已经建立连接的套接字发送数据,其函数原型如下:

#include <sys/socket.h> 
ssize_t send( int sockfd, const void *buf, size_t len, int flags);

函数调用成功将返回发送数据的字节数(返回值为非负数),返回-1 表示发送失败。sockfd 需要发送数据的套接字描述符;buf 待发送数据的缓冲区指针;len 待发送数据的长度;flags 传输标志,通常为 0。

// send data
int ret = send(clientfd, buf, strlen(buf), 0);
if (ret != strlen(buf)){printf("send data error\n");return -1;
}

需要注意的是,send() 函数并不保证一次能够将所有数据都发送出去,如果数据量比较大,可能需要多次调用 send() 函数才能将所有数据发送出去。
(4)判断是否发送完毕:可以通过判断 send() 函数的返回值和待发送数据的长度是否相等来确定是否发送完毕。

6、关闭套接字

关闭套接字是一个非常重要的步骤。当套接字不再需要使用时,应该立即关闭以释放系统资源和避免资源浪费。关闭套接字的步骤非常简单,只需要调用 close() 系统调用即可。close()
系统调用的函数原型如下:

int close( (int sockfd );

其中,sockfd 参数是需要关闭的套接字描述符。函数返回值为 0 表示成功,返回值为 -1表示失败。

四、Socket编程试验

1、源码

server.c

#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
// 自定义传输的数据
typedef struct  msgbuf{int id;char str[32];
} msgbuf;int main() {// create socketint listenfd = socket(AF_INET, SOCK_STREAM, 0);if(-1 == listenfd) {printf("create socket error");return -1;}printf("server create socket ok!\n");// bind port // 创建一个 sockaddr_in 结构体类型的 servaddr 变量用于存储服务器的地址信息,并将其清零。struct sockaddr_in bindaddr;memset (&bindaddr, 0, sizeof(bindaddr));bindaddr.sin_family = AF_INET;//指定使用 IPv4 协议(AF_INET)bindaddr.sin_addr.s_addr = htonl(INADDR_ANY);//监听本地任意可用的 IP 地址(INADDR_ANY)bindaddr.sin_port = htons(3000);//使用指定的端口号(port)// 将套接字 listenfd 绑定到指定的地址 bindaddr上,bind() 函数返回值为 0 表示绑定成功if(0 != bind(listenfd, (struct sockaddr *)&bindaddr, sizeof(bindaddr))) {printf("bind error\n");return -1;}// start listenif (listen(listenfd, 2) != 0) {printf("listem error\n");return -1;}msgbuf socmsg;// 定义一个 sockaddr_in 结构体,用于存储客户端的 IP 地址和端口号struct sockaddr_in clientaddr;// 定义一个 socklen_t 类型的变量 clientaddrlen ,用于存储客户端地址结构体的长度socklen_t clientaddrlen = sizeof(clientaddr);// accept connection// 调用 accept() 系统调用,接受客户端的连接请求,并返回一个新的套接字描述符 connfd,用于与客户端进行通信。// accept() 函数会阻塞程序,直到有客户端连接到服务器端。// listenfd 是服务端的监听套接字, clientaddr 是指向 sockaddr_in 结构体的指针,用于存储客户端的地址信息。// clientaddrlen 是客户端地址结构体的长度,accept() 函数会将实际接受到的客户端地址长度存储到该变量中。int clientfd = accept(listenfd, (struct sockaddr *)&clientaddr, &clientaddrlen);if (clientfd >= 0) { // 判断 accept() 函数的返回值,判断客户端连接是否失败while (1) {        	socmsg.id = 0;memset(socmsg.str, ' ',sizeof(socmsg.str));// receive dataint ret = recv(clientfd, &socmsg, sizeof(socmsg), 0);if (ret > 0) {printf("recv data from client, data: %d %s\n", socmsg.id, socmsg.str);printf("send data ...\n");// send dataret = send(clientfd, &socmsg, sizeof(socmsg), 0);if (ret != sizeof(socmsg)) {printf("send data error.\n");}} else {// printf("recv data error.\n");sleep(1);}}		close(clientfd);} else{printf("accept error\n");}//close socketclose(listenfd);return 0;
}

client.c

#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>typedef struct  msgbuf{int id;char str[32];
} msgbuf;int main(int argc, const char *argv[]) {char *ip = "192.168.1.100"; // 服务器默认的IP,可以改成服务器实际IP// create socketint clientfd = socket(AF_INET, SOCK_STREAM, 0);if(-1 == clientfd) {printf("create socket error");return -1;}printf("client create socket ok!\n");// connect server struct sockaddr_in serveraddr;serveraddr.sin_family = AF_INET;if (argc == 2) { // 如果有输入IP参数,使用输入的IP参数printf("%s\r\n", argv[1]);serveraddr.sin_addr.s_addr = inet_addr(argv[1]);  // 从命令行参数中获取服务器 IP 地址} else {serveraddr.sin_addr.s_addr = inet_addr(ip);}serveraddr.sin_port = htons(3000);if(-1 == connect(clientfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr))) {printf("connect error\n");return -1;}printf("connect OK\n");msgbuf socmsg;int i =0;while(1) {sleep(1);socmsg.id = i++;memcpy(socmsg.str,"this is my test msg", strlen("this is my test msg"));// send dataint ret = send(clientfd, &socmsg, sizeof(socmsg), 0);if (ret != sizeof(socmsg)){printf("send data error\n");return -1;}printf("send data ok, %d %s\n",socmsg.id, socmsg.str);// receive datasocmsg.id = 0;// socmsg.str[128] = {0};memset(socmsg.str, ' ',sizeof(socmsg.str));ret = recv(clientfd, &socmsg, sizeof(socmsg), 0);if (ret > 0) {printf("receive data from server: %d %s\n", socmsg.id, socmsg.str);} else {printf("receive data error\n");}}// close socketclose(clientfd);return 0;
}

2、编译:

gcc -o server server.c
gcc -o client client.c

如果client是在板子上执行,需要使用板子系统对应的交叉编译器来编译。例如:aarch64-linux-gnu-gcc -o client client.c

3、执行结果

在这里插入图片描述
在这里插入图片描述
本例程只作为一个简单的demo,体验下socket通讯。

五、补充TCP和UDP协议的Socket流程对比

在一般的网络书籍中,网络协议被分为 5 层:
在这里插入图片描述
⚫应用层:它是体系结构中的最高层,直接为用户的应用进程(例如电子邮件、文件传输和终端仿真)提供服务。在因特网中的应用层协议很多,如支持万维网应用的 HTTP 协议,支持电子邮件的 SMTP 协议,支持文件传送的 FTP , DNS,POP3, SNMP, Telnet 等等。
⚫运输层:负责向两个主机中进程之间的通信提供服务。
运输层主要使用以下两种协议:
① 传输控制协议 TCP(Transmission Control Protocol):面向连接的,数据传输的单位是报文段,能够提供可靠的交付。
② 用户数据包协议 UDP(User Datagram Protocol):无连接的,数据传输的单位是用户数据报,不保证提供可靠的交付,只能提供“尽最大努力交付”。
⚫ 网络层:负责将被称为数据包(datagram)的网络层分组从一台主机移动到另一台主机。
⚫ 链路层:因特网的网络层通过源和目的地之间的一系列路由器路由数据报。
⚫ 物理层:在物理层上所传数据的单位是比特。物理层的任务就是透明地传送比特流。
这些层对于初学者来说很难理解,我们只需要知道:我们需要使用“运输层”编写应用程序,我们的应用程序位于“应用层”。使用“运输层”时,可以选择 TCP 协议,也可以选择 UDP 协议。

1、TCP 和 和 UDP区别

TCP 向它的应用程序提供了面向连接的服务。这种服务有 2 个特点:可靠传输、流量控制(即发送方/接收方速率匹配)。它包括了应用层报文划分为短报文,并提供拥塞控制机制。
UDP 协议向它的应用程序提供无连接服务。它没有可靠性,没有流量控制,也没有拥塞控制。
在这里插入图片描述

既然 TCP 提供了可靠数据传输服务,而 UDP 不能提供,那么 TCP 是否总是首选呢?

答案是否定的,因为有许多应用更适合用 UDP,举个例子:视频通话时,使用 UDP,偶尔的丢包、偶尔的花屏时可以忍受的;如果使用 TCP,每个数据包都要确保可靠传输,当它出错时就重传,这会导致后续的数据包被阻滞,视频效果反而不好。使用 UDP 时,有如下特点:
① 关于何时发送什么数据控制的更为精细
采用 UDP 时只要应用进程将数据传递给 UDP,UDP 就会立即将其传递给网络层。而 TCP 有重传机制,而不管可靠交付需要多长时间。但是实时应用通常不希望过分的延迟报文段的传送,且能容忍一部分数据丢失。
② 无需建立连接,不会引入建立连接时的延迟。
③ 无连接状态,能支持更多的活跃客户。
④ 分组首部开销较小。

2、TCP工作流程图

在这里插入图片描述

3、UDP工作流程图

在这里插入图片描述

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

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

相关文章

OpenAI 新推出 AI 问答搜索引擎——SearchGPT 震撼登场

您的浏览器不支持 video 标签。 OpenAI-SearchGPT 近日&#xff0c;OpenAI 曝光了自己的一款令人瞩目的 AI 问答搜索引擎——SearchGPT。这款搜索引擎带来了全新的搜索体验&#xff0c;给整个行业带来了巨大的压力。 SearchGPT 支持多种强大的功能。首先&#xff0c;它能够通过…

分布式与一致性协议之Raft算法(三)

Raft算法 如何复制日志 你可以把Raft算法的日志复制理解成一个优化后的二阶段提交(将二阶段优化成了一阶段)。优化后减少了一半的往返消息&#xff0c;也就是降低了一半的消息延迟&#xff0c;那日志复制的具体过程又是什么呢&#xff1f; 首先&#xff0c;领导者进入第一阶段…

【Redis 开发】多级缓存,本地进程缓存Caffeine

多级缓存 多级缓存本地进程缓存CaffeineCaffeine三种缓存驱逐策略 多级缓存 Redis处理并发的能力是非常强大的&#xff0c;但是tomcat的支持并发的能力跟不上Redis的性能&#xff0c;导致整体性能的下降 Redis缓存失效时&#xff0c;会对数据库产生冲击&#xff0c;之间再无屏…

LeetCode1017题:负二进制转换(原创)

【题目描述】 给你一个整数 n &#xff0c;以二进制字符串的形式返回该整数的 负二进制&#xff08;base -2&#xff09;表示。注意&#xff0c;除非字符串就是 "0"&#xff0c;否则返回的字符串中不能含有前导零。 示例 1&#xff1a; 输入&#xff1a;n 2 输出&…

基于Springboot的数字化农家乐管理平台(有报告)。Javaee项目,springboot项目。

演示视频&#xff1a; 基于Springboot的数字化农家乐管理平台&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系…

踏上R语言之旅:解锁数据世界的神秘密码(四)

文章目录 前言一、多元线性回归1.多元线性回归模型的建立2.多元线性回归模型的检验 二、多元线性相关分析1.矩阵相关分析2.复相关分析 三、回归变量的选择方法1.变量选择准则2.变量选择的常用准则3.逐步回归分析 总结 前言 回归分析研究的主要对象是客观事物变量间的统计关系。…

选择内核注意力 SK | Selective Kernel Networks

论文名称&#xff1a;《Selective Kernel Networks》 论文地址&#xff1a;https://arxiv.org/pdf/1903.06586.pdf 代码地址&#xff1a;https://github.com/implus/SKNet 在标准的卷积神经网络中&#xff0c;每层人工神经元的感受野被设计为具有相同的大小。神经科学界已经广…

使用OkHttp 缓存 API 调用提高Android应用性能

使用OkHttp 缓存 API 调用提高Android应用性能 坦率地说&#xff0c;我们都遇到过这样的情况——焦急地刷新应用&#xff0c;看着加载图标不停地旋转&#xff0c;等待那个至关重要的 API 响应。这样的等待我们已经是炉火纯青了&#xff0c;是吧&#xff1f;手指有节奏地轻敲屏…

《R语言与农业数据统计分析及建模》——多重共线性和逐步回归

一、多重共线性 多重共线性&#xff1a;在多元线性回归时&#xff0c;多个自变量之间存在高度相关关系&#xff0c;时模型估计失真或难以估计准确的情况。 一般地&#xff0c;多元线性回归中自变量间应尽量相互独立。常规模型诊断方法难以检测多重共线性。 1、案例解释 作物产…

ActiveMQ 反序列化漏洞 (CVE-2015-5254)

一、漏洞描述 Apache ActiveMQ 是由美国阿帕奇&#xff08;Apache&#xff09;软件基金会开发的开源消息中间件&#xff0c;支持 Java 消息服务、集群、Spring 框架等。属于消息队列组件(消息队列组件&#xff1a;分布式系统中的重要组件&#xff0c;主要解决应用耦合、异步消息…

数据库|TiDB-Server API的高效应用指南

一、API介绍 1.Status 显示TiDB 连接数、版本和git_hash 信息 tidb-server_ip:status_port/status { "connections": 0, "version": "5.7.25-TiDB-v6.1.1", "git_hash": "5263a0abda61f102122735049fd0dfadc7b7f822" } 2.St…

mysql-sql-练习题-4-标记

标记 连续登录2-7天用户建表排名找规律 最大连胜次数建表只输出连胜结果输出所有连续结果 连续登录2-7天用户 建表 create table continuous_login(user_id1 integer comment 用户id,date_login date comment 登陆日期 ) comment 用户登录表;insert into continuous_login val…

LT2611UX四端口 LVDS转 HDMI2.0,带音频

描述LT2611UX 是一款面向机顶盒、DVD 应用的高性能 LVDS 至 HDMI2.0 转换器。LVDS输入可配置为单端口、双端口或四端口&#xff0c;具有1个高速时钟通道和3~4个高速数据通道&#xff0c;工作速率最高为1.2Gbps/通道&#xff0c;可支持高达19.2Gbps的总带宽。LT2611UX 支持灵活的…

002 springCloudAlibaba Sentinel流控-关联

当与A关联的资源B达到阀值后&#xff0c;就限流A自己 文章目录 FlowLimitController.javaSentinelServerApplication.javaServletInitializer.javaapplication.yamlpom.xmlpom.xml 启动Sentinel8080 - java -jar sentinel-dashboard-1.7.0.jar 启动微服务8401 启动8401微服务…

72、栈-每日温度

思路&#xff1a; 第一种方法&#xff0c;双循环&#xff0c;第一层循环拿出一个元素&#xff0c;第二层循环寻找最近比当前大的元素位置。 第二种方法&#xff1a;使用栈来实现。 初始化&#xff1a; int[] ans 用来存储每一天之后多少天温度会升高。Stack<Integer> 用…

Java | AI+编程 | 如何使用通义灵码提升开发效率

大家好&#xff0c;我是程序员影子 | 全网同名 一名致力于帮助更多朋友快速入门编程的程序猿 今天&#xff0c;我将以小白入门的视角带着大家学会如何在Idea上使用通义灵码&#xff0c;提高开发效率&#xff0c;减少重复工作&#xff1b;话不多说&#xff0c;我们直接进入正题…

golang beego结合wire依赖注入及自动路由

1 安装wire 1.1 通过命令直接安装 go install github.com/google/wire/cmd/wirelatest 1.2 通过go get方式安装 go get github.com/google/wire/cmd/wire进入目录编译 cd C:\Users\leell\go\pkg\mod\github.com\google\wirev0.6.0\cmd\wire go build 然后将wire.exe移动到…

广交会烹饪机器人用上大模型 支付宝小程序云提供技术支持

近日&#xff0c;第135届广交会正在火热进行&#xff0c;记者获悉&#xff0c;支付宝小程序云助力合作伙伴田螺云厨&#xff0c;在烹饪机器人上开始用上大模型技术。各类智能产品的亮相&#xff0c;从中国制造迈向中国创造&#xff0c;也成为广交会的一个亮点。 &#xff08;图…

鲲鹏华为云--OBS

文章目录 1.创建桶2.上传对象3.下载对象4.分享对象5. 删除对象6.删除桶 1.创建桶 创建桶 2.上传对象 点击创建的桶–“上传对象” 拖拽本地文件或文件夹至“上传对象”区域框内添加待上传的文件。 也可以通过单击“上传对象”区域框内的“添加文件”&#xff0c;选择本地…

C语言函数指针的使用、函数指针数组及使用、指向函数指针数组的指针,指针进阶版的冒泡排序等介绍

文章目录 前言一、函数指针的使用1. 加减乘除计算器普通实现2. 加减乘除计算机函数指针实现 二、函数指针数组1. 函数指针数组的书写2. 两个有趣的代码3. 函数指针数组的使用 三、指向函数指针数组的指针四、指针进阶_冒泡排序1.整型冒泡排序2. C语言qsort函数3. 仿写C语言qsor…