关于一个模仿qq通信程序

  7月份的时候还在学校那个时候想要学习嵌入式Linux,但是还没有买开发板来玩,再学linux系统编程,网络编程,Linux系统的文件IO,于是学完之后想做一个模仿qq的通信程序于是就有了这个“ailun.exe”,因为暑假去打工了,没时间写代码,后面开学才接着写完,有bug还没解决,不过我也不想解决了,拖着到现在才想着写一篇总结

 

1.客户端

客户端用的是qt开发,其实也没写很多复杂的功能,就有用到qt的Tcp编程,还有界面的设计,字符串处理,如何文件io,还有一个至关重要的也是用到非常多的就是信号与槽,不得不说这个信号与槽真的是很好用。

2.服务端

服务器端的话,是租了一个阿里云的轻量级应用服务器,一年好像才80,服务器端用到的技术就会多一些,像进程间通信的共享内存,Linux的网络编程,文件io,多线程,多进程,还用到了文件系统事件通知机制,算法方面的也是基本上就用到了字符串匹配(用作登录,注册,一系列的检测判断),没用到什么厉害的算法。

服务端没有用到makefile,基本上有点像伪cpp的代码

来仔细分析和回顾一下都用到哪些技术吧

(1)文件io

#include <fstream>

写入文件用的是  ofstream f(路径,ios::app);

这里的ios::app表示追加写入

f<<"字符串";即可写入文件

从文件中读出  ifstream f(路径);

同理string s="";

while(getline(f,s))

{

        //处理逐行读出的文件

}

像其他的一些函数如is_open(),close();

(2)网络编程

主要包含头文件

<sys/socket.h>

<netinet/in.h>

<arpa/inet.h>

<unistd.h>

具体看我往期文章有详细介绍

(3)多线程

#include <pthread>void thread_one()
{//....
}int main()
{thread t1(thread_one);if (t1.joinable()) std::cout << "Thread 1 created successfully." << std::endl;else std::cerr << "Failed 1 to create thread." << std::endl;t1.join();//将线程分离return 0;
}

补充一点,为什么要分离线程?

  • 当一个线程被分离后,它的资源会在其执行完成后自动被系统回收,无需其他线程显式地等待并清理其资源。
  • 如果不分离线程,并且主线程在子线程还未完成时就结束了,可能会导致子线程所占用的资源(如内存、文件描述符等)无法被正确释放,从而造成资源泄漏。

(4)多进程

使用<thread><mutex>等标准库头文件

在服务器代码中关于进程的并没有使用很多函数,只用了一个fork()

在 Linux 和类 Unix 系统中,fork()是一个系统调用,用于创建一个新的进程

  1. 当一个程序调用fork()时,操作系统会创建一个新的进程,这个新进程几乎是调用fork()的进程的一个副本。
  2. fork()函数会返回两次:一次在父进程中,一次在子进程中。
    • 在父进程中,fork()返回新创建子进程的进程 ID。
    • 在子进程中,fork()返回 0。

(5)文件系统事件通知机制

inotify

  • inotify是 Linux 内核提供的文件系统事件监控机制。
  • 它允许应用程序监控文件和目录的各种事件,如创建、修改、删除、移动等。
  • 使用方法:
    • 通过系统调用inotify_init创建一个inotify实例。
    • 使用inotify_add_watch将需要监控的文件或目录添加到inotify实例中,并指定关注的事件类型。
    • 应用程序可以通过读取inotify实例的文件描述符来获取发生的事件。
     #include <stdio.h>#include <sys/inotify.h>int main() {int fd = inotify_init();if (fd == -1) {perror("inotify_init");return 1;}int wd = inotify_add_watch(fd, "./test_directory", IN_CREATE | IN_MODIFY | IN_DELETE);if (wd == -1) {perror("inotify_add_watch");return 1;}char buffer[4096];while (1) {ssize_t len = read(fd, buffer, sizeof(buffer));if (len == -1) {perror("read");break;}for (ssize_t i = 0; i < len; ) {struct inotify_event *event = (struct inotify_event *)&buffer[i];if (event->len) {if (event->mask & IN_CREATE) {printf("Created: %s\n", event->name);} else if (event->mask & IN_MODIFY) {printf("Modified: %s\n", event->name);} else if (event->mask & IN_DELETE) {printf("Deleted: %s\n", event->name);}}i += sizeof(struct inotify_event) + event->len;}}inotify_rm_watch(fd, wd);close(fd);return 0;}

