当前位置: 首页 > news >正文

网络编程套接字(一)

学习任务:

我们先来认识端口号,区分好主机IP和端口号的区别,以及涉及到进程PID和端口号的区别。

然后简单认识一下TCP协议和UDP协议,这两个协议都是传输层的。接着了解什么是网络字节序,它有什么作用。然后是网络编程的一些接口。最后写代码简单实践一下。

目录

1、认识端口号,区分IP/port,PID/port

2、认识TCP协议,认识UDP协议

3、认识网络字节序

4、socket编程接口

5、代码示例:能够实现一个简单的udp客户端/服务器


1、认识端口号,区分IP/port,PID/port

IP地址(公网IP)是用来唯一标识互联网中的一台主机,一台主机一个IP。而IP分源IP和目的IP,源IP和目的IP对一个报文来讲,是起从哪里来,到哪里去的作用,其最大的意义是指导报文该如何进行路径的选择,而路径中,每一个“站点”就是MAC地址的变化。

认识端口号port

数据从计算机A到达计算机B,并不是真正的目的,而是到达计算机B的某一个进程,提供数据处理的服务,才是网络传输数据最终的目的。

数据本身并不是由计算机产生的,而是由人,即用户通过特定的客户端等等输入进去的,因此本质上,所有的网络通信,站在人的角度上,就是人与人之间的通信,这是一个比较好的理解方向,站在计算机角度上,是进程间通信!只不过通信的进程不在一台计算机上。就比如抖音的app客户端,它是一个进程,抖音的服务器,也是一个进程。我们通过抖音客户端达到网络通信,在抖音的服务器上获取信息,便是进程间通信。

而IP地址,仅仅是解决了两台物理机器之间的相互通信的识别问题,我们还要解决是在这两台计算机之间的进程间的通信,就是怎么知道计算机A发出的信息是要传给计算机B中的某个进程呢?这就需要端口号了!

因此,端口号的作用是唯一标识一台机器上的唯一一个进程!通过IP+端口号port,就能够标识互联网中的唯一一个进程!

我们可以将整个网络看成是一个大的OS,所有的网络行为,几乎都是在这一个大的OS进行进程间通信!

既然说端口号port是进程的一个身份,那么进程的PID按理论上来说,也能通过PID来进行网络上的进程间通信,那么为什么还需要一个port呢?

区分IP/PORT,PID/PORT

上面我们已经很清楚了,IP的标识物理机器的,port是标识进程的。而PID也是用来标识进程的,也是唯一性的!其实PID跟port,都属于进程的身份,就好像学生由身份证,也有他的学生证,一句话来说,将进程的PID和port分开来使用,是为了解耦!

一个进程可以关联多个端口号,而一个端口号不能关联多个进程。

网络是一份共享资源

要在网络上进行进程间通信,我们首先需要找到目标主机,然后找到该主机上的服务(进程),完成进程间通信。我们可以说网络世界,是一个进程间通信的世界。而进程要通信的话,由于进程具有独立性,因此不同的进程必须看到同一份资源,即共享资源!所有,网络便是一份共享资源!

2、认识TCP协议,认识UDP协议

这里先简单得对TCP和UDP来一个直观的认识:

TCP协议和UDP协议都是传输层的控制协议,以下是两种协议的特定,我们需要根据它们的特定,在不同场景下,权衡使用哪种协议。

TCP协议:

*传输层协议  *有连接  *可靠传输  *面向字节流

YDP协议:

*传输层协议  *无连接  *不可靠传输  *面向数据报

3、认识网络字节序

我们已经知道,内存中的多字节数据相对于内存地址有大端和小端之分, 磁盘文件中的多字节数据相对于文件中的偏移地址也有大端小端之分, 网络数据流同样有大端小端之分. 那么如何定义网络数据流的地址呢?

网络数据流觉得这样分来分去太麻烦了,这样吧!我就使用大端的形式吧!如果你的数据流本来就是大端,那你就直接传输,如果你的数据流是小端,那么麻烦你先转换成大端,再来传输!

