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

Linux 网络编程

套接字(Socket):

通过网络实现跨机通信

作用:一种文件描述符传输层的文件描述符

整个编程中,需要着重注意htonl/htons、ntohl/ntohs、inet_addr等

TCP的C/S实现


循环服务器模型

TCP服务器实现过程

1.创建套接字:

初始化结构体struct sockaddr_in

2.给套接字绑定ip地址和端口号:bind函数

#include <netinet/in.h>

3.将套接字文件描述符,从主动变为被动文件描述符(做监听准备——listen函数)

4.accept函数:被动监听客户的连接并响应        【实现三次握手(无客户端连接,则会阻塞)】

5.服务器调用read(recv)和write(send)函数————SIGPIPE忽略

recv的返回值等于0的时候,证明客户端已经关闭

6.注意事项:

        字节序转换:

发送数据:将主机端序转为网络端序

接收数据:将网络端序转为主机端序

7.调用close或者shutdown关闭TCP连接

close:

缺点1:一次性将读写都关闭——只想关写(读),打开写(读),就实现不了

缺点2:如果多个文件猫述符指向了同一个连接时。如果只close关闭了其中某个文件猫述符时只要其它的fd还打开着,那么连接不会被断开。直到所有的描述符都被close后才断开连接
出现多个描述指向同一个连接的原因可能两个:
1.通过dup方式复制出其它描述符
2.子进程维承了这个描述符,所以子进程的描述符也指向了连接

shutdown:

可以全关掉

  • shutdown(套接字描述符)会关闭整个套接字的发送和接收功能,不管是否有连接建立。
  • shutdown(一个连接描述符)只会关闭与该连接相关的发送和接收功能,不会影响其他连接或套接字描述符。
  • close(套接字描述符)会完全关闭套接字描述符,释放与之相关的资源,并将描述符标记为无效。
  • close(一个连接描述符)的概念上并不存在,连接描述符通常是由套接字描述符派生出来的,因此关闭连接描述符时实际上是关闭了套接字描述符。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h> //*******//
#include <netinet/in.h> //*******//
#include <arpa/inet.h>  //*******//
#include <unistd.h>
#include <signal.h>
int sockfd;
void my_exit(int sig)
{shutdown(sockfd, SHUT_RDWR);close(sockfd);printf("shutdown socket done\n");exit(0);
}
void handle(int sig) // SIGPIPE的信号处理函数————以观察是否产生了SIGPIPE信号
{if (sig == SIGPIPE){printf("SIGPIPE is going\n");}
}int main(int argc, char **argv)
{signal(SIGINT, my_exit);signal(SIGPIPE, handle);signal(SIGPIPE, SIG_IGN);// 1.sockfd = socket(AF_INET, SOCK_STREAM, 0);if (sockfd < 0){perror("socked is error");exit(-1);}printf("socket success\n");// setsockopt函数int i;setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i));// 2.struct sockaddr_in sockaddr_in1;sockaddr_in1.sin_family = AF_INET; // IPV4// “5555”可以用宏定义sockaddr_in1.sin_port = htons(4443);                         // 正确的做法是使用htons函数将主机字节序转换为网络字节序————htons而非htonl因为端口号是16位sockaddr_in1.sin_addr.s_addr = inet_addr("192.168.106.128"); //*****//if (bind(sockfd, (struct sockaddr *)&sockaddr_in1, sizeof(sockaddr_in1)) < 0){perror("bind error");exit(-1);}printf("bind success\n");// 3.if (listen(sockfd, 20) < 0){perror("listen error");exit(-1);}printf("listen success\n");// 4.struct sockaddr_in addr2;int len_addr2 = sizeof(addr2);while (1){// 强制类型转换int sock_fd1 = accept(sockfd, (struct sockaddr *)&addr2, &len_addr2); // 每来一个客户端的连接请求,就会生成一个描述符,只要知道这个描述符,就能通过此通信if (sock_fd1 < 0){perror("accept error");exit(-1);}printf("client ip = %s ,port = %d\n", inet_ntoa(addr2.sin_addr), ntohs(addr2.sin_port)); // 1.inet_ntoa把ip地址转换为字符————2.把网络的转换为主机的// 5.char buffer[1024] = {0};int recv_t = recv(sock_fd1, buffer, sizeof(buffer) - 1, 0);printf("recv_t : %d   ", recv_t);if (recv_t < 0){perror("recv error");exit(-1);}else if (recv_t == 0) // recv的返回值为零的时候,证明客户端关闭了!{printf("client is closed\n");}else{printf("recv :%s\n", buffer);while (1){memset(buffer, 0, sizeof(buffer));scanf("%s", buffer);// int w_t = send(sock_fd1, buffer, strlen(buffer), 0);int w_t = send(sock_fd1, buffer, strlen(buffer), MSG_NOSIGNAL); // MSG_NOSIGNAL:表示此操作不愿被SIGPIPE信号断开;或注册信号处理函数if (w_t < 0){perror("send data error");exit(-1);}}}shutdown(sock_fd1, SHUT_RDWR);}return 0;
}
8.setsockopt函数