(6)共享内存

这个以前写过了,就不重复写了

struct my_map
{char name[20];int this_socket;	
};//共享内存的指针
struct my_map *ptr;
int *ptriter;//创建共享内
//将内存分离出来
int shmid=shmget((key_t)0x5005,sizeof(struct my_map)*20,0640|IPC_CREAT);int shmiter=shmget((key_t)0x1001,4,0640|IPC_CREAT);//给每个进程创建指针指向这个共享内存
ptr=(struct my_map*)shmat(shmid,NULL,0);
ptriter=(int*)shmat(shmiter,NULL,0);

 

以下是完整代码

#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <unistd.h>
#include <stdio.h>
#include <string>
#include <cerrno>
#include <pthread.h>
#include <vector>
#include <unistd.h>
#include <fstream>
#include <vector>
#include <unordered_map>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <thread>
#include <sys/inotify.h>using namespace std;class server
{
public:int socket_fd;int client_fd;vector<int> vec_client;string ip;unsigned short port;server():socket_fd(-1){}bool connect(string in_ip,unsigned short port){if(socket_fd!=-1)return false;socket_fd=socket(AF_INET,SOCK_STREAM,0);if(socket_fd==-1){return false;}	struct sockaddr_in s_addr;s_addr.sin_family=AF_INET;s_addr.sin_port=htons(port);inet_aton(in_ip.c_str(),&s_addr.sin_addr);bind(socket_fd,(struct sockaddr *)&s_addr,sizeof(struct sockaddr_in));listen(socket_fd,10);return true;}bool send(string msg){if(socket_fd==-1)return false;int x=::send(client_fd,msg.data(),msg.size(),0);if(x<0)return false;return true;	}bool recv(string &msg,int maxsize){	if(socket_fd==-1)return false;msg.clear();msg.resize(maxsize);int x=::recv(client_fd,&msg[0],maxsize,0);if(x<0){msg.clear();std::cerr << "接收失败!错误代码: " << errno << ", 错误信息: " << strerror(errno) << std::endl;return false;}msg.resize(x);return true;}bool accept(){if(socket_fd==-1)return false;struct sockaddr_in c_addr;socklen_t c_size=sizeof(struct sockaddr_in);int c_fd=::accept(socket_fd,(struct sockaddr *)&c_addr,&c_size);if(c_fd==-1){perror("accept failed!");::close(socket_fd);socket_fd=-1;return false;}cout<<"客服端ip:"<<inet_ntoa(c_addr.sin_addr)<<endl;client_fd=c_fd;vec_client.push_back(c_fd);return true;}bool close_socket(){if(socket_fd==-1)return false;::close(socket_fd);socket_fd=-1;return true;}bool close_client(){if(client_fd==-1)return false;::close(client_fd);client_fd=-1;return true;}~server(){close_socket();close_client();}
};struct my_map
{char name[20];int this_socket;	
};//共享内存的指针
struct my_map *ptr;
int *ptriter;
server *server_socket;string this_client_name;vector<string> idvec,passwordvec;int inotify_fd;
int watch_descriptor;bool is_exit=false;void thread_one()
{string buffer;server *c=server_socket;bool flag=true;//发送用户清单,用于添加好友string send_user_list="all_user#";ifstream user("all_user");while(getline(user,buffer)){send_user_list+=buffer;send_user_list+='#';}if(c->send(send_user_list))cout<<"用户清单发送成功:!"<<send_user_list<<"\n";else cout<<"用户清单发送失败!\n";user.close();while(1){int err=c->recv(buffer,128);if(!err){cout<<"发生错误!\n";//当用户关闭客户端时结束进程is_exit=true;for(int i=0;i<*ptriter;i++){if(ptr[*ptriter].name==this_client_name){string ba="?????";strncpy(ptr[*ptriter].name,ba.c_str(),sizeof(ptr[*ptriter].name) - 1);  break;}}cout<<this_client_name<<" 用户关闭客户端!\n\n";break;}else cout<<"【来自客户端的消息】 "<<buffer<<endl;//f<<buffer<<"\n";//发送信息的前面加了@@@@@//std::cout<<"buffer[0]="<<buffer[0]<<" "<<"buffer[1]="<<buffer[1]<<"\n\n";//添加好友,写入好友关系到文件if(buffer[0]=='*'){ifstream read_friend("friend.txt");if(read_friend.is_open())cout<<"好友关系文件已打开!\n";else cout<<"好友关系文件打开失败!\n";unordered_map<string,vector<string>> friend_list;string friend_item;string this_friend="";while(getline(read_friend,friend_item)){if(friend_item=="#####"){getline(read_friend,friend_item);this_friend=friend_item;continue;}friend_list[this_friend].push_back(friend_item);}read_friend.close();for(auto iter=friend_list.begin();iter!=friend_list.end();iter++){auto a=iter->first;auto b=iter->second;cout<<a<<"的好友列表有:";for(int i=0;i<b.size();i++){cout<<b[i]<<" ";}cout<<endl;}string add_who="";for(int i=1;i<buffer.size();i++){add_who+=buffer[i];}friend_list[this_client_name].push_back(add_who);friend_list[add_who].push_back(this_client_name);ofstream write_friend_list("friend.txt",ios::trunc);if(write_friend_list.is_open())cout<<"写入好友关系文件已打开!\n";else cout<<"写入好友关系文件打开失败!\n";write_friend_list<<"#####"<<endl;for(auto iter=friend_list.begin();iter!=friend_list.end();iter++){auto a=iter->first;auto b=iter->second;write_friend_list<<a<<endl;for(int i=0;i<b.size();i++){write_friend_list<<b[i]<<endl;}write_friend_list<<"#####"<<endl;}if(c->send("ok"))cout<<"添加成功\n";write_friend_list.close();continue;}if(buffer[0]=='@'&&buffer[1]=='@'){//cout<<"成功执行了这里的代码"<<endl;string goal="";int start=0;int iter;string this_msg="";for(int i=5;i<buffer.size();i++){if(buffer[i]=='#'){start++;continue;}if(start==1)continue;if(start==2)goal+=buffer[i];if(start==3)this_msg+=buffer[i];}cout<<"发送目标"<<goal<<"\n\n";bool myflag=false;cout<<"当前登录的账号有:\n";for(int i=0;i<=*ptriter;i++){cout<<ptr[i].name<<"\n";if(goal==ptr[i].name)myflag=true;}if(!myflag)cout<<"对方不在线!\n\n";string end_msg="$$发送消息给:$"+this_client_name+"$"+this_msg;//if(!c->send_this(end_msg,ptr[i].this_socket))cout<<"发送失败!\n";string file_name="msg/"+goal;ofstream file_sendmsg(file_name,ios::app);if(file_sendmsg.is_open()){file_sendmsg<<end_msg<<endl;file_sendmsg.close();cout<<goal<<"文件打开成功!\n\n";}else cout<<goal<<"文件打开失败!\n\n";file_sendmsg.close();this_thread::sleep_for(std::chrono::milliseconds(500));//暂停线程500毫秒}}	}bool is_f=false;void thread_two()
{server *c=server_socket;int count=0;char buffer[1024];while (true) {int length = read(inotify_fd, buffer, sizeof(buffer));if (length < 0) {perror("read");break;}int i = 0;while (i < length) {struct inotify_event* event = reinterpret_cast<struct inotify_event*>(&buffer[i]);if (event->mask & IN_MODIFY){inotify_rm_watch(inotify_fd,watch_descriptor);std::ifstream inputFile("msg/"+this_client_name);std::string line;cout<<"打开了"<<this_client_name<<"的文件准备读取"<<endl;string last_send="";while(std::getline(inputFile, line)){count++;last_send+=(line+" ");cout<<"发送了:"<<line<<"  "<<"当前已经发送"<<count<<"条数据"<<endl;}cout<<"总信息汇总:"<<last_send<<"\n\n";if(!c->send(last_send))cout<<"信息发送失败!"<<endl;inputFile.close();watch_descriptor=inotify_add_watch(inotify_fd,("msg/"+this_client_name).c_str(),IN_MODIFY);if (watch_descriptor < 0)perror("1inotify_add_watch failed");}i += sizeof(struct inotify_event) + event->len;inotify_rm_watch(inotify_fd,watch_descriptor);ofstream delete_content("msg/"+this_client_name,ios::trunc);delete_content.close();watch_descriptor=inotify_add_watch(inotify_fd,("msg/"+this_client_name).c_str(),IN_MODIFY);if (watch_descriptor < 0)perror("2inotify_add_watch failed");}}}int main(int argc,char *argv[]) 
{//创建共享内存//将内存分离出来int shmid=shmget((key_t)0x5005,sizeof(struct my_map)*20,0640|IPC_CREAT);int shmiter=shmget((key_t)0x1001,4,0640|IPC_CREAT);	if(shmid==-1){cout<<"结构体共享内存创建失败"<<"\n\n";return 0;}if(shmiter==-1){cout<<"共享内存iter创建失败\n\n";}if(argc<3){cout<<"参数不够!";return 0;}cout<<"开始你的操作咯!\n"<<"进程id:"<<getpid()<<endl;server_socket=new server();if(server_socket->connect(argv[1],atoi(argv[2]))==false){cout<<"连接失败!\n";return 0;}while(1){//给每个进程创建指针指向这个共享内存ptr=(struct my_map*)shmat(shmid,NULL,0);ptriter=(int*)shmat(shmiter,NULL,0);if(!server_socket->accept())return 0;int pid=fork();if(pid>0)continue;else if(pid<0)return 0;//匹配密码,若成功开两个线程bool is_login=false;string buffer;while(1){server *c=server_socket;int err=c->recv(buffer,128);if(!err){cout<<"\n发生错误!尚未登陆,进程已结束!\n";return 0;break;}else cout<<"【来自客户端的消息】 "<<buffer<<endl;//注册功能if(buffer[0]=='$'){bool is_password=false;string p="",n="";cout<<"正在注册账号\n\n";ofstream r("passwordAndid.txt",ios::app);if(r.is_open())cout<<"注册文件打开成功!\n";else cout<<"注册文件打开失败!\n";for(int i=1;i<buffer.size();i++){if(buffer[i]=='#'){is_password=true;continue;}if(is_password)p+=buffer[i];else n+=buffer[i];}string ll="#"+p+"#"+n;r<<ll<<endl;ofstream ma("msg/"+n);if(ma.is_open()){cout<<"新注册用户的信息文本生成成功!\n";}//加入用户名单ofstream add_myself("all_user",ios::app);if(add_myself.is_open())cout<<"all_user 打开成功\n";else cout<<"all_user 打开失败\n";add_myself<<n<<endl;add_myself.close();cout<<"注册成功!\n\n";r.close();continue;}bool flag;if(buffer[0]=='#'){ifstream readfile("passwordAndid.txt");if(!readfile)cout<<"文件读取失败!";string line;cout<<"从文本中查找账号和密码如下:\n";while(getline(readfile,line)){string password,id;password="";id="";flag=true;for(int i=1;i<line.size();i++){if(line[i]=='#'){flag=false;continue;}if(flag)password+=line[i];if(!flag)id+=line[i];}cout<<id<<" "<<password<<"\n";idvec.push_back(id);passwordvec.push_back(password);}cout<<"\n";string curid,curpassword;flag=true;for(int i=1;i<buffer.size();i++){if(buffer[i]=='#'){flag=false;continue;}if(flag)curpassword+=buffer[i];if(!flag)curid+=buffer[i];}cout<<"curid="<<curid<<" "<<"curpassword="<<curpassword<<"\n";cout<<"正在匹配...........\n";for(int i=0;i<idvec.size();i++){if(curid==idvec[i]&&curpassword==passwordvec[i]){//if(!c->send("密码匹配正确!\n"))cout<<"发送失败!";//登录成功的套接字需要在共享内存中保存下来,以便后面的通信cout<<"*ptriter="<<*ptriter<<endl;//ptr[*ptriter].name=curid;strncpy(ptr[*ptriter].name, curid.c_str(), sizeof(ptr[*ptriter].name) - 1);  ptr[*ptriter].name[sizeof(ptr[*ptriter].name) - 1] = '\0'; // 确保字符串以 null 结尾ptr[*ptriter].this_socket=c->client_fd;cout<<"ptr[*ptriter].name="<<ptr[*ptriter].name<<" "<<"ptr[*ptriter].this_socket="<<ptr[*ptriter].this_socket<<"\n";(*ptriter)++;cout<<"ptriter增加后="<<*ptriter<<"\n\n";//ss[curid]=c;cout<<"密码匹配正确!登录成功!\n";//标记当前进程对应的客户端this_client_name=curid;//找出该账号的好友列表ifstream friendfile("friend.txt");if(!friendfile)cout<<"friendfile open errer!\n";string this_ss,last_str;vector<string> arr;bool judge=false;getline(friendfile,last_str);while(getline(friendfile,this_ss)){if(this_ss==curid&&!judge&&last_str=="#####")judge=true;if(judge&&this_ss=="#####")break;if(judge){cout<<"添加的好友:"<<this_ss<<"\n";arr.push_back(this_ss);}last_str=this_ss;}string sendtotal="密码匹配正确!#";is_login=true;for(int i=0;i<arr.size();i++){//c->send(arr[i]);sendtotal+=arr[i];sendtotal+='#';cout<<arr[i]<<"\n";}c->send(sendtotal);break;}else cout<<idvec[i]<<" "<<passwordvec[i]<<"\n";}if(is_login)break;}}cout<<"当前账号"<<this_client_name<<"已经登录"<<endl;inotify_fd = inotify_init();if (inotify_fd < 0){perror("inotify_init");return 1;}//需要监视的文件描述符watch_descriptor = inotify_add_watch(inotify_fd, ("msg/"+this_client_name).c_str(), IN_MODIFY);if (watch_descriptor < 0){perror("inotify_add_watch");close(inotify_fd);return 1;}thread t1(thread_one);if (t1.joinable()) std::cout << "Thread 1 created successfully." << std::endl;else std::cerr << "Failed 1 to create thread." << std::endl;thread t2(thread_two);if (t2.joinable()) std::cout << "Thread 2 created successfully." << std::endl;else std::cerr << "Failed 2 to create thread." << std::endl;while(1){if(is_exit){cout<<"用户成功退出!\n\n";break;}}t1.join();t2.join();}return 0;
}

 

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

【数据结构与算法】线性表

文章目录 一.什么是线性表&#xff1f;二.线性表如何存储&#xff1f;三.线性表的类型 我们知道从应用中抽象出共性的逻辑结构和基本操作就是抽象数据类型&#xff0c;然后实现其存储结构和基本操作。下面我们依然按这个思路来认识线性表 一.什么是线性表&#xff1f; 定义 线性…

TryHackMe 第7天 | Web Fundamentals (二)

继续介绍一些 Web hacking 相关的漏洞。 IDOR IDOR (Insecure direct object reference)&#xff0c;不安全的对象直接引用&#xff0c;这是一种访问控制漏洞。 当 Web 服务器接收到用户提供的输入来检索对象时 (包括文件、数据、文档)&#xff0c;如果对用户输入数据过于信…

【springboot】使用代码生成器快速开发

接上一项目&#xff0c;使用mybatis-plus-generator实现简易代码文件生成 在fast-demo-web模块中的pom.xml中添加mybatis-plus-generator、freemarker和Lombok依赖 <dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-generator&…

Python | 由高程计算坡度和坡向

写在前面 之前参加一个比赛&#xff0c;提供了中国的高程数据&#xff0c;可以基于该数据进一步计算坡度和坡向进行相关分析。 对于坡度和坡向&#xff0c;这里分享一个找到的库&#xff0c;可以方便快捷的计算。这个库为&#xff1a;RichDEM&#xff0c;官网地址如下 https…

SAP学习笔记 - 豆知识11 - 如何查询某个字段/DataElement/Domain在哪个表里使用?

大家知道SAP的表有10几万个&#xff08;也有说30多万个的&#xff0c;总之很多就是了&#xff09;&#xff0c;而且不断增多&#xff0c;那么当想知道一个字段在哪个表里使用的时候该怎么办呢&#xff1f; 思路就是SAP的表其实也是存在表里的&#xff1a;&#xff09;&#xf…

【Git】TortoiseGitPlink提示输入密码解决方法

问题 克隆仓库&#xff0c;TortoiseGitPlink提示输入密码 解法 1、打开TortoiseGit 下的puttygen工具 位置&#xff1a;C:\Program Files\TortoiseGit\bin\ 2、点击【Load】按钮&#xff0c;载入 C:\Users\Administrator\.ssh\ 文件夹下的id_rsa文件。 3、点击save private …

qt_c++_xml存这种复杂类型

demo&#xff0c;迅雷链接。或者我主页上传的资源 链接&#xff1a;https://pan.xunlei.com/s/VO8bIvYFfhmcrwF-7wmcPW1SA1?pwdnrp4# 复制这段内容后打开手机迅雷App&#xff0c;查看更方便 #ifndef MAINWINDOW_H #define MAINWINDOW_H#include <QMainWindow>#include…

请散户股民看过来,密切关注两件大事

明天股市要开市&#xff0c;不仅散户股民期盼节后股市大涨&#xff0c;上面也同样想在节后来上一个“开门红”。 为此&#xff0c;上面没休假&#xff0c;关起门来办了两件大事&#xff0c;这两天发布消息已提前预热了。 两件大事如下&#xff1a; 一是&#xff0c;上交所10…

什么是 JavaScript 的数组空槽

JavaScript 中的数组空槽一直是一个非常有趣且颇具争议的话题。我们可能对它的实际意义、历史以及现今的新版本中对它的处理方式有所疑问。数组空槽的存在最早可以追溯到 JavaScript 的诞生之初&#xff0c;当时的设计决定让它成为了现代 JavaScript 开发中的一种特别的现象。 …

大数据新视界 --大数据大厂之数据血缘追踪与治理:确保数据可追溯性

&#x1f496;&#x1f496;&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎你们来到 青云交的博客&#xff01;能与你们在此邂逅&#xff0c;我满心欢喜&#xff0c;深感无比荣幸。在这个瞬息万变的时代&#xff0c;我们每个人都在苦苦追寻一处能让心灵安然栖息的港湾。而 我的…

计算机毕业设计hadoop+spark天气预测 天气可视化 天气大数据 空气质量检测 空气质量分析 气象大数据 气象分析 大数据毕业设计 大数据毕设

Hadoop天气预测系统开题报告 一、研究背景与意义 在信息化和大数据时代&#xff0c;天气数据已成为社会生活和经济发展中不可或缺的重要资源。天气预测系统作为现代气象学的重要组成部分&#xff0c;对于农业生产、交通管理、环境保护以及防灾减灾等方面都具有重要意义。然而…

集智书童 | 用于时态动作检测的预测反馈 DETR !

本文来源公众号“集智书童”&#xff0c;仅用于学术分享&#xff0c;侵权删&#xff0c;干货满满。 原文链接&#xff1a;用于时态动作检测的预测反馈 DETR ! 视频中的时间动作检测&#xff08;TAD&#xff09;是现实世界中的一个基本且具有挑战性的任务。得益于 Transformer …

Chrome浏览器调用ActiveX控件--allWebOffice控件

背景 allWebOffice控件能够实现在浏览器窗口中在线操作文档的应用&#xff08;阅读、编辑、保存等&#xff09;&#xff0c;支持编辑文档时保留修改痕迹&#xff0c;支持书签位置内容动态填充&#xff0c;支持公文套红&#xff0c;支持文档保护控制等诸多办公功能&#xff0c;本…

国庆期间的问题,如何在老家访问杭州办公室的网络呢

背景&#xff1a;国庆期间的问题&#xff0c;如何在老家访问杭州办公室的网络呢 实现方案&#xff1a;异地组网 实现语言&#xff1a;Java 环境&#xff1a;三个网络&#xff0c;一台拥有公网IP的服务器、一台杭州本地机房内服务器、你老家所在网络中的一台电脑&#xff08;…

Linux中的网络指令:ping、netstat、watch、pidof、xargs

目录 Ping指令 netstat指令 watch指令 pidof指令 xargs指令 Ping指令 功能&#xff1a;检测两台主机间的网络连通性 语法&#xff1a;ping [选项] 目标主机的IP地址 &#xff08;192.168.1.1&#xff09;或域名&#xff08;google.com&#xff09; 常见选项&#xff1a…

鸿蒙next开启地图服务

一般手机软件有的都会有开启地图功能&#xff0c;这里说一下怎么开启地图服务 1、 首先你需要配置一些东西&#xff0c;在华为的agc平台上&#xff0c;下边链接就是详细的教程 https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/map-config-agc-V5 我说一下你…

分治算法(5)_归并排序_排序数组

个人主页&#xff1a;C忠实粉丝 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 C忠实粉丝 原创 分治算法(5)_归并排序_排序数组 收录于专栏【经典算法练习】 本专栏旨在分享学习算法的一点学习笔记&#xff0c;欢迎大家在评论区交流讨论&#x1f48c; 目录 …

如何在各大地图平台上标注店铺定位?

随着互联网的高度普及&#xff0c;地图导航已成为人们日常出行和寻找服务的重要工具。对于商家而言&#xff0c;将自己的店铺定位标注在各大地图平台上&#xff0c;不仅能方便顾客一键导航抵达店铺进行消费&#xff0c;还能提高店铺的线上曝光率&#xff0c;从而吸引更多的潜在…

Chrome浏览器调用ActiveX控件--allWebOffice控件功能介绍

allWebOffice控件概述 allWebOffice控件能够实现在浏览器窗口中在线操作文档的应用&#xff08;阅读、编辑、保存等&#xff09;&#xff0c;支持编辑文档时保留修改痕迹&#xff0c;支持书签位置内容动态填充&#xff0c;支持公文套红&#xff0c;支持文档保护控制等诸多办公功…

鸿蒙开发之ArkUI 界面篇 十九 Flex组件的特点

其语法格式是: Flex(参数对象){ 字组件1, 字组件2, 字组件3, 字组件4 } 这里你会发现&#xff0c;其实和Row容器&#xff0c;Colum容器的语法格式差不多&#xff0c;核心的关键是Colum、Row是不支持换行&#xff0c;实现FlexInterface接口&#xff0c;对外提供的属性是F…