Linux网络编程——socket 通信基础

Linux网络编程——socket 通信基础

    • 1. socket 介绍
    • 2. 字节序
      • 2.1 简介
      • 2.2 字节序举例
      • 2.3 字节序转换函数
    • 3. socket 地址
      • 3.1 通用 socket 地址
      • 3.2 专用 socket 地址
    • 4. IP地址转换(字符串ip -> 整数,主机、网络字节序的转换 )
    • 5. TCP 通信流程
    • 6. 套接字函数

1. socket 介绍

    所谓 socket(套接字),就是对网络中不同主机上的应用进程之间进行 双向通信的 端点的抽象。一个套接字就是网络上进程通信的一端,提供了 应用层进程 利用网络协议交换数据的机制。从所处的地位来讲,套接字 上联 应用进程,下联 网络协议栈,是 应用程序 通过 网络协议 进行通信的接口,是 应用程序 与 网络协议根 进行交互的接口。

    socket 可以看成是两个网络应用程序进行通信时,各自通信连接中的端点,这是一个 逻辑上的概念。它是网络环境中 进程间通信 的 API,也是可以被命名和寻址的通信端点,使用中的每一个套接字都有其类型和一个与之相连进程。通信时其中一个网络应用程序将要传输的一段信息写入它所在主机的 socket 中,该 socket 通过与 网络接口卡(NIC)相连的传输介质将这段信息送到另外一台主机的 socket 中,使对方能够接收到这段信息。socket 是由 IP 地址 和 端口 结合的,提供向应用层进程传送数据包的机制。

    socket 本身有“ 插座 ”的意思,在 Linux 环境下,用于表示 进程间网络通信 的 特殊文件类型。本质为 内核 借助 缓冲区 形成的 伪文件。既然是文件,那么理所当然的,我们可以使用 文件描述符 引用套接字。与管道类似的,Linux 系统将其封装成文件的目的是为了 统一接口,使得 读写套接字 和 读写文件 的操作一致。区别是 管道 主要应用于 本地进程间通信,而 套接字 多应用于 网络进程间数据的传递。

在这里插入图片描述

使用 文件描述符 fd 引用 socket:
在这里插入图片描述

套接字通信 分两部分:

  • 服务器端:被动 接受连接,一般不会主动发起连接
  • 客户端:主动 向服务器发起连接

socket 是一套 通信的接口,Linux 和 Windows 都有,但是有一些细微的差别。

2. 字节序

2.1 简介

    现代 CPU 的累加器 一次都能 装载(至少)4 字节(这里考虑 32 位机),即一个整数。那么这 4 字节 在 内存 中排列的顺序 将影响它被累加器装载成的整数的值,这就是字节序问题。在各种计算机体系结构中,对于字节、字等的存储机制有所不同,因而引发了计算机通信领域中一个很重要的问题,即通信双方交流的信息单元(比特、字节、字、双字 等等)应该以什么样的顺序进行传送。如果不达成一致的规则,通信双方将无法进行正确的编码/译码从而导致通信失败。

    字节序,顾名思义 字节的顺序,就是大于一个字节类型的数据在内存中的存放顺序 (一个字节的数据当然就无需谈顺序的问题了)。

    字节序 分为 小端字节序(Big-Endian) 和 大端字节序(Little-Endian)。

  • 小端字节序则 是指 整数的 低位字节 则存储在内存的 低地址 处,而 高位字节 存储在内存的 高地址 处。
  • 大端字节序 是指一个 整数的 最高位字节 (23 ~ 31 bit)存储在内存的 低地址 处,低位字节(0 ~ 7 bit)存储在 内存的 高地址 处;

2.2 字节序举例

小端字节序

  • 0x 01 02 03 04 (十六进制,四字节。ff = 255)

  • 内存的方向 ----->

  • 内存的低位 -----> 内存的高位
    04 03 02 01

0x 11 22 33 44 12 34 56 78 (八个字节)
在这里插入图片描述

