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

Linux--TCP编程--0216 17

观前提示:本篇博文的一些接口需要前几篇博文实现的

  • 线程池的实现

Liunx--线程池的实现--0208 09_Gosolo!的博客-CSDN博客

  • 线程池的单例模式

Linux--线程安全的单例模式--自旋锁--0211_Gosolo!的博客-CSDN博客


 1.TCP编程需要用的接口

创建 socket 文件描述符

int socket(int domain, int type, int protocol);

type 给成  SOCK_STREAM 表示是流式套接

listensock=socket(AF_INET,SOCK_STREAM,0);

开始监听socket

int listen(int socket, int backlog);

TCP是面向连接的,listen其实也是一个套接字,不过他的用途在于建立连接,而不真正提供服务。类似拉人的,提供服务的是服务员。

接收请求

int accept(int socket, struct sockaddr* address,socklen_t* address_len);

相当于拉客的和服务员进行了交接,返回值是真正提供服务的套接字(fd)

 建立连接

int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);

在正式通信之前,需要先建立连接。客户端需要连接到连接。

 2.TCP编程的框架

 2.1 服务端 TcpServer的框架  tcp_server.hpp

class TcpServer
{
private:const static int gbacklog = 20;  //后面再说public:TcpServer(uint16_t port, std::string ip="0.0.0.0"):_port(port),_ip(ip),listensock(-1){}void initServer(){}void Start(){}~TcpServer(){}
private:uint16_t _port;std::string _ip;int listensock;//listensock套接字仅用于建立连接
};

 头文件在这里一次性给出

#pragma once#include <iostream>
#include <string>
#include <unordered_map>
#include <cstring>
#include <cerrno>
#include <cassert>
#include <signal.h>
#include <unistd.h>
#include <memory>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/wait.h>
#include <pthread.h>
#include <ctype.h>//这几个头文件在线程池里面  其中Task.hpp会在用时给出
#include "ThreadPool/log.hpp"
#include "ThreadPool/ThreadPool.hpp"
#include "ThreadPool/Task.hpp"

 2.1.2 TcpServer的调用 tcp_server.cc

#include "tcp_server.hpp"
#include <memory>static void usage(std::string proc)
{std::cout << "\nUsage: " << proc << " port\n" << std::endl;
}// ./tcp_server port
int main(int argc, char *argv[])
{if(argc != 2){usage(argv[0]);exit(1);}uint16_t port = atoi(argv[1]);std::unique_ptr<TcpServer> svr(new TcpServer(port));svr->initServer();svr->Start();return 0;
}

2.2 客户端 TcpClient的实现 tcp_client.cc

网络间通信首先需要 struct  sockaddr_in 结构体,这里定义一个对象 server

结构对象有了需要对他进行初始化(建议先全部置零,避免出现一些bug)

  • server 有三个地方需要做初始化,sin_familysin_portsin_addr.s_addr

server.sin_family=AF_INET; //跟申请套接字传入的参数一样即可

server.sin_port=htos(serverport); //记得从本地转为网络字节序

server.sin_addr.s_addr=inet_addr(serverip,c_str());

  • connect()接口  客户端需要连接到服务上

 connect(sock, (struct sockaddr *)&server, sizeof(server) );

  •  send() 向服务端发送消息

 ssize_t s = send(sock, line.c_str(), line.size(), 0);

  •  recv() 接收服务器发来的消息

 recv(sock, buffer, sizeof(buffer) - 1, 0);

  •  close() 关闭套接字

 close(sock);