主要用在服务器端:

【当有客服端连接到服务器的时候,此时服务器端按下ctrl + c,断开连接,此时需要等待2MSL,才能再次用原来的ip和端口号新建客户端,为了去除这种等待2MSL的】

SO_REUSEADDR允许完全重复的捆绑:当一个IP地址和端口绑定到某个套接口上时,还允许此IP地址和端口捆绑到另一个套接口上

setsockopt(server_sockfd,SOL_SOCKET,SO_REUSEADDR,&j,sizeof(j));-CSDN博客

9.在socket()和bind()调用之间,使用下列代码——防止客户端关闭时,要等2MSL的时间

TCP客服端的实现过程

client.c#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <signal.h>
#include <unistd.h>int main(int argc, char **argv)
{if (argc != 3){perror("input error");exit(-1);}int socket_fd = socket(AF_INET, SOCK_STREAM, 0);if (socket_fd < 0){perror("socket error");exit(-1);}struct sockaddr_in addr_in1;addr_in1.sin_family = AF_INET;addr_in1.sin_addr.s_addr = inet_addr(argv[1]);addr_in1.sin_port = htons(atoi(argv[2]));if (connect(socket_fd, (struct sockaddr *)&addr_in1, sizeof(addr_in1)) == 0){printf("connect ok\n");}else{printf("connect error\n");}while (1){char buffer[1024];memset(buffer, 0, sizeof(buffer));scanf("%s", buffer);write(socket_fd, buffer, strlen(buffer) + 1);memset(buffer, 0, sizeof(buffer));read(socket_fd, buffer, sizeof(buffer));printf("%s", buffer);}return 0;
}

UDP的C/S实现

UDP协议没有建立连接特性,所以UDP协议没有自动记录对方IP和端口的特点,每次发
送数据时,必须亲自指定对方的IP和端口,只有这样才能将数据发送给对方。

 

UDP通信过程

1.调用socket创建套接字文件

2.bind绑定固定的ip和端口