大端字节序

  • 0x 01 02 03 04
  • 内存的方向 ----->
  • 内存的低位 -----> 内存的高位
    01 02 03 04

0x 12 34 56 78 11 22 33 44
在这里插入图片描述

  • 通过代码检测当前主机的字节序
#include <stdio.h>int main() {union {short value;    // 2字节char bytes[sizeof(short)];  // char[2]} test;test.value = 0x0102;if((test.bytes[0] == 1) && (test.bytes[1] == 2)) {printf("大端字节序\n");} else if((test.bytes[0] == 2) && (test.bytes[1] == 1)) {printf("小端字节序\n");} else {printf("未知\n");}return 0;
}

在这里插入图片描述

2.3 字节序转换函数

当格式化的数据在两台使用不同字节序的主机之间直接传递时,接收端必然错误的解释之。

  • 解决问题的方法是:发送端 总是 把要发送的数据 转换成 大端字节序数据 后再发送,而接收端知道对方传送过来的数据总是采用大端字节序,所以接收端可以根据自身采用的字节序决定是否对接收到的数据进行转换(小端机转换,大端机不转换)。

    网络字节顺序 是 TCP/IP 中规定好的 一种数据表示格式,它与具体的 CPU 类型、操作系统等无关,从而可以保证数据在不同主机之间传输时能够被正确解释,网络字节顺序 采用 大端排序 方式。

 
BSD Socket 提供了封装好的 转换接口,方便程序员使用。

  • 包括从 主机字节序 到 网络字节序 的 转换函数:htons、htonl;
  • 从 网络字节序 到 主机字节序 的转换函数:ntohs、ntohl。
h 	- host 主机,主机字节序
to 	- 转换成什么
n 	- network 网络字节序
s 	- short : unsigned short   无符号短整型,两个字节
l 	- long : unsigned int		 无符号长整型,四个字节
#include <arpa/inet.h>
/*网络通信时,需要将主机字节序转换成网络字节序(大端),另外一段获取到数据以后根据情况将网络字节序转换成主机字节序。
*/// 32位,转IP
uint32_t htonl(uint32_t hostlong);    	// 主机字节序 -> 网络字节序
uint32_t ntohl(uint32_t netlong); 		// 网络字节序 -> 主机字节序// 16位,转换端口
uint16_t htons(uint16_t hostshort); 	// 主机字节序 -> 网络字节序
uint16_t ntohs(uint16_t netshort);		// 网络字节序 -> 主机字节序
#include <stdio.h>
#include <arpa/inet.h>int main() {// htonl  转换IPchar buf[4] = {192, 168, 1, 100};int num = *(int *)buf;int sum = htonl(num);unsigned char *p = (char *)&sum;printf("%d %d %d %d\n", *p, *(p+1), *(p+2), *(p+3));printf("=======================\n");// htons 转换端口unsigned short a = 0x0102;printf("a : %x\n", a);unsigned short b = htons(a);printf("b : %x\n", b);printf("=======================\n");// ntohl 转换IPunsigned char buf1[4] = {1, 1, 168, 192};int num1 = *(int *)buf1;int sum1 = ntohl(num1);unsigned char *p1 = (unsigned char *)&sum1;printf("%d %d %d %d\n", *p1, *(p1+1), *(p1+2), *(p1+3));// ntohs 转换端口return 0;
}

3. socket 地址

 
    socket 地址 其实是一个 结构体,封装 端口号 和 IP 等信息。 后面的 socket 相关的 api 中需要使用到这个 socket地址。

  • 客户端 -> 服务器(IP, Port)

3.1 通用 socket 地址

 
    socket 网络编程接口 中表示 socket 地址 的是 结构体 sockaddr,其定义如下:

#include <bits/socket.h>struct sockaddr {sa_family_t sa_family;	// 地址族类型char sa_data[14]; 		// 14字节
};typedef unsigned short int sa_family_t;		// 2字节

    sa_family 成员是 地址族类型(sa_family_t)的 变量。地址族类型 通常与 协议族类型 对应。常见的 协议族(protocol family,也称 domain)和对应的 地址族(address family) 如下所示:
在这里插入图片描述
     宏 PF_* 和 AF_* 都定义在 bits/socket.h 头文件中,且 后者 与 前者 有 完全相同的值,所以二者通常混用。

    sa_data 成员用于存放 socket 地址值。但是,不同的协议族的地址值具有不同的含义和长度,如下所示:
在这里插入图片描述

     由上表可知,14 字节的 sa_data 根本无法容纳多数协议族的地址值。因此,Linux 定义了下面这个 新的通用的 socket 地址结构体,这个结构体不仅提供了足够大的空间用于存放地址值,而且是 内存对齐 的。

#include <bits/socket.h>
struct sockaddr_storage
{sa_family_t sa_family;			// 地址族类型unsigned long int __ss_align;	// 内存对齐char __ss_padding[ 128 - sizeof(__ss_align) ];
};typedef unsigned short int sa_family_t;

3.2 专用 socket 地址

     很 多网络编程函数 诞生 早于 IPv4 协议,那时候都使用的是 struct sockaddr 结构体,为了向前兼容,现在 sockaddr 退化成了(void *)的作用,传递一个地址 给函数,至于这个函数是 sockaddr_in 还是 sockaddr_in6,由地址族确定,然后函数内部再 强制类型转化 为所需的地址类型。
在这里插入图片描述
    UNIX 本地域协议族 使用如下 专用的 socket 地址结构体:

#include <sys/un.h>struct sockaddr_un
{sa_family_t sin_family;char sun_path[108];
};

    TCP/IP 协议族 有 sockaddr_in 和 sockaddr_in6 两个专用的 socket 地址结构体,它们分别用于 IPv4 和 IPv6:

#include <netinet/in.h>struct sockaddr_in
{sa_family_t sin_family; 		/* __SOCKADDR_COMMON(sin_) 地址族类型*/in_port_t sin_port; 			/* Port number. */struct in_addr sin_addr; 		/* Internet address. *//* Pad to size of `struct sockaddr'.  填充*/unsigned char sin_zero[sizeof (struct sockaddr) - __SOCKADDR_COMMON_SIZE - sizeof (in_port_t) - sizeof (struct in_addr)];
};struct in_addr
{in_addr_t s_addr;
};struct sockaddr_in6
{sa_family_t sin6_family;in_port_t sin6_port; /* Transport layer port # */uint32_t sin6_flowinfo; /* IPv6 flow information */struct in6_addr sin6_addr; /* IPv6 address */uint32_t sin6_scope_id; /* IPv6 scope-id */
};typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
typedef uint16_t in_port_t;
typedef uint32_t in_addr_t;#define __SOCKADDR_COMMON_SIZE (sizeof (unsigned short int))

    所有 专用 socket 地址(以及 sockaddr_storage)类型的变量 在实际使用时都需要转化 为 通用 socket 地址 类型 sockaddr(强制转化 即可),因为所有 socket 编程接口 使用的地址参数类型都是 sockaddr。

4. IP地址转换(字符串ip -> 整数,主机、网络字节序的转换 )

    通常,人们习惯用 可读性好的字符串 来表示 IP 地址,比如用 点分十进制字符串 表示 IPv4 地址,以及用 十六进制字符串 表示 IPv6 地址。但编程中我们需要先把它们 转化为 整数(二进制数)方能使用。而记录日志时则相反,我们要把整数表示的 IP 地址 转化为 可读的字符串。下面 3 个函数可用于用 点分十进制字符串 表示的 IPv4 地址 和 用 网络字节序整数 表示的 IPv4 地址 之间的转换:

#include <arpa/inet.h>// 下面的这些函数比较久,使用起来比较麻烦,不推荐使用 
in_addr_t inet_addr(const char *cp); 	// 点分十进制字符串 -> 整数
int inet_aton(const char *cp, struct in_addr *inp);	// 点分十进制字符串 -> 整数, 并保存到结构体指针 inp 中
char *inet_ntoa(struct in_addr in); 	// 整数 -> 点分十进制字符串

    下面这对更新的函数也能完成前面 3 个函数同样的功能,并且它们同时适用 IPv4 地址 和 IPv6 地址:⭐️

#include <arpa/inet.h>// p:点分十进制的IP字符串,n:表示network,网络字节序的整数
int inet_pton(int af, const char *src, void *dst);af:地址族: AF_INET AF_INET6src:需要转换的点分十进制的IP字符串dst:转换后的结果保存在这个里面// 将网络字节序的整数,转换成点分十进制的IP地址字符串
const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);af:地址族: AF_INET AF_INET6src: 要转换的ip的整数的地址dst: 转换成IP地址字符串保存的地方size:第三个参数的大小(数组的大小)返回值:返回转换后的数据的地址(字符串),和 dst 是一样的
#include <stdio.h>
#include <arpa/inet.h>int main() {// 创建一个ip字符串,点分十进制的IP地址字符串char buf[] = "192.168.1.4"; // 后面默认还有一个字符串结束符unsigned int num = 0;// 将点分十进制的IP字符串转换成网络字节序的整数inet_pton(AF_INET, buf, &num);unsigned char * p = (unsigned char *)&num;printf("%d %d %d %d\n", *p, *(p+1), *(p+2), *(p+3)); // 大端排序// 将网络字节序的IP整数转换成点分十进制的IP字符串char ip[16] = "";const char * str =  inet_ntop(AF_INET, &num, ip, 16);printf("str : %s\n", str);printf("ip : %s\n", str);printf("%d\n", ip == str);return 0;
}

在这里插入图片描述

5. TCP 通信流程

TCP 和 UDP -> 传输层的协议

  • UDP: 用户数据报协议,面向无连接,可以单播,多播,广播, 面向 数据报,不可靠
  • TCP: 传输控制协议,面向连接的,可靠的,基于 字节流,仅支持单播传输
 UDPTCP
是否创建连接无连接面向连接
是否可靠不可靠可靠的
连接的对象个数一对一、一对多、多对一、多对多支持一对一
传输的方式面向数据报面向字节流
首部开销8个字节最少20个字节
适用场景实时应用(视频会议,直播)可靠性高的应用(文件传输)

在这里插入图片描述

TCP 通信的流程 ⭐️⭐️⭐️
在这里插入图片描述
⭐️服务器端 ( 被动接受连接的角色)⭐️

  1. 创建 一个用于监听的套接字
    • 监听:监听有客户端的连接
    • 套接字 :这个套接字其实就是一个 文件描述符
  2. 将这个 监听 文件描述符 和 本地的IP 和 端口 绑定(IP 和 端口 就是 服务器的地址信息)
    • 客户端 连接 服务器 的时候使用的就是这个 IP 和 端口
  3. 设置 监听,监听的 fd 开始工作
  4. 阻塞等待,当有客户端发起连接,解除阻塞,接受客户端的连接,会得到一个 和客户端通信的 套接字(fd)
  5. 通信
    • 接收数据
    • 发送数据
  6. 通信结束,断开连接

⭐️客户端⭐️

  1. 创建一个用于通信的套接字(fd)
  2. 连接服务器,需要指定连接的服务器的 IP 和 端口
  3. 连接成功了,客户端可以直接和服务器 通信
    • 接收数据
    • 发送数据
  4. 通信结束,断开连接

6. 套接字函数