#include <iostream>
#include <string>
#include <cstdio>
#include <cstring>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <netinet/in.h>void usage(std::string proc)
{std::cout << "\nUsage: " << proc << " serverIp serverPort\n"<< std::endl;
}// ./tcp_client targetIp targetPort
int main(int argc, char *argv[])
{if (argc != 3){usage(argv[0]);exit(1);}std::string serverip = argv[1];uint16_t serverport = atoi(argv[2]);int sock = 0;while (true) // TODO{sock = socket(AF_INET, SOCK_STREAM, 0);if (sock < 0){std::cerr << "socket error" << std::endl;exit(2);}// client 要不要bind呢?不需要显示的bind,但是一定是需要port// 需要让os自动进行port选择// 连接别人的能力!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());if (connect(sock, (struct sockaddr *)&server, sizeof(server)) < 0){std::cerr << "connect error" << std::endl;exit(3); // TODO}std::cout << "connect success" << std::endl;std::cout << "请输入# ";std::string line;std::getline(std::cin, line);if (line == "quit"){close(sock);break;}ssize_t s = send(sock, line.c_str(), line.size(), 0);if (s > 0){char buffer[1024];ssize_t s = recv(sock, buffer, sizeof(buffer) - 1, 0);if (s > 0){buffer[s] = 0;std::cout << "server 回显# " << buffer << std::endl;close(sock);}else if (s == 0){close(sock);}}else{close(sock);}}return 0;
}

3. 服务端的实现

3.1 TcpServer::initServer() 

  • 初始化,首先需要建立一个监听套接字listensock,这个监听套接字的作用是建立连接。
listensock=socket(AF_INET,SOCK_STREAM,0);

我们是网络之间进行通信,所以需要借助 struct sockaddr_in 类型的对象,local,创建出来之后最好先清空一下,保证不会出现一些奇怪的问题。

  • local 有三个地方需要做初始化,sin_familysin_portsin_addr.s_addr

local.sin_family=AF_INET; //跟申请套接字传入的参数一样即可

local.sin_port=htos(_port); //记得从本地转为网络字节序

local.sin_addr.s_addr=_ip=="0.0.0.0"?INADDR_ANY:inet_addr(_ip.c_str());

  •  接着和udp一样,进行绑定操作

//注意 虽然使用struct sockaddr_in 结构体类型 但是接口中的参数依然是 struct sockaddr*