因此,网络字节序指的就是在网络上的采用的大端形式,先发出的数据是低地址,后发出的数据是高地址。

为使网络程序具有可移植性,使同样的C代码在大端和小端计算机上编译后都能正常运行,可以调用以下库函数做网络字节序和主机字节序的转换:

这些函数名很好记,h表示host,n表示network,l表示32位长整数,s表示16位短整数。例如htonl表示将32位的长整数从主机字节序转换为网络字节序,例如将IP地址转换后准备发送。如果主机是小端字节序,这些函数将参数做相应的大小端转换然后返回;如果主机是大端字节序,这些 函数不做转换,将参数原封不动地返回。

总结一下网络字节序:

⭐发送主机通常将发送缓冲区中的数据按内存地址从低到高的顺序发出。
⭐接收主机把从网络上接到的字节依次保存在接收缓冲区中,也是按内存地址从低到高的顺序保存。
⭐因此,网络数据流的地址应这样规定:先发出的数据是低地址,后发出的数据是高地址。
⭐TCP/IP协议规定,网络数据流应采用大端字节序,即低地址高字节。
⭐不管这台主机是大端机还是小端机, 都会按照这个TCP/IP规定的网络字节序来发送/接收数据。
⭐如果当前发送主机是小端, 就需要先将数据转成大端; 否则就忽略, 直接发送即可。

4.socket编程接口

socket是套接字的意思,用于描述IP地址和端口号,是一个通信链的句柄。应用程序通过socket向网络发出请求或者回应。

socket 常见API

// 创建 socket 文件描述符 (TCP/UDP, 客户端 + 服务器)
int socket(int domain, int type, int protocol);// 绑定端口号 (TCP/UDP, 服务器)
int bind(int socket, const struct sockaddr *address,socklen_t address_len);// 开始监听socket (TCP, 服务器)
int listen(int socket, int backlog);// 接收请求 (TCP, 服务器)
int accept(int socket, struct sockaddr* address,socklen_t* address_len);// 建立连接 (TCP, 客户端)
int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);

我们逐一来理解一下这些接口:

// 创建 socket 文件描述符 (TCP/UDP, 客户端 + 服务器)
int socket(int domain, int type, int protocol);

第一个参数:domain:协议域。就是需要用哪种协议,我们最常用的就两种->AF_INET (IPV4协议),AF_INET6 (IPV6协议)。

  

第二个参数:套接字的类型,即SOCK_STREAM(TCP)、SOCK_DGRAM(UDP)。

  

第三个参数:这个我们置为0即可,它是用来制定某个协议的特定类型,即type类型中的某个类型。通常一种协议只有一种类型,那样该参数可以直接被设置为0;如果协议有多种类型,则需要指定协议类型。

返回值:返回一个文件描述符。

// 绑定端口号 (TCP/UDP, 服务器)
int bind(int socket, const struct sockaddr *address,socklen_t address_len);

 第一个参数:socket函数返回的文件描述符。

第二个参数:指定想要绑定的IP和端口。下面将分析sockadder结构体。

第三个参数:address的长度。

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

sockaddr结构:

网络通信的方式有很多种,比如基于网IP的网络通信,AF_INET,原始套接字,域间套接字等等。有那么多方式,那么在绑定IP和端口的时候,就需要很多种方法了,因此系统需要将其统一一下结构,就有了sockadder。

IPv4和IPv6的地址格式定义在netinet/in.h中,IPv4地址用sockaddr_in结构体表示,包括16位地址类型, 16位端口号和32位IP地址。

 
IPv4、 IPv6地址类型分别定义为常数AF_INET、 AF_INET6. 这样,只要取得某种sockaddr结构体的首地址,不需要知道具体是哪种类型的sockaddr结构体,就可以根据地址类型字段确定结构体中的内容。

 
socket API可以都用struct sockaddr *类型表示, 在使用的时候需要强制转化成sockaddr_in; 这样的好处是程序的通用性, 可以接收IPv4, IPv6, 以及UNIX Domain Socket各种类型的sockaddr结构体指针做为参数。