#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h> // 包含了这个头文件,上面两个就可以省略int socket(int domain, int type, int protocol);- 功能:创建一个套接字- 参数:- domain: 协议族AF_INET : ipv4AF_INET6 : ipv6AF_UNIX, AF_LOCAL : 本地套接字通信(进程间通信)- type: 通信过程中使用的协议类型SOCK_STREAM : 流式协议SOCK_DGRAM : 报式协议- protocol : 具体的一个协议。一般写0(默认)- SOCK_STREAM : 流式协议默认使用 TCP- SOCK_DGRAM : 报式协议默认使用 UDP- 返回值:- 成功:返回文件描述符,操作的就是内核缓冲区。- 失败:-1int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen); // socket命名- 功能:绑定,将fd 和本地的IP + 端口进行绑定- 参数:- sockfd : 通过socket函数得到的文件描述符- addr : 需要绑定的socket地址,这个地址封装了ip和端口号的信息- addrlen : 第二个参数结构体占的内存大小int listen(int sockfd, int backlog);  /proc/sys/net/core/somaxconn- 功能:监听这个socket上的连接- 参数:- sockfd : 通过socket()函数得到的文件描述符- backlog : 未连接的队列 和 已经连接的队列 和的最大值(以使用 cat /proc/sys/net/core/somaxconn 查看:4096),一般不用设置那么大,如:128int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);- 功能:接收客户端连接,默认是一个阻塞的函数,阻塞等待客户端连接- 参数:- sockfd : 用于监听的文件描述符- addr : 传出参数,记录了连接成功后客户端的地址信息(ip,port)- addrlen : 指定第二个参数的对应的内存大小- 返回值:- 成功 :用于通信的文件描述符- -1 : 失败int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);- 功能: 客户端连接服务器- 参数:- sockfd : 用于通信的文件描述符- addr : 客户端要连接的服务器的地址信息- addrlen : 第二个参数的内存大小- 返回值:成功 0, 失败 -1ssize_t write(int fd, const void *buf, size_t count); // 写数据
ssize_t read(int fd, void *buf, size_t count); // 读数据

TCP 通信实现

(1)服务器端

    创建 server.c 文件

// TCP 通信的服务器端#include <stdio.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>int main() {// 1.创建socket(用于监听的套接字)int lfd = socket(AF_INET, SOCK_STREAM, 0);if(lfd == -1) {perror("socket");exit(-1);}// 2.绑定struct sockaddr_in saddr;saddr.sin_family = AF_INET;// inet_pton(AF_INET, "192.168.193.128", saddr.sin_addr.s_addr);saddr.sin_addr.s_addr = INADDR_ANY;  // 0.0.0.0saddr.sin_port = htons(9999);int ret = bind(lfd, (struct sockaddr *)&saddr, sizeof(saddr));if(ret == -1) {perror("bind");exit(-1);}// 3.监听ret = listen(lfd, 8);if(ret == -1) {perror("listen");exit(-1);}// 4.接收客户端连接struct sockaddr_in clientaddr;int len = sizeof(clientaddr);int cfd = accept(lfd, (struct sockaddr *)&clientaddr, &len);if(cfd == -1) {perror("accept");exit(-1);}// 输出客户端的信息char clientIP[16];inet_ntop(AF_INET, &clientaddr.sin_addr.s_addr, clientIP, sizeof(clientIP));unsigned short clientPort = ntohs(clientaddr.sin_port);printf("client ip is %s, port is %d\n", clientIP, clientPort);// 5.通信char recvBuf[1024] = {0};while(1) {// 获取客户端的数据int num = read(cfd, recvBuf, sizeof(recvBuf));if(num == -1) {perror("read");exit(-1);} else if(num > 0) {printf("recv client data : %s\n", recvBuf);} else if(num == 0) {// 表示客户端断开连接printf("clinet closed...");break;}char * data = "hello,i am server";// 给客户端发送数据write(cfd, data, strlen(data));}// 关闭文件描述符close(cfd);close(lfd);return 0;
}

注: 仅供学习参考,如有不足,欢迎指正!

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

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

相关文章

算法------(13)KMP

例题&#xff1a;&#xff08;1&#xff09;AcWing 831. KMP字符串 。。其实写完也不太理解。。随便写点吧 KMP就是求next数组和运用next的数组的过程。相比传统匹配模式一次更新一单位距离的慢速方法&#xff0c;next数组可以让下表字符串一次更新n - next【n】个距离&#x…

