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

【计算机网络】socket编程

文章目录

  • 1. 网络通信的理解
  • 2.进程PID可以取代端口号吗?
  • 3. 认识TCP协议
  • 4. 认识 UDP协议
  • 5. socket编程接口
    • udp_server.hpp的代码解析
      • socket——创建 socket 文件描述符
      • Initserver——初始化
        • 1.创建套接字接口,打开网络文件
          • bind——绑定的使用
        • 2.给服务器指明IP地址和端口号
          • struct sockaddr_in的理解
          • bzero 清空
          • 代码实现
          • inet_addr ——字符串风格转化为4字节风格
          • 服务器自己指定IP地址
        • 3. 云服务器,或者一款服务器,一般不要指明某一个确定的IP
      • start ——启动
        • 1. 收到客户端发来的消息
          • recvfrom——获取用户数据报
          • inet_addr ——将4字节风格转为字符串风格
        • 2.将消息发给别人
          • sendto
    • udp_client.cc的代码解析
      • 客户端如何绑定?
      • 服务器为什么要自己绑定?
      • 代码实现
    • 完整代码
      • err.hpp (枚举错误码)
      • makefile
      • udp_client.cc(客户端的实现,无封装)
      • udp_clinet.hpp
      • udp_server.cc (有封装)
      • udp_server.hpp(服务器的实现)

1. 网络通信的理解

主机A将自己的数据交给主机B,就需要给主机B发送消息,主机B未来要给主机A回消息

但实际上 主机A将自己的数据交给主机B 并不是最终目的

如:你在淘宝上买了一件衣服,卖家发货后,从广东省发货 到 你所在的地区 ,最终包裹成功到达你的手上,你还需要决定这个快递该怎么用

数据的传送不是目的,让两台主机通过数据进行通信来协同完成任务才是目的


如:唐僧说要去西天去取经,唐僧所对应的寺庙是A主机,西天的大雷音寺是B主机,唐僧并不是到大类饮食就完了,这只是他的手段,
他还需要面见如来,如来会提供给他经书的服务


数据发起时,从主机A的传输层开始,交给主机B的传输层
而数据是从主机A的应用层中的某种客户端传来的
而将数据交给主机B的传输层不是直接目的,要把数据再交给应用层 中的某种服务器

主机A对应的客户端一定要启动起来,所以其本质是 进程

因为主机B的某种服务器在以进程的方式运行,所以可以随时随地能够访问某种服务

网络通信的本质是 进程间的通信


通信的第一个阶段:先将数据通过操作系统,将数据发送到目标主机(手段)
通信的第二个阶段:在本主机将收到的数据,推送给自己上层的指定进程

第一个阶段 可以通过TCP/IP协议完成,因为IP可以表示互联网上唯一的一台主机

当主机B的传输层把数据交给应用层,应用层对应的进程非常多
所以为了标识自己主机上网络进程的唯一性,提出了 端口号 的概念

端口号是传输层协议的字段,是一个2个字节16位的整数,用来标识系统层面上进程的唯一性

所以 IP地址 + 端口号 可以表示 互联网中唯一的一个进程

通信时,是有两个进程进行通信,所以就有源IP 和源 端口号 以及 目标IP 和目标 端口号
源IP 和源 端口号表示 互联网中唯一的一个进程
目标IP 和目标 端口号也表示 互联网中唯一的一个进程

所以 网络通信的本质 是通过IP+PORT号 构建唯一性,来进行网络进程间通信, 简称 套接字通信

2.进程PID可以取代端口号吗?

进程PID在系统层面上每个进程也是唯一的,也能表示该系统上进程的唯一性,所以用进程PID可以代替端口号的
但会存在一些问题
1.不是所有的进程都要进行网络通信,只有部分进程可能会网络通信,若用进程PID来作为网络标识该进程,就很难区分清楚那些是进行网络通信的,那些不是进行网络通信的

2. PID是操作系统进程管理的概念,网络模块也要包含进程管理的部分,要不然无法认识PID
增加了系统当中进程管理和网络管理的耦合度