sockaddr 结构

 sockaddr_in 结构

虽然socket api的接口是sockaddr, 但是我们真正在基于IPv4编程时, 使用的数据结构sockaddr_in; 这个结构里主要有三部分信息: 地址类型, 端口号, IP地址。

我们简化看看表示IPV4的结构体:

struct sockaddr_in
{sa_family_t       sin_family;//地址族uint16_t          sin_port;//TCP/UDP端口号,16位整型struct in_addr    sin_addr;//IP地址,32位整型char              sin_sero[8];//别管它了
};

其中sin_famile:

地址族含义
AF_INETIPV4网络协议中的使用的地址族
AF_INET6IPV6网络协议中使用的地址族
AF_LOCAL本地通信中采用的UNIX协议的地址族

in_addr结构

in_addr用来表示一个IPv4的IP地址. 其实就是一个32位的整数。

我们使用这两个函数,再补充两个函数:recvfrom和sendto就可以写一个示例了(UDP的)。

 recvfrom:适用于UDP协议

ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t *addrlen);

 本函数用于从(已连接)套接口上接收数据,并捕获数据发送源的地址

第一个参数:套接字文件描述符

第二个参数:指明一个缓冲区,该缓冲区用来存放recvfrom函数接收到的数据

第三个参数:buf的长度

第四个参数:一般置0,即false。

第五个参数:是一个struct sockaddr类型的变量,该变量保存源机的IP地址及端口号

第六个参数:第五个参数的sizeof

返回值:成功返回接收到的字节数。失败返回-1。

sendto:适用于UDP协议

ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen);

·第一个参数:套接字文件描述符。

第二个参数:指明一个存放应用程序要发送数据的缓冲区。

第三个参数:buf的长度

第四个参数:置为0吧。

第五个参数:dest_addr表示目地机的IP地址和端口号信息

第六个参数:dest_addr的长度

返回值:成功返回接收到的字节数。失败返回-1。

示例代码:

实现一个网络通信功能,在client中输入信息,会在server中显示出来,并且返回信息给client,达到网络通信聊天的效果。

客户端client代码:

#include <iostream>
#include <string>
#include <cerrno>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>void Usage(std::string proc)
{std::cout<<"Usage: \n\t"<<proc<<" server_ip server_port"<<std::endl;
}int main(int argc,char *argv[])
{if(argc!=3){Usage(argv[0]);return 0;}//1.创建套接字,打开网络文件int sock=socket(AF_INET,SOCK_DGRAM,0);if(sock<0){std::cerr << "socket error : " << errno << std::endl;return 1;}//客户端不需要显示bind。//首先,客户端必须也要有IP和port//但是,客户端不需要显示的bind。因为一旦显示bind,就必须明确客户端client//要和哪个端口port关联。//而如果客户端client指明了端口号,那么在客户端client不一定会有用,因为//这个端口号有可能被占用了,比如我们在联网的时候,一边打LOL,一边斗地主//被占用就会导致client无法使用//server要的是port必须明确,而且不变,但client只要有就行!一般是由OS自动给你bind()// 就是client正常发送数据的时候,OS会自动给你bind,采用的是随机端口的方式!struct sockaddr_in server;server.sin_family = AF_INET;server.sin_port = htons(atoi(argv[2]));server.sin_addr.s_addr = inet_addr(argv[1]);//使用服务while(1){//数据从我们键盘输入std::string message;std::cout<<"输入# ";std::cin>>message;sendto(sock,message.c_str(),message.size(),0,(struct sockaddr*)&server, sizeof(server));struct sockaddr_in tmp;socklen_t len = sizeof(tmp);char buffer[1024];recvfrom(sock,buffer,sizeof(buffer),0,(struct sockaddr*)&tmp, &len);std::cout<<"server echo# "<<buffer<<std::endl;}return 0;
}