Java读取文件

读取文件为String 、访问链接直接跳转html 环境&#xff1a;SpringMVC 、前端jsp InputStreamReader FileInputStream fileInputStream new FileInputStream(formatFile.getHtmlpath());InputStreamReader reader new InputStreamReader(fileInputStream, StandardCharsets…

【EAI 026】RoboGen: 通过自动数据生成管线实现机器人技能学习

Paper Card 论文标题&#xff1a;RoboGen: Towards Unleashing Infinite Data for Automated Robot Learning via Generative Simulation 论文作者&#xff1a;Yufei Wang, Zhou Xian, Feng Chen, Tsun-Hsuan Wang, Yian Wang, Zackory Erickson, David Held, Chuang Gan 作者单…

C++:菱形继承问题

目录 1、什么是菱形继承 2、虚拟继承 3、一些常见问题 1. 什么是菱形继承&#xff1f;菱形继承的问题是什么&#xff1f; 2. 什么是菱形虚拟继承&#xff1f;如何解决数据冗余和二义性的 3. 继承和组合的区别&#xff1f;什么时候用继承&#xff1f;什么时候用组合&#…

Qt 自定义长条进度条(类似播放器进度条)

1.运行界面 2.步骤 其实很简单。 2.1绘制底图圆角矩形 2.2绘制播放进度圆角矩形 参考&#xff1a;painter绘图 3.源码 #pragma once#include <QWidget> #include <QLabel> #include <QHBoxLayout> #include <QMouseEvent> #include <QDebug&g…

Slicer学习笔记(六十五) 3DSlicer的医学图像数据增强扩展模块

1. 医学图像数据增强扩展模块 基于3D Slicer5.1.0 编写了一个测试医学图像的数据增强测试扩展模块。 扩展模块名&#xff1a;DataAugementation 项目地址&#xff1a;DataAugmentation 下载该项目后&#xff0c;可以将该扩展模块添加到3D Slicer的扩展中。 关于如何给3DSlicer…

MySQL数据库基本操作(一)

数据库的基本概念 1. 数据库的英文单词&#xff1a; DataBase 简称 &#xff1a; DB 2. 什么数据库&#xff1f;* 用于存储和管理数据的仓库。 ​ 3. 数据库的特点&#xff1a;1. 持久化存储数据的。其实数据库就是一个文件系统2. 方便存储和管理数据3. 使用了统一的方式操作数…

微信自动回复,基于python

#!/usr/bin/python3 # -*- coding: utf-8 -*-import numpy as np import pandas as pd from uiautomation import WindowControl import csvwx WindowControl(Name微信,searchDepth1 ) # 切换窗口 wx.ListControl() wx.SwitchToThisWindow() # 寻找会话控件绑定 hw wx.…

LaTeX-设置表格大小

文章目录 LaTeX-设置表格大小1.创建表格2.设置表格的宽度2.1控制表格每一列的宽度2.2控制整个表格的宽度 3.设置表格的外观4.LaTeX绘制三线表 LaTeX-设置表格大小 本文介绍了LaTeX如何设置表格的大小、改变表格的外观以及如何绘制三线表。 1.创建表格 在LaTeX中创建表很耗时…

【前端素材】推荐优质后台管理系统网页my-Task平台模板(附源码)

一、需求分析 1、系统定义 后台管理系统是一种用于管理网站、应用程序或系统的工具&#xff0c;通常由管理员使用。后台管理系统是一种用于管理和控制网站、应用程序或系统的管理界面。它通常被设计用来让网站或应用程序的管理员或运营人员管理内容、用户、数据以及其他相关功…

2023年NOC大赛软件创意编程(学而思)赛道图形化小低高组决赛试题

2023NOC 决赛-小低组 每个小朋友从小会有梦寐以求的愿望,或是拥有孙悟空七十二变的能 力,或是像神笔马良一样想要什么画什么,或是成为人见人爱的国宝 大熊猫,或是变身全能机器人……今天,你可以用编程实现自己愿望! 【题目要求】 请以“假如我是_____”为题,自选主…