3. 认识TCP协议

TCP协议(Transmission Control Protocol) 传输控制协议
特点:
传输层协议
面向连接
在通信过程中,会自带可靠性
面向字节流
在进行发和收数据时,在TCP层没有报文的概念,收到一堆的数据,把这一堆的东西一次将给上层的应用层,也可一个字节一个字节交
字节数据如何解释TCP不关心,只关心要都多少,给你多少,最终解释信息由应用层自己解释,这种从称之为字节流

4. 认识 UDP协议

UDP协议(User Datagram Protocol)用户数据报协议
特点:
传输层协议
无连接
不可靠传输
面向数据报
如:收快递,收一个就是一个完整的快递,具体的快递不可能收半个或者一个半,若对方发了三次,你就必须收三次

5. socket编程接口

实验室做出来一套进程间通信的标准,既可在本地通信,又可以在网络跨主机通信的标准 即 socket标准 隶属于 posix标准

最常见的为 基于网络通信的套接字 sockaddr_in

预间套接字 (使用在两个进程间使用本地进程通信的) sockaddr_un

套接字的设计者为了能够让所有人以 一套接口的方式 既能本地通信 又能网络通信,
所以设计出一个公共的数据结构 叫做 struct sockaddr
若想进行网络通信 (struct sockaddr_in) 或者 进行 本地通信 (struct sockaddr_un) ,使用 sockaddr 进行强制转换即可


在结构最开始时,都要有16位的地址类型
AF_INET 与AF_UNIX 实际上都是宏,用整数来表示的
将地址进行比较判断,
若等于 AF_INET,就为网络通信,把 sockaddr强转为 sockaddr_in
若等于 AF_UNIX,就为本地通信,把 sockaddr强转为 sockaddr_un


udp_server.hpp的代码解析

通过网络协议栈的通信功能 ,来把数据交付给对方的应用层,来完成双方进程的通信

将客户端的数据交给 服务端 ,就需要给服务端发送消息,服务端再给客户端回消息


在 udp_server.hpp 中 使用namspace 将命名空间 命名为 ns_server
其中再定义一个类 udpserver

socket——创建 socket 文件描述符

输入 man socket创建套接字

第一个参数 domain ,用于区分 进行网络通信还是 本地通信
若想为网络通信,则使用 AF_INET
若想为本地通信,则使用 AF_UNIX

第二个参数 type, 套接字对应的服务类型

在这里插入图片描述

SOCK_STREAM 流式套接
SOCK_DGRAM 无连接不可靠的通信(用户数据报)

第三个参数 protocol ,表示想用那种协议,协议默认为0
若为 流式套接,则系统会认为是TCP协议 ,若为用户数据报,则系统会认为是UDP协议

套接字的返回值:若成功则返回文件描述符,若失败则返回 -1

Initserver——初始化

1.创建套接字接口,打开网络文件

在这里插入图片描述
使用socket套接字,创建出 网络通信、UDP协议
若套接字返回-1表示失败,则初始化也就失败,程序就没有必要在继续运行了,所以使用exit终止程序

若套接字创建成功,则返回文件描述符
文件描述符的前三个分别被 标准输入 标准输出 标准错误占用,所以此时的文件描述符应该打印出3

bind——绑定的使用

输入 man 2 bind ,查看绑定

给一个套接字绑定一个名字
第一个参数 sockfd 为 文件描述符
第二个参数 addr 为 通用结构体类型
第三个参数 addrlen 为 第二个参数的实际长度大小

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

2.给服务器指明IP地址和端口号

想要使用struct sockaddr_in类型 需添加头文件

定义一个 struct sockaddr_in(网络通信) 类型的 变量 local

struct sockaddr_in的理解

在这里插入图片描述
将 struct sockaddr_in 转到定义
16位地址类型:将 sa_prefix替换成 sin_ ,sin## family 实际上为 sin_family
此时的 sin_port 对应 当前绑定的端口号
sin_addr对应的是IP地址
再次将 in_addr转到定义,IP地址就是一个32位的整数