服务器server代码:

#include<iostream>
#include<string>
#include<cerrno>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>const uint16_t port = 8080;int main()
{//1.创建套接字,打开网络文件int sock = socket(AF_INET,SOCK_DGRAM,0);if(sock<0){std::cerr<<"socket create error: "<<errno<<std::endl;return 1;}//2.给该服务器绑定端口和ipstruct sockaddr_in local;//填充字段local.sin_family = AF_INET;local.sin_port = htons(port);//此处的port是端口号,是计算机上的变量//是属于主机序列,说明需要主机转网络的操作htons();//需要将人识别的点分十进制,字符串风格IP地址,转化成为4字节整数IP //需要考虑大小端,因此使用in_addr_t inet_addr(const char *cp);//local.sin_addr.s_addr = inet_addr("43.139.32.198");//点分十进制【0-255】//我们不能像上面这行代码一样,直接绑定bind某个IP,因为如果指定绑定一个IP,那么//只有发送到该IP主机上的数据才会交给你的网络进程//但是,服务器一般会配置很多个网卡,有很多个IP。//因此,作为服务器,我们需要的不是某个IP上面的数据,//而是需要所有发送到该服务器主机上的某个端口的数据!//使用INADDR_ANY,不绑定指定IPlocal.sin_addr.s_addr = INADDR_ANY;//绑定IP和端口if(bind(sock,(struct sockaddr*)&local,sizeof(local))<0){std::cerr<<"bind error: "<<errno<<std::endl;return 2;}//3.提供服务bool quit = false;#define NUM 1024char buffer[NUM];while(!quit){struct sockaddr_in peer;//保存接受到的数据的空间socklen_t len = sizeof(peer);//空间的大小recvfrom(sock,buffer,sizeof(buffer)-1,0,(struct sockaddr*)&peer,&len);std::cout<<"client# "<<buffer<<std::endl;std::string echo_hello = "hello";//服务器发送回给用户,表示收到消息了sendto(sock,echo_hello.c_str(),echo_hello.size(),0,(struct sockaddr*)&peer,len);}return 0;
}

接下来我们改造一下代码,实现一个功能:在client中输入bash命令,在server中执行命令,并且将执行结果返回到客户端client中。实现了简单的xshell。

client的代码:

#include <iostream>
#include <string>
#include <cerrno>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include<cstring>void Usage(std::string proc)
{std::cout << "Usage: \n\t" << proc << " server_ip server_port" << std::endl;
}// ./udp_client server_ip server_portint main(int argc, char *argv[])
{if (argc != 3){Usage(argv[0]);return 0;}// 1. 创建套接字,打开网络文件int sock = socket(AF_INET, SOCK_DGRAM, 0);if (sock < 0){std::cerr << "socket error : " << errno << std::endl;return 1;}//客户端需要显示的bind的吗??// a. 首先,客户端必须也要有ip和port// b. 但是,客户端不需要显示的bind!一旦显示bind,就必须明确,client要和哪一个port关联// client指明的端口号,在client端一定会有吗??有可能被占用,被占用导致client无法使用// server要的是port必须明确,而且不变,但client只要有就行!一般是由OS自动给你bind()// 就是client正常发送数据的时候,OS会自动给你bind,采用的是随机端口的方式!// b. 你要给谁发??struct sockaddr_in server;server.sin_family = AF_INET;server.sin_port = htons(atoi(argv[2]));server.sin_addr.s_addr = inet_addr(argv[1]);// 2.使用服务while (1){// a. 你的数据从哪里来??// std::string message;// std::cout << "输入# ";// std::cin >> message;std::cout<<"MyShell $ ";char line[1024];fgets(line,sizeof(line),stdin);sendto(sock, line, strlen(line), 0, (struct sockaddr*)&server, sizeof(server));//此处tmp就是一个”占位符“struct sockaddr_in tmp;socklen_t len = sizeof(tmp);char buffer[1024];ssize_t cnt = recvfrom(sock, buffer, sizeof(buffer), 0, (struct sockaddr*)&tmp, &len);if(cnt>0){//在网络通信中,只有报文大小,或者是字节流中字节的个数//没有C/C++字符串这样的概念buffer[cnt] = 0;//添加'\0'std::cout << buffer << std::endl;}else{//TODO}}return 0;
}