Sentinel实战(待完善)

目录 服务雪崩 什么是服务雪崩 服务不可用原因 解决方案 技术选型对比 Sentinel 介绍 优点 核心概念 资源 规则 代码实战 API实现 SentinelResource注解实现 Sentinel控制台 启动控制台服务 java应用接入控制台 微服务接入Sentinel 服务雪崩 什么是服务雪崩…

DETR详解

1. 动机 传统的目标检测任务需要大量的人工先验知识&#xff0c;例如预定义的先验anchor&#xff0c;NMS后处理策略等。这些人工先验知识引入了很多人为因素&#xff0c;且较难处理。如果能够端到端到直接生成目标检测结果&#xff0c;将会使问题变得很优雅。 2. 主要贡献 提…

牛客小白月赛87 A-G 题解 | JorbanS

文章目录 [A - 小苯的石子游戏](https://ac.nowcoder.com/acm/contest/73854/A)[B - 小苯的排序疑惑](https://ac.nowcoder.com/acm/contest/73854/B)[C - 小苯的IDE括号问题&#xff08;easy&#xff09;](https://ac.nowcoder.com/acm/contest/73854/C)[D - 小苯的IDE括号问题…

向爬虫而生---Redis 探究篇3<`Redis事务`和`Sql事务`区别>

前言: 在数据管理和应用开发中&#xff0c;事务的概念至关重要。事务用于组织和管理一系列对数据进行更新或操作的步骤&#xff0c;确保数据的一致性和可靠性。事务能够保证在一组相关操作中的原子性、一致性、隔离性和持久性&#xff0c;从而确保数据库的可靠性。 Redis和My…

idea中maven配置(一次成功,全部细节都有)

写这篇文章的原因是maven的配置很简单&#xff0c;但是也很容易出错&#xff0c;我连配了两台电脑的maven出现了各种小错误&#xff0c;参考了以下两篇博文IDEA配置Maven教程&#xff08;超详细版~)_idea maven配置教程-CSDN博客 一次包会——最新IDEA配置Maven指南&#xff0…

python 基础知识点(蓝桥杯python科目个人复习计划57)

今日复习计划&#xff1a;做题 例题1&#xff1a;笨笨的机器人 问题描述&#xff1a; 肖恩有一个机器人&#xff0c;他能根据输入的指令移动相应的距离。但是这个机器人很笨&#xff0c;他永远分不清往左边还是往右边移动。肖恩也知道这一点&#xff0c;所以他设定这个机器人…

mysql 远程不允许连接 1130 -Host ‘‘ is not allowed to connect to this MySQL server

1、docker 进入mysql 命令 sudo docker exec -it 0c58 /bin/bash 2、连接mysql mysql -u root -ppwd 3、 use mysql; 4、更改表所有root用户都可以连接 update user set host ‘%’ where user‘root’; 5、刷新权限 flush privilege&#xff1b; ok解决&#xff1b;

五大跨平台桌面应用开发框架:Electron、Tauri、Flutter等

hello&#xff0c;我是贝格前端工场&#xff0c;本次介绍跨平台开发的框架&#xff0c;欢迎大家评论、点赞。 一、什么是跨平台桌面应用开发框架 跨平台桌面应用开发框架是一种工具或框架&#xff0c;它允许开发者使用一种统一的代码库或语言来创建能够在多个操作系统上运行的…

3.2日学习打卡----初学FastDFS(二)

3.2日学习打卡 目录: 3.2日学习打卡SpringBoot整合FastDFS实战开发文件上传 FastDFS集成Nginx环境搭建 SpringBoot整合FastDFS 由GitHub大牛tobato在原作者YuQing与yuqih发布的JAVA客户端基础上进行了大量重构工作&#xff0c;并于GitHub上发布了FastDFS-Client1.26.5。 主要特…