bzero 清空

sin_zero 作为 该结构体的填充字段
结构体可能很大,用不完,则使用填充字段将其填充上即可

输入 man bzero

将有n个字节的缓冲区,全部写为0

代码实现

在这里插入图片描述

将local对应的family(16位地址类型) 设置为 网络通信


设置一个私有的端口号port_


在这里插入图片描述
在类外设置一个端口号,用于构造时,若没有端口号传入,则8082充当缺省值


若我给你发消息,未来也需要将消息发回来,所以就必须知道我的IP地址和端口号
即端口号 以报文的形式发送到网络中

类内定义的port_,被称为本地主机序列, 需要把这个port_从主机序列 转成网络序列

输入 man htons ,表示短整数的主机转网络序列



定义一个私有的变量 ip_ 由于我们设置的IP地址是字符串风格的,而系统中的IP地址是4字节风格的 所以就需要将字符串风格的转化为 4字节风格的
inet_addr ——字符串风格转化为4字节风格

输入 man inet_addr

作用为:将字符串风格的IP地址 转化为 4字节风格的IP地址,并 默认会把主机序列 转换为 网络序列


由于local实际上定义在用户层的栈上,并没有在内核

所以借助bind,将填充好的套接字字段和文件字段,进行绑定关联,这样的文件才是网络文件
由于local 是 struct sock_addr_in 类型 ,需要强转为 struct sockaddr 公共类型


服务器自己指定IP地址

此时运行 udp_server可执行程序,会发现套接字创建成功,但绑定会失败


云服务器 不需要bind IP地址,需要让服务器自己指定IP地址


所以在main函数中添加命令行参数
命令行参数
main函数的两个参数,char* argv[] 为指针数组 ,argv为一张表,包含一个个指针,指针指向字符串
int argc,argc为数组的元素个数

设计一个usage函数,用以表示出 出现问题的可执行程序的名字 proc


再次创建一个err.hpp,使用enum枚举,将USAGE_ERR设置成1 ,默认将SOCKET_ERR(套接字报错)设置为2,
将 BIND_ERR(绑定错误)设置为3


通过argv数组的第二个下标指明字符串风格的端口号,再通过atoi将字符串转化为整数
最终只传入 端口号即可


在这里插入图片描述

3. 云服务器,或者一款服务器,一般不要指明某一个确定的IP

在这里插入图片描述

使用 INADDDR_ANY , 让udpserver在启动的时候,bind本主机上的任意IP


将 INADDDR_ANY 转到定义,实际上为缺省的0值


start ——启动

服务器本质是一个死循环,永远不退出
如:半夜打开王者荣耀,依旧可以玩


1. 收到客户端发来的消息

recvfrom——获取用户数据报

输入 man recvfrom, 获取用户数据报

第一个参数 sockfd 为 套接字
第二个参数 buf 为 自己定义的缓冲区
第三个参数 len 为 缓冲区的长度
第四个参数 flags 为读取方式,默认设为0,以阻塞方式读取
剩余两个参数 src_addr 和 addrlen 为 输入 输出型 参数
使用recvfrom收到数据,最终还要把数据还回去,想要还回去就必须知道别人是谁
src_addr 为 作为一个结构体,内部记录客户端的IP地址和端口号
addrlen 为 输出时结构体的大小
返回值:若大于0,则读取成功


定义一个 struct sockaddr_in(网络通信) 类型的 变量 peer
使用 len 来表示 未来的结构体大小

若n大于0,则读取成功,将最后一个位置的下一个位置设为\0
若读取失败,则继续读取


peer下的IP地址为 4字节整数,需要将其转为字符串风格

inet_addr ——将4字节风格转为字符串风格

输入 man inet_addr,将4字节IP转为字符串风格的IP


peer下的端口号为网络序列,想要获取客户端的端口号 clientport,需要使用 ntohs 将网络序列转为主机序列

2.将消息发给别人

sendto