server的代码:

#include <iostream>
#include <string>
#include <cerrno>
#include <cstdio>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>//const uint16_t port = 8080;
std::string Usage(std::string proc)
{std::cout<<"Usage: "<<proc<<"port"<<std::endl;
}
// udp_server,细节最后在慢慢完善
//  ./udp_server port
int main(int argc,char *argv[])
{if(argc!=2){Usage(argv[0]);return -1;}uint16_t port = atoi(argv[1]);//argv[1]是字符串类型,需要转成整型//1. 创建套接字,打开网络文件int sock = socket(AF_INET, SOCK_DGRAM, 0);if(sock < 0){std::cerr << "socket create error: " << errno << std::endl;return 1;}//2. 给该服务器绑定端口和ip(特殊处理)struct sockaddr_in local;local.sin_family = AF_INET;local.sin_port = htons(port); //此处的端口号,是我们计算机上的变量,是主机序列// a. 需要将人识别的点分十进制,字符串风格IP地址,转化成为4字节整数IP// b. 也要考虑大小端// in_addr_t inet_addr(const char *cp); 能完成上面ab两个工作.// 坑: // 云服务器,不允许用户直接bind公网IP,另外, 实际正常编写的时候,我们也不会指明IP// local.sin_addr.s_addr = inet_addr("42.192.83.143"); //点分十进制,字符串风格[0-255].[0-255].[0-255].[0-255]// INADDR_ANY: 如果你bind的是确定的IP(主机), 意味着只有发到该IP主机上面的数据// 才会交给你的网络进程, 但是,一般服务器可能有多张网卡,配置多个IP,我们需要的不是// 某个IP上面的数据,我们需要的是,所有发送到该主机,发送到该端口的数据!local.sin_addr.s_addr = INADDR_ANY;if(bind(sock, (struct sockaddr*)&local, sizeof(local)) < 0){std::cerr << "bind error : " << errno << std::endl;return 2;}//3. 提供服务bool quit = false;#define NUM 1024char buffer[NUM];while(!quit){struct sockaddr_in peer;socklen_t len = sizeof(peer);ssize_t cnt = recvfrom(sock, buffer, sizeof(buffer)-1, 0, (struct sockaddr*)&peer, &len);if(cnt>0){buffer[cnt] = 0;//0=='\0'FILE *fp = popen(buffer,"r");std::string echo_hello;char line[1024] = {0};while(fgets(line,sizeof(line),fp)!=NULL){echo_hello+=line;}//这里可以选择判断是否读到了文件结尾// if(feof(fp))// {//     //读取结果完成// }pclose(fp);std::cout << "client# " << buffer << std::endl;//根据用户输入,构建一个新的返回字符串//echo_hello+="...";sendto(sock, echo_hello.c_str(), echo_hello.size(), 0, (struct sockaddr*)&peer, len);}else{//TODO}}return 0;
}

相关文章:

网络编程套接字(一)

学习任务&#xff1a; 我们先来认识端口号&#xff0c;区分好主机IP和端口号的区别&#xff0c;以及涉及到进程PID和端口号的区别。 然后简单认识一下TCP协议和UDP协议&#xff0c;这两个协议都是传输层的。接着了解什么是网络字节序&#xff0c;它有什么作用。然后是网络编程的…...

Mysql数据库存储过程