3.调用sendto和recvfrom函数,发送和接收数据

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <signal.h>
#include <unistd.h>
int main(int argc, char **argv)
{// if (argc != 3)// {//     printf("input error\n");//     exit(-1);// }// 1.int sock_fd = socket(AF_INET, SOCK_DGRAM, 0);if (sock_fd < 0){perror("socket error");exit(-1);}// 2.struct sockaddr_in addr;addr.sin_family = AF_INET;addr.sin_addr.s_addr = inet_addr("127.0.0.1");addr.sin_port = htons(5554);if (bind(sock_fd, (struct sockaddr *)&addr, sizeof(addr)) < 0){perror("bind error");exit(-1);}// 3.struct sockaddr_in addr2;int addr2_len = sizeof(addr2);addr2.sin_family = AF_INET;addr2.sin_addr.s_addr = inet_addr(argv[1]);addr2.sin_port = htons(atoi(argv[2]));while (1){char buffer[1024];scanf("%s", buffer);int ret = sendto(sock_fd, buffer, strlen(buffer) + 1,0, (struct sockaddr *)&addr2, addr2_len);if (ret < 0){perror("sendto error");exit(-1);}}return 0;
}#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <signal.h>
#include <unistd.h>
int main(int argc, char **argv)
{// 1.int sock_fd = socket(AF_INET, SOCK_DGRAM, 0);if (sock_fd < 0){perror("socket error");exit(-1);}// 2.struct sockaddr_in addr;addr.sin_family = AF_INET;addr.sin_addr.s_addr = inet_addr("127.0.0.1");addr.sin_port = htons(5555);if (bind(sock_fd, (struct sockaddr *)&addr, sizeof(addr)) < 0){perror("bind error");exit(-1);}// 3.struct sockaddr_in addr2;memset(&addr2, 0, sizeof(addr2));int addr2_len = sizeof(addr2);char buffer[1024] = {0};while (1){int ret = recvfrom(sock_fd, buffer, sizeof(buffer),0, (struct sockaddr *)&addr2, &addr2_len);if (ret < 0){perror("recvfrom error");exit(-1);}printf("from ip = %s ,from port = %d \n", inet_ntoa(addr2.sin_addr), ntohs(addr2.sin_port));printf("recv message = %s \n", buffer);}return 0;
}

运行结果:

广播


一个人发,然后其它所有人都接收,这就是广播。


广播只能在局域网内部有效,广播数据是无法越过路由器的,也就是说路由器就是广播数据的边界。 广播只能在局域网内部有效,广播数据是无法越过路由器的,也就是说路由器就是广播数据的边界。


实现方法:

1.广播的发数据,不需要绑定自己的IP地址

2.ip地址写成广播地址;例如:192.168.1.255

3.接收端的ip地址,不能设置为固定ip,要指定为htons(INADDR_ANY)

4.接收方需要setsockopt函数,设置套接字文件可以重复绑定

   addr1.sin_addr.s_addr = htons(INADDR_ANY);//为什么是htons和htonl!!!!
广播发送:无需bind#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>int main(int argc, char **argv)
{int sock_fd = socket(AF_INET, SOCK_DGRAM, 0);if (sock_fd < 0){perror("socket error");exit(-1);}//*****************************************************************************//int j = 1;setsockopt(sock_fd, SOL_SOCKET, SO_BROADCAST, (void *)&j, sizeof(j));//*****************************************************************************//struct sockaddr_in addr1;addr1.sin_family = AF_INET;addr1.sin_addr.s_addr = inet_addr("127.0.0.255");addr1.sin_port = htons(5555);while (1){char buffer[1024] = {0};scanf("%s", buffer);sendto(sock_fd, buffer, sizeof(buffer),0, (struct sockaddr *)&addr1, sizeof(addr1));}return 0;
}接受广播:#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>int main(int argc, char **argv)
{int sock_fd = socket(AF_INET, SOCK_DGRAM, 0);if (sock_fd < 0){perror("socket error");exit(-1);}int j = 1;setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, &j, sizeof(j));struct sockaddr_in addr1;addr1.sin_family = AF_INET;//*****************************************************************************//addr1.sin_addr.s_addr = htons(INADDR_ANY);//为什么是htons和htonl!!!!//*****************************************************************************//addr1.sin_port = htons(5555);int ret = bind(sock_fd, (struct sockaddr *)&addr1, sizeof(addr1));if (ret < 0){perror("bind error");exit(-1);}struct sockaddr_in addr2;int len = sizeof(addr2);memset(&addr2, 0, sizeof(addr2));char buffer[1024];while (1){memset(buffer, 0, sizeof(buffer));recvfrom(sock_fd, buffer, sizeof(buffer),0, (struct sockaddr *)&addr2, &len);printf("recv %s\n", buffer);}return 0;
}

组播