输入 man sendto

第一个参数 sockfd 为 套接字
第二个参数 buf 为 自己定义的缓冲区
第三个参数 len 为 缓冲区的长度
第四个参数 flags 为读取方式,默认设为0,以阻塞方式读取
剩余两个参数 src_addr 和 addrlen 为 输入 输出型 参数
使用recvfrom收到数据,最终还要把数据还回去,想要还回去就必须知道别人是谁
src_addr 为 将以前收到的消息转会给客户端
addrlen 为 输出时结构体的大小
返回值:若大于0,则读取成功



udp_client.cc的代码解析

第一个参数 使用 AF_INET,表示网络通信
第二个参数 使用SOCK_DRAM,表示数据报
第三个参数 默认设为0,由于上述为数据报,所以为UDP协议


客户端如何绑定?

客户端是需要绑定的
socket通信的本质 是 客户端的IP与端口号 与 服务器的IP与端口号 进行网络版本的进程间通信
但客户端是不需要自己绑定的,由操作系统自动进行绑定
如:电脑和手机充满大量客户端,这些客户端来自于不同的企业,每个客户端的端口号不可以是固定的
必须让操作系统随机去选择,本质是为了防止确定的客户端被别人去占用,减少客户端层面的冲突
所以客户端的端口号要让操作系统随机分配,防止客户端出现启动冲突

服务器为什么要自己绑定?

1.服务器的端口 是 众所周知并不能随意改变的
如:110是报警电话,不可能报警电话每天都变,否则会导致当真正想打电话时都不知道打那个

2.服务器都是一家公司的,所以端口号需要统一规范化
如:淘宝不会把自己的服务部署到知乎上


代码实现

进行while循环,向服务器发送消息

目前没有消息,所以让用户输入充当消息源
使用 sendto,将消息发送给服务端

作为客户端将消息发送给 服务器主机
想要运行 客户端 ,就需要服务器的IP 和端口号


在这里插入图片描述
借助命令行参数,通过用户的输入的第二个参数 作为服务器的IP
用户输入的第三个作为 服务器的端口号

虽然此时服务器的IP和端口号知道了,但是想要借助sendto,后两个参数是需要套接字结构体


新建一个结构体server,内部包含服务器的IP和端口号
使用 htons ,将主机序列转为网络序列
使用inet_addr,将字符串转化为 4字节


在这里插入图片描述

此时 sendto的后两个参数 添加 创建的结构体 sever ,来完成发送服务器的任务
由于server 的类型 是 struct sockaddr_in ,而参数的类型为 公共结构体类型 struct sockaddr ,所以需要强转


使用 revfrom ,获取用户数据报
收到来自服务器转回来的消息 ,所以 定义一个 temp结构体,用于接收

在首次系统调用发送数据的时候,操作系统在底层随机选择客户端的端口号 加上自己的IP
先构建bind,再构建发送的数据报文

完整代码

err.hpp (枚举错误码)

#pragma onceenum 
{USAGE_ERR=1,SOCKET_ERR,BIND_ERR
};

makefile

.PHONY:all
all: udp_client udp_serverudp_client:udp_client.ccg++ -o  $@ $^ -std=c++11
udp_server:udp_server.ccg++ -o $@  $^ -std=c++11.PHONY:clean
clean:rm -f udp_clinet udp_server

udp_client.cc(客户端的实现,无封装)