1、参数分类 存储过程的参数类型可以是IN、OUT和INOUT。根据这点分类如下&#xff1a; 1、没有参数&#xff08;无参数无返回&#xff09; 2、仅仅带 IN 类型&#xff08;有参数无返回&#xff09; 3、仅仅带 OUT 类型&#xff08;无参数有返回&#xff09; 4、既带 IN 又带 O…...

当我开始学习人工智能:人工智能的学派及研究目标

上课真是不认真啊&#xff0c;现在都写不来了作业了&#xff0c;真的会谢 一、人工智能的学派及其争论 1.1 对人工智能方法的争论 三个学派 符号主义 认为人的认知基元是符号&#xff0c;认知过程即符号操作过程。 认为人是一个物理符号系统&#xff0c;计算机也是一个物理符…...

Html5钢琴块游戏制作与分享(音游可玩)

当年一款手机节奏音游&#xff0c;相信不少人都玩过或见过。最近也是将其做了出来分享给大家。 游戏的基本玩法&#xff1a;点击下落的黑色方块&#xff0c;弹奏音乐。&#xff08;下落的速度会越来越快&#xff09; 可以进行试玩&#xff0c;手机玩起来效果会更好些。 点击…...

MySQL数据库——数据库设计概念和数据库设计步骤

数据库设计就是根据业务系统的具体需求&#xff0c;结合我们所选用的数据库&#xff0c;建立好表结构及表与表之间的管理关系&#xff0c;为这个业务系统构造出最优秀的数据存储模型的过程。使之能有效的对应用的数据进行存储&#xff0c;并高效的对已经存储的数据进行访问。 …...

【云原生】Kubernetes(k8s)之Pod概念和使用

k8s之Pod概念和使用一、Pod简介1.1、Pod的阶段&#xff08;状态&#xff09;1.2、容器状态二、Pod的定义2.1、restartPolicy2.2、imagePullPolicy2.3、command2.4、args2.5、resources三、Pod的使用3.1、创建并访问Pod3.2、多个应用容器3.3、Init容器3.3.1、Init容器与普通容器…...

数组(九)-- LC[316][321][402] 去除重复字母

1 移掉 K 位数字 1.1 题目描述 题目链接&#xff1a;https://leetcode.cn/problems/remove-k-digits/ 1.2 思路分析 这道题让我们从一个字符串数字中删除 k 个数字&#xff0c;使得剩下的数最小。也就说&#xff0c;我们要保持原来的数字的相对位置不变。 以题目中的 num1432…...

ubuntu下Thrift安装

thrift是一种常用rpc框架&#xff0c;工作中经常会用到&#xff0c;本文记录一下其安装过程。 目录 1.下载软件包 1.1thrift下载 1.2libevent下载 1.3boost下载 2.安装&#xff08;注意步骤&#xff09; 2.1安装libevent 2.2安装boost 2.3安装与Python2.7版本对应的py…...

读懂AUTOSAR :DiagnosticLogAndTrace DLT(四)-- API解析

一、周期调用的函数&#xff1a;Dlt_TxFunction 根据参数DltGeneralTrafficShapingSupport&#xff0c;决定如何去发送DLT消息。如果为TRUE&#xff0c;那需要参考参数DltLogChannelTrafficShapingBandwidth为每个Log通道设置发送带宽&#xff1b;如果为FALSE&#xff0c;那么…...

【LeetCode】剑指 Offer 56. 数组中数字出现的次数 p275 -- Java Version

1. 题目介绍&#xff08;56. 数组中数字出现的次数&#xff09; 面试题56.&#xff1a;数组中数字出现的次数&#xff0c; 一共分为两小题&#xff1a; 题目一&#xff1a;数组中只出现一次的两个数字题目二&#xff1a;数组中唯一只出现一次的数字 2. 题目1&#xff1a;数组中…...

Zookeeper集群 + Fafka集群