bind(listensock, (struct sockaddr *)&local, sizeof(local);

  •  (tcp新增)建立连接

 listen(listensock, gbacklog);//这个gbacklog以后再谈

3.1.1 完整代码

class TcpServer
{
private:const static int gbacklog = 20;  //后面再说public:TcpServer(uint16_t port, std::string ip="0.0.0.0"):_port(port),_ip(ip),listensock(-1){}void initServer(){listensock=socket(AF_INET,SOCK_STREAM,0);if(listensock<0){logMessage(FATAL, "create socket error, %d:%s", errno, strerror(errno));exit(2);}logMessage(NORMAL, "create socket success, listensock: %d", listensock);struct sockaddr_in local;memset(&local,0,sizeof(local));local.sin_family=AF_INET;local.sin_port=htons(_port);//local.sin_addr.s_addr=_ip.empty()?INADDR_ANY:inet_addr(_ip.c_str());local.sin_addr.s_addr=_ip=="0.0.0.0"?INADDR_ANY:inet_addr(_ip.c_str());//inet_pton(AF_INET, _ip.c_str(), &local.sin_addr);if (bind(listensock, (struct sockaddr *)&local, sizeof(local)) < 0){logMessage(FATAL, "bind error, %d:%s", errno, strerror(errno));exit(3);}if(listen(listensock, gbacklog)<0){logMessage(FATAL, "listen error, %d:%s", errno, strerror(errno));exit(4);}logMessage(NORMAL, "init server success");}
}

3.2 TcpServer::Start()

 要想服务端程序开始运行,首先需要有人来提供服务,记得listensock的作用仅是建立连接吗,那谁来做具体的服务呢?

使用accept接口的返回值!

首先,网络通信需要struct sockaddr_in结构体,先创建一个,struct sockaddr_in src;,len就是这个结构体的长度。

int servicesock=accept(listensock,(struct sockaddr*)&src,&len);

连接成功时候,就可以从我们创建的src中获取端口号、ip信息了。

 uint16_t client_port=ntohs(src.sin_port);

 std::string client_ip=inet_ntoa(src.sin_addr);

 接下来就可以开始进行服务了,自定义让做什么。这里让服务端去做这个任务

service(servicesock, client_ip, client_port);

static void service(int sock, const std::string &clientip, const uint16_t &clientport)
{//echo serverchar buffer[1024];while(true){// read && write 可以直接被使用!ssize_t s = read(sock, buffer, sizeof(buffer)-1);if(s > 0){buffer[s] = 0; //将发过来的数据当做字符串std::cout << clientip << ":" << clientport << "# " << buffer << std::endl;}else if(s == 0) //对端关闭连接{logMessage(NORMAL, "%s:%d shutdown, me too!", clientip.c_str(), clientport);break;}else{ // logMessage(ERROR, "read socket error, %d:%s", errno, strerror(errno));break;}write(sock, buffer, strlen(buffer));}close(sock);
}

 3.2.1  完整代码——单进程阻塞循环版

     void Start(){while(true){struct sockaddr_in src;socklen_t len=sizeof(src);//建立连接int servicesock=accept(listensock,(struct sockaddr*)&src,&len);if(servicesock < 0){logMessage(ERROR, "accept error, %d:%s", errno, strerror(errno));continue;}uint16_t client_port=ntohs(src.sin_port);std::string client_ip=inet_ntoa(src.sin_addr);logMessage(NORMAL, "link success, servicesock: %d | %s : %d |\n",servicesock, client_ip.c_str(), client_port);//版本1————单进程阻塞循环版service(servicesock, client_ip, client_port);}

问题在于,一次只能够处理一个进程。因为我们调用的函数service是一个死循环函数,如果一个客户端没有终止访问,其他客户端都不能正常来使用。

 3.2.2 完整代码——多进程带信号屏蔽版

那我使用多进程来解决这个问题,可是使用多进程也有问题,我创建了子进程,那我是不是要等待子进程结束啊?如果我使用阻塞等待那和上面有什么本质区别呢?

注:使用非阻塞等待成本很大,可以但不建议。

所以我们还需要用到信号,当子进程结束后,会给父进程发SIGCHLD信号!

 如果我们主动忽略SIGCHLD信号,子进程退出的时候,会自动释放自己的僵尸状态。

      void Start(){        signal(SIGCHLD, SIG_IGN); while(true){struct sockaddr_in src;socklen_t len=sizeof(src);//建立连接int servicesock=accept(listensock,(struct sockaddr*)&src,&len);if(servicesock < 0){logMessage(ERROR, "accept error, %d:%s", errno, strerror(errno));continue;}uint16_t client_port=ntohs(src.sin_port);std::string client_ip=inet_ntoa(src.sin_addr);logMessage(NORMAL, "link success, servicesock: %d | %s : %d |\n",servicesock, client_ip.c_str(), client_port);pid_t id = fork();assert(id != -1);if(id == 0){close(listensock);//关闭不需要的文件描述符service(servicesock, client_ip, client_port);exit(0); }//关闭父进程不需要的文件描述符 不关闭会导致父进程可用的文件描述符越来越少close(servicesock);}}

 3.3.3 完整代码——多进程版

能不能不屏蔽SIGCHLD信号呢?那我们就需要有人等待子进程,让谁等呢?

让bash领养,让bash等!

    void Start(){while(true){//...跟上面一样//版本3————多进程孤儿进程版// 利用孤儿进程被系统回收pid_t id=fork();if(id==0){close(listensock);if(fork()>0) {//子进程本身 exit(0);}//子进程的子进程service(servicesock, client_ip, client_port);exit(0);}waitpid(id,nullptr,0);//由于子进程创建子进程后立即退出 所以父进程不会阻塞close(servicesock);}}

 3.3.4 完整代码——多线程版

相较于使用多进程,多线程的开销明显小。

class ThreadData
{
public:int _sock;std::string _ip;uint16_t _port;
};class TcpServer
{
private:const static int gbacklog = 20;  //后面再说//设置的回调函数 必须是static的 不然会多一个this指针static void *threadRoutine(void *args){pthread_detach(pthread_self());ThreadData *td = static_cast<ThreadData *>(args);service(td->_sock, td->_ip, td->_port);delete td;return nullptr;}void Start(){while(true){//...//版本4————多线程版本//因为创建一个进程的代价还是比较大的,创建一个线程相对简便//不使用在栈上创建是为了保证线程安全 不会被覆盖 发生拷贝ThreadData *td=new ThreadData(); td->_sock=servicesock;td->_ip=client_ip;td->_port=client_port;pthread_t tid ;//如果不join 一定会造成内存泄漏 可以在threadRoutine中设置等待pthread_create(&tid,nullptr,threadRoutine,td); }}};

 3.3.5 完整代码——线程池版本

 线程的创建也是一笔开销,能省就省

线程池版本的服务函数

//线程池版本的服务函数
static void service(int sock, const std::string &clientip,const uint16_t &clientport, const std::string &thread_name)
{// echo server//  同时在线10人//  所以,我们一般服务器进程业务处理,如果是从连上,到断开,要一直保持这个链接, 长连接char buffer[1024];while (true){// read && write 可以直接被使用!ssize_t s = read(sock, buffer, sizeof(buffer) - 1);if (s > 0){buffer[s] = 0; // 将发过来的数据当做字符串std::cout << thread_name << "|" << clientip << ":" << clientport << "# " << buffer << std::endl;}else if (s == 0) // 对端关闭连接{logMessage(NORMAL, "%s:%d shutdown, me too!", clientip.c_str(), clientport);break;}else{ //logMessage(ERROR, "read socket error, %d:%s", errno, strerror(errno));break;}write(sock, buffer, strlen(buffer));}close(sock);
}
class TcpServer
{
public:TcpServer(uint16_t port, std::string ip="0.0.0.0"):_port(port),_ip(ip),listensock(-1), _threadpool_ptr(ThreadPool<Task>::getThreadPool()){}void Start(){//引入线程池_threadpool_ptr->run();//signal(SIGCHLD, SIG_IGN); // 对SIGCHLD,主动忽略SIGCHLD信号,子进程退出的时候,会自动释放自己的僵尸状态while(true){//...略//线程池版本Task t(servicesock, client_ip, client_port, service);//Task t(servicesock, client_ip, client_port, dictOnline);_threadpool_ptr->pushTask(t);}}~TcpServer(){}
private:uint16_t _port;std::string _ip;int listensock;//仅用于建立连接//定义一个线程池先std::unique_ptr<ThreadPool<Task>> _threadpool_ptr;
};

pushTask

#pragma once#include <iostream>
#include <string>
#include <functional>
#include "log.hpp"//typedef std::function<void (int , const std::string &, const uint16_t &)> func_t;
using func_t = std::function<void (int , const std::string &, const uint16_t &, const std::string &)>;class Task
{
public:Task(){}Task(int sock, const std::string ip, uint16_t port, func_t func): _sock(sock), _ip(ip), _port(port), _func(func){}void operator ()(const std::string &name){_func(_sock, _ip, _port, name);}
public:int _sock;std::string _ip;uint16_t _port;// int type;func_t _func;
};

相关文章:

Linux--TCP编程--0216 17

观前提示&#xff1a;本篇博文的一些接口需要前几篇博文实现的 线程池的实现Liunx--线程池的实现--0208 09_Gosolo&#xff01;的博客-CSDN博客 线程池的单例模式Linux--线程安全的单例模式--自旋锁--0211_Gosolo&#xff01;的博客-CSDN博客 1.TCP编程需要用的接口 创建 sock…...

关于设计模式的记录

############### 先弄清楚类模型的关系 ############### 万物的抽象关系 ############### 1.组合 composition实菱形 实线 无填充箭头整体与部分的关系同生共死代码体现&#xff1a;成员变量如&#xff1a;生命体与器官&#xff0c;http请求&#xff08;请求行&#xff0c;请求…...

Lambda-常见的函数式接口

如果需要使用Lambda接口&#xff0c;就必须要有一个函数式接口 函数式接口是有且仅有一个抽象方法的接口, 对应的注解是FunctionalInterface Java中内置的常见函数式接口如下: 1.Runnable/ Callable /*** The <code>Runnable</code> interface should be implem…...

P1196 [NOI2002] 银河英雄传说 带权并查集

[NOI2002] 银河英雄传说 题目背景 公元 580158015801 年&#xff0c;地球居民迁至金牛座 α\alphaα 第二行星&#xff0c;在那里发表银河联邦创立宣言&#xff0c;同年改元为宇宙历元年&#xff0c;并开始向银河系深处拓展。 宇宙历 799799799 年&#xff0c;银河系的两大军…...

【项目实战】快来入门Groovy的基础语法吧

一、Groovy是什么? 1.1 与Java语言的关系 下一代的Java 语言,增强Java平台的唯一的脚本语言跟java一样,它也运行在 JVM 中。支持Java平台,无缝的集成了Java 的类和库;Groovy是一种运行在JVM上的动态语言,跑在JVM中的另一种语言编译后的.groovy也是以class的形式出现的。1…...

Mybatis中的动态SQL

Mybatis中的动态SQL 当存在多条件查询的SQL时&#xff0c;当用户某个条件的属性没有写时&#xff0c;就会存在问题&#xff0c;在test中则不能很好的运行 所以Mybatis提出了动态SQL。 即判断用户是否输入了某个属性 动态SQL中的一些问题 方法一 这个里的and是为了确保if条…...

VUE常用API

1.$set数据变了&#xff0c;视图没变 this.$set(targe&#xff0c;key&#xff0c;value)2.$nextTick:返回参数[函数]。是一个异步的&#xff0c;功能获得更新后DOM$nextTick(callback){return Promise.resolve().then(()>{callback();}) }3.$refs获取dom4.$el获取当前组件根…...

25 openEuler管理网络-使用nmcli命令配置ip

文章目录25 openEuler管理网络-使用nmcli命令配置ip25.1 nmcli介绍25.2 设备管理25.2.1 连接到设备25.2.2 断开设备连接25.3 设置网络连接25.3.1 配置动态IP连接25.3.1.1 配置IP25.3.1.2 激活连接并检查状态25.3.2 配置静态IP连接25.3.2.1 配置IP25.3.2.2 激活连接并检查状态25…...

如何安装和使用A-ops工具?

一、pip配置 1.配置信任域 ​ pip3 config set global.trusted-host mirrors.tools.huawei.com2.配置pip源的url地址pip3 config set global.index-url http://mirrors.tools.huawei.com/pypi/simple 二、npm安装及配置 npm -v检测系统有无安装npm,如果没有的话需要配置ope…...

MySql数据库环境部署

MySql基础与Sql数据库概述基础环境的建立MYSQL数据库的连接方法MySql的默认数据库数据库端口号数据库概述 数据库&#xff08;DataBase&#xff0c;DB)∶存储在磁带、磁盘、光盘或其他外存介质上、按定结构组织在一起的相关数据的集合。数据库管理系统〈DataBase Management S…...

极品笔记,阿里P7爆款《K8s+Jenkins》技术笔记,职场必备

前些日子从阿里的朋友那里取得这两份K8sJenkins的爆款技术笔记&#xff1a;《K8S(kubernetes)学习指南》《Jenkins持续集成从入门到精通》&#xff0c;非常高质量的干货&#xff0c;我立马收藏&#xff01; 而今天咱们文章的主角就是这非常之干货的技术笔记&#xff1a;K8SJenk…...

数据结构:各种排序方法的综合比较

排序方法的选用应视具体场合而定。一般情况下考虑的原则有:(1)待排序的记录个数 n;(2)记录本身的大小;(3)关键字的分布情况:(4)对排序稳定性的要求等。 1.时间性能 (1) 按平均的时间性能来分,有三类排序方法: 时间复杂度为 O(nlogn)的方法有:快速排序、堆排序和归并排序,其中…...

【设计模式】 策略模式介绍及C代码实现

【设计模式】 策略模式介绍及C代码实现 背景 在软件构建过程中&#xff0c;某些对象使用的算法可能多种多样&#xff0c;经常改变&#xff0c;如果将这些算法都编码到对象中&#xff0c;将会使对象变得异常复杂&#xff0c;而且有时候支持不使用的算法也是一个性能负担。 如何…...

【数据库】第二章 关系数据库

第二章 关系数据库 2.1关系数据结构及形式化定义 关系 域&#xff08;domain) :域是一组具有相同数据类型的值的集合&#xff0c;可以取值的个数叫基数 笛卡尔积 &#xff1a;一个记录叫做一个元组&#xff08;tuple),元组中每一个属性值&#xff0c;叫一个分量 基数&…...

oracle和mysql的分页

oracle的分页&#xff1a;rownum 注意:&#xff1a; 对 ROWNUM 只能使用 < 或 <, 用 、 >、 > 都不能返回任何数据。 rownum是对结果集的编序排列&#xff0c;始终是从1开始&#xff0c;所以rownum直接使用时不允许使用>、> 所以当查询中间部分的信息时&…...

深拷贝与浅拷贝的理解

浅拷贝的理解浅拷贝的话只会拷贝基本数据类型&#xff0c;例如像string、Number等这些&#xff0c;类似&#xff1a;Object、Array 这类的话拷贝的就是对象的一个指针(通俗来讲就是拷贝一个引用地址&#xff0c;指向的是一个内存同一份数据)&#xff0c;也就是说当拷贝的对象数…...

Shell变量

一、变量分类 根据作用域分三种 &#xff08;一&#xff09;只在函数内有效&#xff0c;叫局部变量 &#xff08;二&#xff09;只在当前shell进程中有效&#xff0c;叫做全局变量 &#xff08;三&#xff09;在当前shell进程与子进程中都有效&#xff0c;叫做环境变量 shell进…...

Android 8请求权限时弹窗BUG

弹窗BUG 应用使用requestPermissions申请权限时&#xff0c;系统会弹出一个选择窗口&#xff0c;可进行允许或拒绝&#xff0c; 此窗口中有一个”不再询问“的选择框&#xff0c; ”拒绝”及“允许”的按钮。 遇到一个Bug,单点击“不再询问”&#xff0c;“允许”这个按钮会变…...

路漫漫:网络空间的监管趋势

网络空间是“以相互依存的网络基础设施为基本架构&#xff0c;以代码、信息与数据的流动为环境&#xff0c;人类利用信息通讯技术与应用开展活动&#xff0c;并与其他空间高度融合与互动的空间”。随着信息化技术的发展&#xff0c;网络空间日益演绎成为与现实人类生存空间并存…...

洛谷 P1208 [USACO1.3]混合牛奶 Mixing Milk

最后水一篇水题题解&#xff08;实在太水了&#xff09; # [USACO1.3]混合牛奶 Mixing Milk ## 题目描述 由于乳制品产业利润很低&#xff0c;所以降低原材料&#xff08;牛奶&#xff09;价格就变得十分重要。帮助 Marry 乳业找到最优的牛奶采购方案。 Marry 乳业从一些奶农手…...

国防科技大学计算机基础课程笔记02信息编码

1.机内码和国标码 国标码就是我们非常熟悉的这个GB2312,但是因为都是16进制&#xff0c;因此这个了16进制的数据既可以翻译成为这个机器码&#xff0c;也可以翻译成为这个国标码&#xff0c;所以这个时候很容易会出现这个歧义的情况&#xff1b; 因此&#xff0c;我们的这个国…...

在软件开发中正确使用MySQL日期时间类型的深度解析

在日常软件开发场景中&#xff0c;时间信息的存储是底层且核心的需求。从金融交易的精确记账时间、用户操作的行为日志&#xff0c;到供应链系统的物流节点时间戳&#xff0c;时间数据的准确性直接决定业务逻辑的可靠性。MySQL作为主流关系型数据库&#xff0c;其日期时间类型的…...

[2025CVPR]DeepVideo-R1:基于难度感知回归GRPO的视频强化微调框架详解

突破视频大语言模型推理瓶颈,在多个视频基准上实现SOTA性能 一、核心问题与创新亮点 1.1 GRPO在视频任务中的两大挑战 ​安全措施依赖问题​ GRPO使用min和clip函数限制策略更新幅度,导致: 梯度抑制:当新旧策略差异过大时梯度消失收敛困难:策略无法充分优化# 传统GRPO的梯…...

基于大模型的 UI 自动化系统

基于大模型的 UI 自动化系统 下面是一个完整的 Python 系统,利用大模型实现智能 UI 自动化,结合计算机视觉和自然语言处理技术,实现"看屏操作"的能力。 系统架构设计 #mermaid-svg-2gn2GRvh5WCP2ktF {font-family:"trebuchet ms",verdana,arial,sans-…...

Xshell远程连接Kali(默认 | 私钥)Note版

前言:xshell远程连接&#xff0c;私钥连接和常规默认连接 任务一 开启ssh服务 service ssh status //查看ssh服务状态 service ssh start //开启ssh服务 update-rc.d ssh enable //开启自启动ssh服务 任务二 修改配置文件 vi /etc/ssh/ssh_config //第一…...

2.Vue编写一个app

1.src中重要的组成 1.1main.ts // 引入createApp用于创建应用 import { createApp } from "vue"; // 引用App根组件 import App from ./App.vue;createApp(App).mount(#app)1.2 App.vue 其中要写三种标签 <template> <!--html--> </template>…...

在 Nginx Stream 层“改写”MQTT ngx_stream_mqtt_filter_module

1、为什么要修改 CONNECT 报文&#xff1f; 多租户隔离&#xff1a;自动为接入设备追加租户前缀&#xff0c;后端按 ClientID 拆分队列。零代码鉴权&#xff1a;将入站用户名替换为 OAuth Access-Token&#xff0c;后端 Broker 统一校验。灰度发布&#xff1a;根据 IP/地理位写…...

工程地质软件市场:发展现状、趋势与策略建议

一、引言 在工程建设领域&#xff0c;准确把握地质条件是确保项目顺利推进和安全运营的关键。工程地质软件作为处理、分析、模拟和展示工程地质数据的重要工具&#xff0c;正发挥着日益重要的作用。它凭借强大的数据处理能力、三维建模功能、空间分析工具和可视化展示手段&…...

Python爬虫(二):爬虫完整流程

爬虫完整流程详解&#xff08;7大核心步骤实战技巧&#xff09; 一、爬虫完整工作流程 以下是爬虫开发的完整流程&#xff0c;我将结合具体技术点和实战经验展开说明&#xff1a; 1. 目标分析与前期准备 网站技术分析&#xff1a; 使用浏览器开发者工具&#xff08;F12&…...

BCS 2025|百度副总裁陈洋:智能体在安全领域的应用实践

6月5日&#xff0c;2025全球数字经济大会数字安全主论坛暨北京网络安全大会在国家会议中心隆重开幕。百度副总裁陈洋受邀出席&#xff0c;并作《智能体在安全领域的应用实践》主题演讲&#xff0c;分享了在智能体在安全领域的突破性实践。他指出&#xff0c;百度通过将安全能力…...