#include"udp_client.hpp"
#include"err.hpp"
#include<cstring>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>static void usage(std::string proc)
{std::cout<<"usage:\n\t"<<proc<<"serverip serverport\n"<< std::endl;
}
// ./udp_client serverip sevrerport
int main(int argc ,char* argv[])//命令行参数 传入的是 客户端的运行 服务器的IP和端口号
{if(argc!=3){std::cout<<" "<<std::endl;exit( USAGE_ERR);//终止程序}std::string serverip = argv[1];//服务器的IPuint16_t serverport =atoi(argv[2]);//服务器的端口号int sock=socket(AF_INET,SOCK_DGRAM,0);if(sock<0)//创建套接字失败{std::cout<<"create socket error"<<std::endl;exit( SOCKET_ERR);}//明确server是谁struct sockaddr_in server;//设置网络通信的结构体memset(&server,0,sizeof(server)); //将结构体清空server.sin_family=AF_INET;server.sin_port=htons(serverport);//端口号server.sin_addr.s_addr=inet_addr(serverip.c_str());//IP地址while(true){//用户输入  std::string message;std::cout<<  "please enter# ";std::cin>> message;//发送消息sendto(sock,message.c_str(),message.size(),0,(struct sockaddr*)&server,sizeof(server));//接收消息char buffer[1024];struct sockaddr_in temp;socklen_t len=sizeof(temp);int n=recvfrom(sock,buffer,sizeof(buffer)-1,0,(struct sockaddr*)&temp,&len);if(n>0){buffer[n]=0;//收到回显消息std::cout<<"server echo"<<buffer<<std::endl;}}return 0;
}

udp_clinet.hpp

#pragma once
#include<iostream>
using namespace std;

udp_server.cc (有封装)

#include"udp_server.hpp"
#include"err.hpp"
#include<memory>
#include<string>
using namespace ns_server;
using namespace std;static void usage(string proc)
{std::cout<<"usage:\n\t"<<proc<<"prot\n"<< std::endl;
}//udp_server port
int main(int argc,char*argv[])//命令行参数
{if(argc!=2)//若命令行参数个数不为2,则当前会报错{usage(argv[0]);exit(USAGE_ERR);//终止程序}//端口号uint16_t port=atoi(argv[1]);//atoi可将字符串转化为整数//只需传入由用户指明的端口号unique_ptr<UdpServer> usvr(new UdpServer (port));usvr->Initserver();//服务器的初始化usvr->Start();//启动服务器return 0;
}

udp_server.hpp(服务器的实现)

#pragma once
#include<iostream>
#include<cerrno>
#include<cstring>
#include<cstdlib> 
#include<strings.h>
#include<functional>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<sys/types.h>
#include<sys/socket.h>
#include"err.hpp"namespace  ns_server
{const static uint16_t  default_port=8082;//设置端口号为8082 class UdpServer{public:UdpServer(uint16_t port=default_port)//构造:port_(port){}void  Initserver()//初始化{//1.创建套接字接口,打开网络文件sock_=socket(AF_INET,SOCK_DGRAM,0);if(sock_<0)//创建失败{//打印错误信息std::cout<<" create socket   error: "<<strerror(errno)<<std::endl;exit(SOCKET_ERR);//终止程序}std::cout<<"create socket success:"<<sock_<<std::endl;//3//2.给服务器指明IP地址和端口号struct sockaddr_in local;bzero(&local,sizeof(local));//全部置为0local.sin_family=AF_INET;//将16位地址类型 置为 网络通信local.sin_port=  htons(port_); //主机转网络的端口号//1.需要将字符串风格转化为 4字节//2.需要 将主机序列转换为 网络序列local.sin_addr.s_addr= INADDR_ANY ; //bind本机上的任意IP//bind 绑定int n=bind(sock_,(struct sockaddr*)&local,sizeof(local));if(n<0)//绑定失败{std::cout<<" bind  socket   error: "<<strerror(errno)<<std::endl;exit(BIND_ERR);}std::cout<<"bind socket success:"<<sock_<<std::endl;//3}void Start()//启动{char buffer[1024];//用于保护用户数据//设置一个死循环while(true){//1.收到客户端发来的消息struct sockaddr_in peer;socklen_t len=sizeof(peer);//传入的缓冲区大小int n=recvfrom(sock_,buffer,sizeof(buffer)-1,0,(struct sockaddr*)&peer,&len);if(n>0){buffer[n]='\0';}else {//读取失败,则继续读取continue;}//提取客户端信息//4字节IP转为 字符串IPstd::string clientip =inet_ntoa(peer.sin_addr);//客户端IP//将网络序列转换为主机序列uint16_t clientport =ntohs(peer.sin_port);//客户端 端口号std::cout<<clientip<<"-"<<clientport<<"-"<<"get message# "<<buffer<<std::endl;//2.将消息发给别人sendto(sock_,buffer,strlen(buffer),0,(struct sockaddr*)&peer,sizeof(peer));}}~UdpServer()//析构{}private:int sock_; //文件描述符uint16_t port_;//端口号 }; 
}

相关文章:

【计算机网络】socket编程

文章目录 1. 网络通信的理解2.进程PID可以取代端口号吗&#xff1f;3. 认识TCP协议4. 认识 UDP协议5. socket编程接口udp_server.hpp的代码解析socket——创建 socket 文件描述符Initserver——初始化1.创建套接字接口&#xff0c;打开网络文件bind——绑定的使用 2.给服务器指…...

2023华为OD机试真题 Python 实现【寻找最大价值的矿堆/深度优先搜索】

前言 本题使用Python解答,如果需要Java代码,请点击以下链接:点我 题目 我们规定,0表示空地,1表示银矿、2表示金矿,矿堆表示由相邻的金矿或银矿连接形成的地图。 银矿价值是1 ,金矿价值是2 ,你的目标是找出地图中最大价值的矿堆,并且输出该矿堆的价值 示例1 输入:…...

【Java面试】Nacos自动注册原理实现以及服务注册更新并如何保存到注册表

文章目录 Nacos自动注册原理实现服务注册更新并如何保存到注册表 Nacos自动注册原理实现 完整流程 我们知道SpringBoot提供了挂载点的方式来帮助我们的类完成自动注入。 Nacos再META-INF的spring.factories这个文件中添加了自己需要自动注入的Bean对象。 叫做NacosServiceRegi…...

linux 手动编译安装 pkg-config 步骤

1. 下载源码 Index of /releases (pkg-config.freedesktop.org) 2. 解压 并 进入解压后的文件夹 3. 运行配置文件 ./configure 错误解决办法&#xff1a;在linux中使用 ./configure 时报错 4. 编译、 自检、 安装 make make check make install 5. 安装完成后查看版本号…...

【MongoDB】数据库、集合、文档常用CRUD命令

目录 一、数据库操作 1、创建数据库操作 2、查看当前有哪些数据库 3、查看当前在使用哪个数据库 4、删除数据库 二、集合操作 1、查看有哪些集合 2、删除集合 3、创建集合 三、文档基本操作 1、插入数据 2、查询数据 3、删除数据 4、修改数据 四、文档分页查询 …...

【JVM】是如何管理内存的

文章目录 JVM 内存管理 模型JVM内存管理示例解析jvm 常见优化手段 JVM 内存管理 模型 以下是JVM内存管理的详细图示&#xff1a; ------------------------------------------------------ | Java 运行时数据区 | ------…...

进程与线程、线程创建、线程周期、多线程安全和线程池(ThreadPoolExecutor)

目录 进程与线程线程和进程的区别是什么&#xff1f;线程分两种&#xff1a;用户线程和守护线程线程创建四种方式run()和start()方法区别&#xff1a;为什么调用 start() 方法时会执行 run() 方法&#xff0c;为什么不能直接调用 run() 方法&#xff1f;Runnable接口和Callable…...

《论文阅读13》Efficient Urban-scale Point Clouds Segmentationwith BEV Projection

一、论文 研究领域&#xff1a; 城市级3D语义分割论文&#xff1a;Efficient Urban-scale Point Clouds Segmentationwith BEV Projection论文链接 注&#xff1a; BEV&#xff1a; Birds Eye View BEV投影是指鸟瞰视角(Birds Eye View,简称BEV)的一种从上方观看对象或场景的…...

Django实现音乐网站 ⑻

使用Python Django框架制作一个音乐网站&#xff0c; 本篇主要是后台对单曲原有功能的基础上进行部分功能实现和显示优化。 目录 新增编辑 歌手下拉显示修改 设置歌曲时长 安装eyed3库 获取mp3时长 歌曲时长字段修改 重写save方法 增加歌手单曲数量 查询歌手单曲数量 …...

VScode中同时打开两个脚本

使用快捷键&#xff1a; CtrlAltRightArrow 效果&#xff1a; 可以看到&#xff0c;上述两个脚本使用独立的窗口进行编辑和查看。...

能源电力工程师专属Python学习资料

随着我国新型电力系统的建设&#xff0c;一方面电源侧各类新能源装机快速增长&#xff0c;对于新能源出力的功率预测需求日益增长&#xff1b;另一方面&#xff0c;我国电力市场经过 8 年建设&#xff0c;关于电力商品价格影响因素的研究亟待深入。超过 90% 的业务小伙伴都具备…...

推荐5款实用软件,提高工作效率,丰富生活乐趣

​ 分享软件会让我感到开心和满足&#xff0c;因为我知道这些软件可以提高工作效率,丰富生活乐趣。今天再次将几款非常实用的软件推荐给大家。 截图翻译工具——CopyTranslator ​ CopyTranslator是一款非常实用的截图翻译软件,它支持对截图、选定区域进行OCR文字识别,自动翻…...

Python爬虫在电商数据挖掘中的应用

作为一名长期扎根在爬虫行业的专业的技术员&#xff0c;我今天要和大家分享一些有关Python爬虫在电商数据挖掘中的应用与案例分析。在如今数字化的时代&#xff0c;电商数据蕴含着丰富的信息&#xff0c;通过使用爬虫技术&#xff0c;我们可以轻松获取电商网站上的产品信息、用…...

element-ui 表格el-table的列内容溢出省略显示,鼠标移上显示全部和定制样式

1、在对应列加上省略显示show-overflow-tooltip属性&#xff0c;如果加上这属性&#xff0c;鼠标移上还是没效果&#xff0c;要考滤是不是层级的原因&#xff0c;被其他挡住了。 :deep(.el-tooltip){position: relative;z-index:9; } <el-table-column label"用款渠…...

研究人员发现特斯拉汽车能被越狱,可免费解锁付费功能

Bleeping Computer 网站披露&#xff0c;柏林工业大学&#xff08;Technical University of Berlin&#xff09;的研究人员开发出一种新技术&#xff0c;可以破解特斯拉近期推出所有车型上使用的基于 AMD 的信息娱乐系统&#xff0c;并使其运行包括付费项目在内的任何软件。 实…...

【设计模式】责任链的基本概念及使用Predicate灵活构造校验链

文章目录 1. 概述1.1.背景1.2.责任链模式的概念 2.责任链的基本写法2.1.链表实现2.2.数组实现 3.Predicate校验链2.1.使用Predicate改写代码2.1.更丰富的条件拓展 4.总结 1. 概述 1.1.背景 在最近的开发中遇到了这么一个需求&#xff0c;需要对业务流程中的各个参数做前置校验…...

Taro保存图片到手机

萌新亚历山大啊&#xff0c;搞了一下午&#xff0c;真多坑 Taro.downloadFile({url: res,filePath: Taro.env.USER_DATA_PATH /xcxcode.jpg,success: res > {if (res.statusCode 200) {console.log(res)const tempFilePath res.filePath; // 获取下载的临时文件路径// …...

zookeeper --- 基础篇

一、zookeeper简介 1.1、什么是zookeeper zookeeper官网&#xff1a;https://zookeeper.apache.org/ 大数据生态系统里的很多组件的命名都是某种动物或者昆虫&#xff0c;他是用来管 Hadoop&#xff08;大象&#xff09;、Hive(蜜蜂)、Pig(小 猪)的管理员。顾名思义就是管理…...

Golang map 常用方法

文章目录 前言按key排序按value排序统计字符串中元素重复出现次数并将结果排序返回 前言 由于map是无序的&#xff0c;所以排序成 slice 返回&#xff0c;且都使用泛,代码只是示例&#xff0c;省略了错误判断 按key排序 package mainimport "fmt"func example[T c…...

用于视觉跟踪的在线特征选择研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…...

Docker基本使用

查看本地镜像 查看本地&#xff1a;docker imagesPull镜像&#xff1a;docker pull nginx:latest登录镜像&#xff1a;docker login hub.docker.com -u **** -p ****制作镜像&#xff1a;docker build -t xxxx:v1push&#xff1a;docker push xxx:v1删除镜像:docker rmi #imag…...

PHP生成随机数

要在 PHP 中生成随机密码&#xff0c;可以使用 rand() 函数和字符串操作函数。以下是一个示例代码来生成包含字母、数字和特殊字符的随机密码 function generateRandomPassword($length 8) {// 定义包含字母、数字和特殊字符的字符集$characters abcdefghijklmnopqrstuvwxyz…...

MongoDB:Unrecognized option: storage

MongoDB一直显示 Unrecognized option: storage try ‘mongod --help’ for more information 意思是我们配置的config文件出了问题。 说明&#xff1a;MongoDB采用的是YAML格式&#xff0c;所以我们只需要稍微改改就好。 在storage前面&#xff1a;没有空格 下面两行最前面…...

Java基础九 - 异常

1. throw 和 throws 1. throw是在代码运行过程中引起一个异常 2. throws是将异常声明但是不处理&#xff0c;而是将异常往上传&#xff0c;谁调用我就交给谁处理 2. final、finally、finalize 1. final是修饰符&#xff0c;用于修饰变量、方法、类修饰变量&#xff0c;最开始…...

[国产MCU]-BL602开发实例-UART数据发送与接收

UART数据发送与接收 文章目录 UART数据发送与接收1、BL602的UART介绍2、UART相关驱动API介绍3、UART使用示例3.1 轮询方式数据接收与发送3.2 中断方式数据接收与发送3.3 DMA方式接收与发送数据通用异步收发传输器(Universal Asynchronous Receiver/Transmitter,通常称为UART)…...

mac安装open3d时候出现错误

在测试open3d是否正常顺利安装时&#xff0c;出现了如下错误&#xff1a; python -c "import open3d as o3d; print(o3d.__version__)" Traceback (most recent call last):File "<string>", line 1, in <module>File "/Users/huangzhe/…...

打造本地户外装备小程序商城教程大揭秘

在如今的移动互联网时代&#xff0c;小程序已经成为了各行各业的发展利器。尤其对于户外用具行业来说&#xff0c;一个专属的小程序商城将能够极大地提升企业的品牌形象和销售业绩。下面就来介绍一下快速上手制作户外用具小程序的攻略吧。 首先&#xff0c;登录乔拓云平台进入商…...

在外SSH远程连接Ubuntu系统

在外SSH远程连接Ubuntu系统【无公网IP】 文章目录 在外SSH远程连接Ubuntu系统【无公网IP】前言1. 在Ubuntu系统下安装cpolar软件2. 完成安装后打开cpolar客户端web—UI界面3. 创建隧道取得连接Ubuntu系统公网地址4. 打开Windows的命令界面并输入命令 前言 随着科技和经济的发展…...

GOTS标准速递---7.0 版将于2024年3月1日起全面生效

【GOTS标准速递---7.0 版将于2024年3月1日起全面生效】 全球有机纺织品标准很高兴地宣布发布GOTS 7.0 版&#xff0c;该版本扩大了环境和社会标准的范围&#xff0c;同时保持了适用于工业生产并适用于各种产品的标准。在为期一年的定期修订过程中&#xff0c;在有机生产、纺织品…...

Ansible的安装和配置

安装和配置 Ansible 安装所需的软件包 创建名为 /home/greg/ansible/inventory 的静态清单文件&#xff0c;以满足以下要求&#xff1a; 172.25.250.9 是 dev 主机组的成员 172.25.250.10 是 test 主机组的成员 172.25.250.11 和 172.25.250.12 是 prod 主机组的成员 172.2…...