目录 第一章Zookeeper 概述 1.1.Zookeeper 定义 1.2.Zookeeper 工作机制 1.3.Zookeeper 特点 1.4.Zookeeper 数据结构 1.5.Zookeeper 应用场景 1.6.Zookeeper 原理之选举机制 1.7.部署 Zookeeper 集群 总结 第二章消息队列概述 2.1消息队列需求原因 2.2消息队列的优…...

全国青少年电子信息智能创新大赛(复赛)python·模拟四卷

目录 一、编程题 答案解析如下: 下载文档打印做题: 全国青少年电子信息智能创新大赛(复赛)python模拟四卷 一、编程题 第一题:描述 班上有学生若干名,给出每名学生的年龄《整数),求班上所有学生的平均年龄,保留到小数点后两企 输入 第一行有一个整数n (1<= n...

Redis - 介绍与使用场景

简介 Redis 的全称是 Remote Dictionary Server&#xff0c;是一个使用 C 语言编写的、开源的&#xff08;BSD 许可&#xff09;高性能非关系型&#xff08;NoSQL&#xff09;的键值对数据库。 Redis 的数据是存储在内存中的&#xff0c;所以读写速度非常快&#xff0c;被广泛…...

Spark SQL实战(07)-Data Sources

1 概述 Spark SQL通过DataFrame接口支持对多种数据源进行操作。 DataFrame可使用关系型变换进行操作&#xff0c;也可用于创建临时视图。将DataFrame注册为临时视图可以让你对其数据运行SQL查询。 本节介绍使用Spark数据源加载和保存数据的一般方法&#xff0c;并进一步介绍…...

Django DRF - 权限Permissions

权限Permissions 权限控制可以限制用户对于视图的访问和对于具体数据对象的访问。 在执行视图的dispatch()方法前&#xff0c;会先进行视图访问权限的判断在通过get_object()获取具体对象时&#xff0c;会进行对象访问权限的判断 1.提供的权限 AllowAny 允许所有用户IsAuth…...

二叉树(OJ)

单值二叉树&#xff08;力扣&#xff09; ---------------------------------------------------哆啦A梦的任意门------------------------------------------------------- 我们来看一下题目的具体要求&#xff1a; 既然我们都学了二叉树了&#xff0c;我们就应该学会如何去…...

mysql中增删改成的练习

文章目录一、表的创建1.student表的数据2、课程表的数据course3、学生成绩表的数据二、操作序列1、查询计算机系cs的全体学生学号、姓名和性别2、检索选修了课程号为2的学生号和姓名3、检索至少选修了三门课以上的学生号4、检索选修了全部课程的学生5、在原表的基础上创建一个视…...

谈一谈Java的ThreadLocal

目录 先说原理&#xff1a; 再上代码&#xff1a; 运行结果&#xff1a; 先说原理&#xff1a; ThreadLocal 是一个本地线程副本变量工具类&#xff0c;它可以在每个线程中创建一个副本变量&#xff0c;每个线程可以独立地修改自己的副本变量&#xff0c;而不会影响其他线程…...

边缘检测与阈值分割

Canny [1] Canny Edge Detection. https://docs.opencv.org/3.4/da/d22/tutorial_py_canny.html [2] OpenCV Edge Detection ( cv2.Canny ). https://pyimagesearch.com/2021/05/12/opencv-edge-detection-cv2-canny/ 由John F. Canny提出 1、由于边缘检测容易受噪声影响&…...

QQ空间无敌装逼,复制下面的任一代码粘贴即可出现意想不到的图案。

复制下面的任一代码粘贴即可出现意想不到的图案。 打赏代码&#xff1a; [em]e10033[/em]{uin:123,nick: 打赏了你一个冰淇淋,who:1} [em]e10033[/em] 打赏了100000000000.00元红包 [em]e10011[/em] 赞代码:{uin:0000,nick: xx、xx、xx、xx、xx、xx、xx、xx、xx、xx、xx、x…...

必看!总结5种JavaScript异步解决方案

1.回调 回调简单地理解为一个函数作为参数传递给另一个函数&#xff0c;回调是早期最常用的异步解决方案之一。 回调不一定是异步的&#xff0c;也不直接相关。 举个简单的例子&#xff1a; function f1(cb) {setTimeout(() > {cb && cb();}, 2000); }f1(() >…...

JUC并发编程高级篇第四章之ThreadLocal(人手一份,天下安)

文章目录1、ThreadLocal的简介1.1、常见的面试题(也是本次的讲解的内容&#xff09;1.2、什么是ThreadLocal1.3、ThreadLocal的所用1.4、没有出现ThreadLocal前后的变化1.5、ThreadLocal代码示例1.6、阿里巴巴对ThreadLocal的使用要求1.7、ThreadLocal的源码分析2、ThreadLocal…...

dump 定位分析

在缺少pdb的时候如何分析dump&#xff1f; windbgidaWindbg定位崩溃位置 通过windbg打开dump&#xff0c;并且分析dump !analyze -v 分析&#xff1a; 分析dump&#xff1a; !analyze -v错误原因&#xff1a;读取空指针错误线程&#xff1a;00001e04&#xff0c;可通过命令…...

(十二)排序算法-插入排序

1 基本介绍 1.1 概述 插入排序属于内部排序法&#xff0c;是对于欲排序的元素以插入的方式找寻该元素的适当位置&#xff0c;以达到排序的目的。 插入排序的工作方式非常像人们排序一手扑克牌一样。开始时&#xff0c;我们的左手为空并且桌子上的牌面朝下。然后&#xff0c;…...

elasticsearch 认知

1.大数据领域需要解决以下三个问题 如何存储数据 传统的关系数据库&#xff08;MySQL、Oracle、和Access等&#xff09;主导了20世纪的数据存储模式&#xff0c;但当数据量达到太字节级&#xff0c;甚至拍字节级时&#xff0c;关系型数据库表现出了难以解决的瓶颈问题。为了解决…...

《人体地图》笔记

《人体地图》 坂井建雄 著 孙浩 译 腹部通向大腿的隧道 腹部与大腿的分界点是大腿根部&#xff0c;即是腹股沟。 腹壁肌肉连结在腹股沟韧带上&#xff0c;腹壁肌肉包括三层&#xff0c;分别为腹外斜肌、腹内斜肌和腹横肌&#xff0c;每块肌肉都有一个张开的小孔&#xff0c;…...

java基础集合面试题

什么是集合 集合就是一个放数据的容器&#xff0c;准确的说是放数据对象引用的容器 集合类存放的都是对象的引用&#xff0c;而不是对象的本身 集合类型主要有3种&#xff1a;set(集&#xff09;、list(列表&#xff09;和map(映射)。 集合的特点 集合的特点主要有如下两点&…...

Vue学习-Vue入门

Vue学习 一、Vue入门 1、 引入Vue Vue (读音 /vjuː/&#xff0c;类似于 view) 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是&#xff0c;Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层&#xff0c;不仅易于上手&#xff0c;还便于与第三方库…...

【项目】bxg基于SaaS的餐掌柜项目实战(2023)

基于SaaS的餐掌柜项目实战 餐掌柜是一款基于SaaS思想打造的餐饮系统&#xff0c;采用分布式系统架构进行多服务研发&#xff0c;共包含4个子系统&#xff0c;分别为平台运营端、管家端&#xff08;门店&#xff09;、收银端、小程序端&#xff0c;为餐饮商家打造一站式餐饮服务…...

灌区流量监测设备-中小灌区节水改造

系统概述 灌区信息化管理系统主要对对灌区的水情、雨情、土壤墒情、气象等信息进行监测&#xff0c;对重点区域进行视频监控&#xff0c;同时对泵站、闸门进行远程控制&#xff0c;实现了信息的测量、统计、分析、控制、调度等功能。为灌区管理部门科学决策提供了依据&#xf…...