把一些ip设置为一个组,给这些组,发消息(后续在QT里涉及到

相关文章:

Linux 网络编程

套接字&#xff08;Socket&#xff09;&#xff1a; 通过网络实现跨机通信 作用&#xff1a;一种文件描述符传输层的文件描述符 整个编程中&#xff0c;需要着重注意htonl/htons、ntohl/ntohs、inet_addr等 TCP的C/S实现 循环服务器模型 TCP服务器实现过程 1.创建套接字&a…...

SpringBoot读取配置的方式

在 Spring Boot 应用中&#xff0c;我们通常需要一些配置信息来指导应用的运行。这些配置信息可以包括如下内容&#xff1a;端口号、数据库连接信息、日志配置、缓存配置、认证配置、等等。Spring Boot 提供了多种方式来读取这些配置信息。读取配置的目的是为了在程序中使用这些…...

c# winform程序,DispatcherTimer被调用延迟,响应间隔长

c# winform程序&#xff0c;DispatcherTimer被调用延迟&#xff0c;响应间隔长 最近修改的问题&#xff0c;winform界面上两个控件的数据刷新&#xff0c;用DispatcherTimer定时刷新&#xff0c;但是在某些机器上的实际刷新时间间隔远远大于设置时间。 既然MSDN已经说了&…...

【智能家居项目】裸机版本——项目介绍 | 输入子系统(按键) | 单元测试

&#x1f431;作者&#xff1a;一只大喵咪1201 &#x1f431;专栏&#xff1a;《智能家居项目》 &#x1f525;格言&#xff1a;你只管努力&#xff0c;剩下的交给时间&#xff01; 目录 &#x1f3c0;项目简介&#x1f3c0;输入子系统(按键)⚽应用层⚽设备层⚽ 内核层抽象层⚽…...

算法练习8——有序三元组中的最大值

LeetCode 100088 有序三元组中的最大值 I LeetCode 100086 有序三元组中的最大值 II 给你一个下标从 0 开始的整数数组 nums 。 请你从所有满足 i < j < k 的下标三元组 (i, j, k) 中&#xff0c;找出并返回下标三元组的最大值。如果所有满足条件的三元组的值都是负数&am…...

git创建

问: git remote add origin https://github.com//blog.git fatal: not a git repository (or any of the parent directories): .git 回答: 这个错误提示指出当前目录或其父目录中不存在.git文件夹&#xff0c;因此无法执行git相关操作。请确保你是在一个已经初始化为git仓库…...

yolov8 opencv模型部署(python版)

yolov8 opencv模型部署&#xff08;python版&#xff09; 使用opencv推理yolov8模型&#xff0c;以yolov8n为例子&#xff0c;一共几十行代码&#xff0c;没有废话&#xff0c;给出了注释&#xff0c;从今天起&#xff0c;少写一行代码&#xff0c;少掉一根头发。测试数据有需…...

Simulink仿真封装中的参数个对话框设置

目录 参数和对话框窗格 初始化窗格 文档窗格 为了更加直观和清晰的分析仿真&#xff0c;会将多个元件实现的一个功能封装在一起&#xff0c;通过参数对话框窗格&#xff0c;可以使用参数、显示和动作选项板中的对话框控制设计封装对话框。如图所示&#xff1a; 参数和对话框…...

【C++】class的设计与使用(十)重载iostream运算符

希望对某个类对象进行读写操作&#xff0c;直接cout<<类对象<<endl;或cin>>类对象;编译器会报错&#xff0c;所以我们必须提供一份重载的input/output运算符&#xff1a; 重载ostream运算符 ostream& operator<<(ostream &os, const Triangu…...

Java使用Scanner类实现用户输入与交互

概述&#xff1a; Scanner类是Java中的一个重要工具类&#xff0c;用于读取用户的输入。它提供了一系列的方法&#xff0c;可以方便地读取不同类型的数据&#xff0c;如整数、浮点数、字符串等。在本文中&#xff0c;我们将详细介绍Scanner类的使用方法&#xff0c;并通过两个…...

FFmpeg 命令:从入门到精通 | ffppeg 命令参数说明

FFmpeg 命令&#xff1a;从入门到精通 | ffmpeg 命令参数说明 FFmpeg 命令&#xff1a;从入门到精通 | ffmpeg 命令参数说明主要参数音频参数视频参数更多参考 FFmpeg 命令&#xff1a;从入门到精通 | ffmpeg 命令参数说明 本节主要介绍了 ffmpeg 命令的常用参数。 主要参数 …...

Chrome(谷歌浏览器)如何关闭搜索栏历史记录

目录 问题描述解决方法插件解决&#xff08;亲测有效&#xff09;自带设置解决步骤首先打开 地址 输入&#xff1a;chrome://flags关闭浏览器&#xff0c;重新打开Chrome 发现 已经正常 问题描述 Chrome是大家熟知的浏览器&#xff0c;但是搜索栏的历史记录如何自己一条条的删…...

基于Java的宠物医院管理系统设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09;有保障的售后福利 代码参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作…...

使用WPS自动化转换办公文档: 将Word, PowerPoint和Excel文件转换为PDF

&#x1f337;&#x1f341; 博主猫头虎 带您 Go to New World.✨&#x1f341; &#x1f984; 博客首页——猫头虎的博客&#x1f390; &#x1f433;《面试题大全专栏》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &a…...

对pyside6中的textedit进行自定义,实现按回车可以触发事件。

我的实现方法是&#xff0c;先用qt designer写好界面&#xff0c;如下图&#xff1a; 接着将其生成的ui文件编译成为py文件。 找到里面这几行代码&#xff1a; self.textEdit QTextEdit(self.centralwidget)self.textEdit.setObjectName(u"textEdit")self.textEdit…...

Spark SQL

Spark SQL 一、Spark SQL概述二、准备Spark SQL的编程环境三、Spark SQL程序编程的入口四、DataFrame的创建五、DataFrame的编程风格六、DataSet的创建和使用七、Spark SQL的函数操作 一、Spark SQL概述 Spark SQL属于Spark计算框架的一部分&#xff0c;是专门负责结构化数据的…...

初识多线程

一、多任务 现实中太多这样同时做多件事的例子了&#xff0c;例如一边吃饭一遍刷视频&#xff0c;看起来是多个任务都在做&#xff0c;其实本质上我们的大脑在同一时间依旧只做了一件事情。 二、普通方法调用和多线程 普通方法调用只有主线程一条执行路径 多线程多条执行路径…...

Linux用户、用户组和文件权限的管理与实践

目录 一、Linux用户、用户组和文件权限的基础概念与作用1.1 Linux用户的概念与作用1.2 Linux用户组的概念与作用1.3 Linux文件权限的概念与作用 二、Linux用户、用户组和文件权限的具体操作实践2.1 创建新用户&#xff1a;从零开始构建用户体系2.2 修改用户和用户组属性&#x…...

【CMU15-445 Part-14】Query Planning Optimization I

Part14-Query Planning & Optimization I SQL is Declarative&#xff0c;只告诉想要什么而不需要说怎么做。 IBM System R是第一个实现query optimizer查询优化器的系统 Heuristics / Rules 条件触发 静态规则&#xff0c;重写query来remove 低效或者愚蠢的东西&#xf…...

七、垃圾收集中级

JVM由浅入深系列 JVM由浅入深系列一、关于Java性能的误解二、Java性能概述三、了解JVM概述四、探索JVM架构五、垃圾收集基础六、HotSpot中的垃圾收集七、垃圾收集中级八、垃圾收集高级👋垃圾收集中级 ⚽️1. 权衡收集器插件 就 Java 平台而言,有一点可能初学者未必能马上意…...

Python|GIF 解析与构建(5):手搓截屏和帧率控制

目录 Python&#xff5c;GIF 解析与构建&#xff08;5&#xff09;&#xff1a;手搓截屏和帧率控制 一、引言 二、技术实现&#xff1a;手搓截屏模块 2.1 核心原理 2.2 代码解析&#xff1a;ScreenshotData类 2.2.1 截图函数&#xff1a;capture_screen 三、技术实现&…...

PPT|230页| 制造集团企业供应链端到端的数字化解决方案:从需求到结算的全链路业务闭环构建

制造业采购供应链管理是企业运营的核心环节&#xff0c;供应链协同管理在供应链上下游企业之间建立紧密的合作关系&#xff0c;通过信息共享、资源整合、业务协同等方式&#xff0c;实现供应链的全面管理和优化&#xff0c;提高供应链的效率和透明度&#xff0c;降低供应链的成…...

Mybatis逆向工程,动态创建实体类、条件扩展类、Mapper接口、Mapper.xml映射文件

今天呢&#xff0c;博主的学习进度也是步入了Java Mybatis 框架&#xff0c;目前正在逐步杨帆旗航。 那么接下来就给大家出一期有关 Mybatis 逆向工程的教学&#xff0c;希望能对大家有所帮助&#xff0c;也特别欢迎大家指点不足之处&#xff0c;小生很乐意接受正确的建议&…...

家政维修平台实战20:权限设计

目录 1 获取工人信息2 搭建工人入口3 权限判断总结 目前我们已经搭建好了基础的用户体系&#xff0c;主要是分成几个表&#xff0c;用户表我们是记录用户的基础信息&#xff0c;包括手机、昵称、头像。而工人和员工各有各的表。那么就有一个问题&#xff0c;不同的角色&#xf…...

质量体系的重要

质量体系是为确保产品、服务或过程质量满足规定要求&#xff0c;由相互关联的要素构成的有机整体。其核心内容可归纳为以下五个方面&#xff1a; &#x1f3db;️ 一、组织架构与职责 质量体系明确组织内各部门、岗位的职责与权限&#xff0c;形成层级清晰的管理网络&#xf…...

土地利用/土地覆盖遥感解译与基于CLUE模型未来变化情景预测;从基础到高级,涵盖ArcGIS数据处理、ENVI遥感解译与CLUE模型情景模拟等

&#x1f50d; 土地利用/土地覆盖数据是生态、环境和气象等诸多领域模型的关键输入参数。通过遥感影像解译技术&#xff0c;可以精准获取历史或当前任何一个区域的土地利用/土地覆盖情况。这些数据不仅能够用于评估区域生态环境的变化趋势&#xff0c;还能有效评价重大生态工程…...

如何理解 IP 数据报中的 TTL?

目录 前言理解 前言 面试灵魂一问&#xff1a;说说对 IP 数据报中 TTL 的理解&#xff1f;我们都知道&#xff0c;IP 数据报由首部和数据两部分组成&#xff0c;首部又分为两部分&#xff1a;固定部分和可变部分&#xff0c;共占 20 字节&#xff0c;而即将讨论的 TTL 就位于首…...

ABAP设计模式之---“简单设计原则(Simple Design)”

“Simple Design”&#xff08;简单设计&#xff09;是软件开发中的一个重要理念&#xff0c;倡导以最简单的方式实现软件功能&#xff0c;以确保代码清晰易懂、易维护&#xff0c;并在项目需求变化时能够快速适应。 其核心目标是避免复杂和过度设计&#xff0c;遵循“让事情保…...

R语言速释制剂QBD解决方案之三

本文是《Quality by Design for ANDAs: An Example for Immediate-Release Dosage Forms》第一个处方的R语言解决方案。 第一个处方研究评估原料药粒径分布、MCC/Lactose比例、崩解剂用量对制剂CQAs的影响。 第二处方研究用于理解颗粒外加硬脂酸镁和滑石粉对片剂质量和可生产…...

JS手写代码篇----使用Promise封装AJAX请求

15、使用Promise封装AJAX请求 promise就有reject和resolve了&#xff0c;就不必写成功和失败的回调函数了 const BASEURL ./手写ajax/test.jsonfunction promiseAjax() {return new Promise((resolve, reject) > {const xhr new XMLHttpRequest();xhr.open("get&quo…...