鸿蒙开发实战:【网络管理-Socket连接】

介绍

本示例主要演示了Socket在网络通信方面的应用,展示了Socket在两端设备的连接验证、聊天通信方面的应用。

效果预览

使用说明

1.打开应用,点击用户文本框选择要登录的用户,并输入另一个设备的IP地址,点击确定按钮进入已登录的用户页面(两个设备都要依次执行此步骤)。

2.在其中一个设备上点击创建房间按钮,任意输入房间号,另一个设备会收到有房间号信息的弹框,点击确定按钮后,两个设备进入聊天页面。

3.在其中一个设备上输入聊天信息并点击发送按钮后,另一个设备的聊天页面会收到该聊天消息。

4.点击顶部标题栏右侧的退出图标按钮,则返回已登录的用户页面。

5.点击聊天页面中的昵称栏,会弹出一个菜单,选择离线选项后,两端设备的状态图标都会切换为离线图标,并且昵称栏都会变成灰色,此时任何一端发送消息另一端都接收不到消息。

6.当点击昵称栏再次切换为在线状态,则两端的己方账号状态会切换为在线图标,同时两端的昵称栏会显示蓝色,此时可正常收发消息。

工程目录

entry/src/main/ets/MainAbility
|---app.ets
|---model
|   |---chatBox.ts                     // 聊天页面
|   |---DataSource.ts                  // 数据获取
|   |---Logger.ts                      // 日志工具
|---pages
|   |---Index.ets                      // 监听消息页面
|   |---Login.ets                      // 首页登录页面
|---Utils
|   |---Utils.ets

具体实现

  • 本示例分为三个模块
    • 输入对端IP模块
      • 使用wifi.getIpInfo()方法获取IP地址,constructUDPSocketInstance方法创建一个UDPSocket对象
      • 源码链接:[Login.ets]
/** Copyright (c) 2022-2023 Huawei Device Co., Ltd.* Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at**     http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/import wifi from '@ohos.wifi';
import router from '@ohos.router';
import { resolveIP } from '../Utils/Util'
import socket from '@ohos.net.socket';
import Logger from '../model/Logger'const TAG: string = '[Login]'let localAddr = {address: resolveIP(wifi.getIpInfo().ipAddress),family: 1,port: 0
}
let oppositeAddr = {address: '',family: 1,port: 0
}
let loginCount = 0let udp = socket.constructUDPSocketInstance()@Entry
@Component
struct Login {@State login_feng: boolean = false@State login_wen: boolean = false@State user: string = ''@State roomDialog: boolean = false@State confirmDialog: boolean = false@State ipDialog: boolean = true@State warnDialog: boolean = false@State warnText: string = ''@State roomNumber: string = ''@State receiveMsg: string = ''bindOption() {let bindOption = udp.bind(localAddr);bindOption.then(() => {Logger.info(TAG, 'bind success');}).catch(err => {Logger.info(TAG, 'bind fail');})udp.on('message', data => {Logger.info(TAG, `data:${JSON.stringify(data)}`);let buffer = data.message;let dataView = new DataView(buffer);Logger.info(TAG, `length = ${dataView.byteLength}`);let str = '';for (let i = 0;i < dataView.byteLength; ++i) {let c = String.fromCharCode(dataView.getUint8(i));if (c != '') {str += c;}}if (str == 'ok') {router.clear();loginCount += 1;router.push({url: 'pages/Index',params: { address: oppositeAddr.address, port: oppositeAddr.port, loginCount: loginCount }})}else {this.receiveMsg = str;this.confirmDialog = true;}})}build() {Stack({ alignContent: Alignment.Center }) {Column() {Text($r('app.string.MainAbility_label')).width('100%').height(50).backgroundColor('#0D9FFB').textAlign(TextAlign.Start).fontSize(25).padding({ left: 10 }).fontColor(Color.White).fontWeight(FontWeight.Bold)if (!this.ipDialog) {Column() {Image(this.login_feng ? $r('app.media.fengziOn') : $r('app.media.wenziOn')).width(100).height(100).objectFit(ImageFit.Fill)Text('用户名:' + this.user).fontSize(25).margin({ top: 50 })Button() {Text($r('app.string.create_room')).fontSize(25).fontColor(Color.White)}.width('150').height(50).margin({ top: 30 }).type(ButtonType.Capsule).onClick(() => {this.roomDialog = truethis.bindOption()})}.width('90%').margin({ top: 100 })}}.width('100%').height('100%')if (this.confirmDialog) {Column() {Text('确认码:' + this.receiveMsg).fontSize(25)Row() {Button($r('app.string.cancel')).onClick(() => {this.confirmDialog = false}).backgroundColor(0xffffff).fontColor(Color.Black)Button($r('app.string.confirm')).onClick(() => {udp.send({data: 'ok',address: oppositeAddr}).then(function (data) {Logger.info(TAG, `send ${JSON.stringify(data)}`);}).catch(function (err) {Logger.info(TAG, `send ${JSON.stringify(err)}`);})router.clear()loginCount += 1;router.push({url: 'pages/Index',params: { address: oppositeAddr.address, port: oppositeAddr.port, loginCount: loginCount }})this.confirmDialog = false;}).backgroundColor(0xffffff).fontColor(Color.Red)}.margin({ bottom: 10 }).justifyContent(FlexAlign.SpaceAround)}.width('80%').height(150).margin({ top: '10%' }).backgroundColor(Color.White).border({ radius: 10, width: 3 })}if (this.ipDialog) {Column() {Text('本地IP:' + localAddr.address).fontSize(25).margin({ top: 10 })Text('用户:' + this.user).fontSize(20).margin({ top: 10 }).bindMenu([{value: '风子',action: () => {this.user = '风子'this.login_feng = truethis.login_wen = falselocalAddr.port = 8080oppositeAddr.port = 9090}},{value: '蚊子',action: () => {this.user = '蚊子'this.login_wen = truethis.login_feng = falselocalAddr.port = 9090oppositeAddr.port = 8080}}])TextInput({ placeholder: '请输入对端ip' }).width(200).fontSize(25).margin({ top: 10 }).onChange((value: string) => {oppositeAddr.address = value;})if (this.warnDialog) {Text(this.warnText).fontSize(10).fontColor(Color.Red).margin({ top: 5 })}Button($r('app.string.confirm')).fontColor(Color.Black).height(30).margin({ bottom: 10 }).onClick(() => {if (this.user == '') {this.warnDialog = true;this.warnText = '请先选择用户';} else if (oppositeAddr.address === '') {this.warnDialog = true;this.warnText = '请先输入对端IP';} else {this.bindOption()this.ipDialog = false;Logger.debug(TAG, `peer ip=${oppositeAddr.address}`);Logger.debug(TAG, `peer port=${oppositeAddr.port}`);Logger.debug(TAG, `peer port=${localAddr.port}`);}}).backgroundColor(0xffffff)}.width('80%').height(200).margin({ top: '10%' }).backgroundColor(Color.White).border({ radius: 10, width: 3 })}if (this.roomDialog) {Column() {Text($r('app.string.input_roomNumber')).fontSize(25).margin({ top: 10 })TextInput().width(100).fontSize(25).margin({ top: 10 }).onChange((value: string) => {this.roomNumber = value;})Row() {Button($r('app.string.cancel')).onClick(() => {this.roomDialog = false}).backgroundColor(0xffffff).fontColor(Color.Black)Button($r('app.string.confirm')).onClick(() => {Logger.info(TAG, `[ROOM]address=${oppositeAddr.address}`);Logger.info(TAG, `[ROOM]port=${oppositeAddr.port}`);/*点击确定后发送房间号,另一端开始监听*/Logger.info(TAG, `[ROOM]oppositeAddr.address=${oppositeAddr.address}`);Logger.info(TAG, `[ROOM]oppositeAddr.port=${oppositeAddr.port}`);Logger.info(TAG, `[ROOM]localAddr.address=${localAddr.address}`);Logger.info(TAG, `[ROOM]localAddr.port=${localAddr.port}`);this.bindOption()udp.send({data: this.roomNumber,address: oppositeAddr}).then(function (data) {Logger.info(TAG, `send success, data = ${JSON.stringify(data)}`);}).catch(function (err) {Logger.info(TAG, `send fail, err = ${JSON.stringify(err)}`);})this.roomDialog = false;}).backgroundColor(0xffffff).fontColor(Color.Red)}.margin({ bottom: 10 }).justifyContent(FlexAlign.SpaceAround)}.width('80%').height(150).margin({ top: '10%' }).backgroundColor(Color.White).border({ radius: 10, width: 3 })}}}
}

[Util.ets]

/** Copyright (c) 2022-2023 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* 
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.*/export function resolveIP(ip) {
if (ip < 0 || ip > 0xFFFFFFFF) {
throw ('The number is not normal!');
}
return (ip >>> 24) + '.' + (ip >> 16 & 0xFF) + '.' + (ip >> 8 & 0xFF) + '.' + (ip & 0xFF);
}
  • 创建房间模块
    • 点击创建房间按钮,弹出创建房间框,输入房间号,点击确定,进入聊天页面
    • 源码链接:[Login.ets]
/** Copyright (c) 2022-2023 Huawei Device Co., Ltd.* Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at**     http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/import wifi from '@ohos.wifi';
import router from '@ohos.router';
import { resolveIP } from '../Utils/Util'
import socket from '@ohos.net.socket';
import Logger from '../model/Logger'const TAG: string = '[Login]'let localAddr = {address: resolveIP(wifi.getIpInfo().ipAddress),family: 1,port: 0
}
let oppositeAddr = {address: '',family: 1,port: 0
}
let loginCount = 0let udp = socket.constructUDPSocketInstance()@Entry
@Component
struct Login {@State login_feng: boolean = false@State login_wen: boolean = false@State user: string = ''@State roomDialog: boolean = false@State confirmDialog: boolean = false@State ipDialog: boolean = true@State warnDialog: boolean = false@State warnText: string = ''@State roomNumber: string = ''@State receiveMsg: string = ''bindOption() {let bindOption = udp.bind(localAddr);bindOption.then(() => {Logger.info(TAG, 'bind success');}).catch(err => {Logger.info(TAG, 'bind fail');})udp.on('message', data => {Logger.info(TAG, `data:${JSON.stringify(data)}`);let buffer = data.message;let dataView = new DataView(buffer);Logger.info(TAG, `length = ${dataView.byteLength}`);let str = '';for (let i = 0;i < dataView.byteLength; ++i) {let c = String.fromCharCode(dataView.getUint8(i));if (c != '') {str += c;}}if (str == 'ok') {router.clear();loginCount += 1;router.push({url: 'pages/Index',params: { address: oppositeAddr.address, port: oppositeAddr.port, loginCount: loginCount }})}else {this.receiveMsg = str;this.confirmDialog = true;}})}build() {Stack({ alignContent: Alignment.Center }) {Column() {Text($r('app.string.MainAbility_label')).width('100%').height(50).backgroundColor('#0D9FFB').textAlign(TextAlign.Start).fontSize(25).padding({ left: 10 }).fontColor(Color.White).fontWeight(FontWeight.Bold)if (!this.ipDialog) {Column() {Image(this.login_feng ? $r('app.media.fengziOn') : $r('app.media.wenziOn')).width(100).height(100).objectFit(ImageFit.Fill)Text('用户名:' + this.user).fontSize(25).margin({ top: 50 })Button() {Text($r('app.string.create_room')).fontSize(25).fontColor(Color.White)}.width('150').height(50).margin({ top: 30 }).type(ButtonType.Capsule).onClick(() => {this.roomDialog = truethis.bindOption()})}.width('90%').margin({ top: 100 })}}.width('100%').height('100%')if (this.confirmDialog) {Column() {Text('确认码:' + this.receiveMsg).fontSize(25)Row() {Button($r('app.string.cancel')).onClick(() => {this.confirmDialog = false}).backgroundColor(0xffffff).fontColor(Color.Black)Button($r('app.string.confirm')).onClick(() => {udp.send({data: 'ok',address: oppositeAddr}).then(function (data) {Logger.info(TAG, `send ${JSON.stringify(data)}`);}).catch(function (err) {Logger.info(TAG, `send ${JSON.stringify(err)}`);})router.clear()loginCount += 1;router.push({url: 'pages/Index',params: { address: oppositeAddr.address, port: oppositeAddr.port, loginCount: loginCount }})this.confirmDialog = false;}).backgroundColor(0xffffff).fontColor(Color.Red)}.margin({ bottom: 10 }).justifyContent(FlexAlign.SpaceAround)}.width('80%').height(150).margin({ top: '10%' }).backgroundColor(Color.White).border({ radius: 10, width: 3 })}if (this.ipDialog) {Column() {Text('本地IP:' + localAddr.address).fontSize(25).margin({ top: 10 })Text('用户:' + this.user).fontSize(20).margin({ top: 10 }).bindMenu([{value: '风子',action: () => {this.user = '风子'this.login_feng = truethis.login_wen = falselocalAddr.port = 8080oppositeAddr.port = 9090}},{value: '蚊子',action: () => {this.user = '蚊子'this.login_wen = truethis.login_feng = falselocalAddr.port = 9090oppositeAddr.port = 8080}}])TextInput({ placeholder: '请输入对端ip' }).width(200).fontSize(25).margin({ top: 10 }).onChange((value: string) => {oppositeAddr.address = value;})if (this.warnDialog) {Text(this.warnText).fontSize(10).fontColor(Color.Red).margin({ top: 5 })}Button($r('app.string.confirm')).fontColor(Color.Black).height(30).margin({ bottom: 10 }).onClick(() => {if (this.user == '') {this.warnDialog = true;this.warnText = '请先选择用户';} else if (oppositeAddr.address === '') {this.warnDialog = true;this.warnText = '请先输入对端IP';} else {this.bindOption()this.ipDialog = false;Logger.debug(TAG, `peer ip=${oppositeAddr.address}`);Logger.debug(TAG, `peer port=${oppositeAddr.port}`);Logger.debug(TAG, `peer port=${localAddr.port}`);}}).backgroundColor(0xffffff)}.width('80%').height(200).margin({ top: '10%' }).backgroundColor(Color.White).border({ radius: 10, width: 3 })}if (this.roomDialog) {Column() {Text($r('app.string.input_roomNumber')).fontSize(25).margin({ top: 10 })TextInput().width(100).fontSize(25).margin({ top: 10 }).onChange((value: string) => {this.roomNumber = value;})Row() {Button($r('app.string.cancel')).onClick(() => {this.roomDialog = false}).backgroundColor(0xffffff).fontColor(Color.Black)Button($r('app.string.confirm')).onClick(() => {Logger.info(TAG, `[ROOM]address=${oppositeAddr.address}`);Logger.info(TAG, `[ROOM]port=${oppositeAddr.port}`);/*点击确定后发送房间号,另一端开始监听*/Logger.info(TAG, `[ROOM]oppositeAddr.address=${oppositeAddr.address}`);Logger.info(TAG, `[ROOM]oppositeAddr.port=${oppositeAddr.port}`);Logger.info(TAG, `[ROOM]localAddr.address=${localAddr.address}`);Logger.info(TAG, `[ROOM]localAddr.port=${localAddr.port}`);this.bindOption()udp.send({data: this.roomNumber,address: oppositeAddr}).then(function (data) {Logger.info(TAG, `send success, data = ${JSON.stringify(data)}`);}).catch(function (err) {Logger.info(TAG, `send fail, err = ${JSON.stringify(err)}`);})this.roomDialog = false;}).backgroundColor(0xffffff).fontColor(Color.Red)}.margin({ bottom: 10 }).justifyContent(FlexAlign.SpaceAround)}.width('80%').height(150).margin({ top: '10%' }).backgroundColor(Color.White).border({ radius: 10, width: 3 })}}}
}

[Util.ets]

/** Copyright (c) 2022-2023 Huawei Device Co., Ltd.* Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at**     http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/export function resolveIP(ip) {if (ip < 0 || ip > 0xFFFFFFFF) {throw ('The number is not normal!');}return (ip >>> 24) + '.' + (ip >> 16 & 0xFF) + '.' + (ip >> 8 & 0xFF) + '.' + (ip & 0xFF);
}
相关概念

UDP Socket是面向非连接的协议,它不与对方建立连接,而是直接把我要发的数据报发给对方,适用于一次传输数据量很少、对可靠性要求不高的或对实时性要求高的应用场景。

相关权限

1.允许使用Internet网络权限:[ohos.permission.INTERNET]

2.允许应用获取WLAN信息权限:[ohos.permission.GET_WIFI_INFO]

依赖

不涉及。

约束与限制

1.本示例仅支持标准系统上运行,支持设备:RK3568。

2.本示例仅支持API9版本SDK,版本号:3.2.11.9 及以上。

3.本示例需要使用DevEco Studio 3.1 Beta2 (Build Version: 3.1.0.400 构建 2023年4月7日)及以上才可编译运行。

下载

如需单独下载本工程,执行如下命令:

git init
git config core.sparsecheckout true
echo code\BasicFeature\Connectivity\Socket > .git/info/sparse-checkout
git remote add origin https://gitee.com/openharmony/applications_app_samples.git
git pull origin master

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【C++】用红黑树模拟实现set、map

目录 前言及准备&#xff1a;一、红黑树接口1.1 begin1.2 end1.3 查找1.4 插入1.5 左单旋和右单旋 二、树形迭代器&#xff08;正向&#xff09;2.1 前置 三、模拟实现set四、模拟实现map 前言及准备&#xff1a; set、map的底层结构是红黑树&#xff0c;它们的函数通过调用红…

鸿蒙Harmony应用开发—ArkTS声明式开发(基础手势:Toggle)

组件提供勾选框样式、状态按钮样式及开关样式。 说明&#xff1a; 该组件从API Version 8开始支持。后续版本如有新增内容&#xff0c;则采用上角标单独标记该内容的起始版本。 子组件 仅当ToggleType为Button时可包含子组件。 接口 Toggle(options: { type: ToggleType, is…

一台电脑安装多个版本node,如何切换使用

直接上答案&#xff0c;请安装nvm——nodejs的版本管理工具 官网地址在此&#xff1a;nvm文档手册 - nvm是一个nodejs版本管理工具 - nvm中文网 (uihtm.com) 1.由于我电脑本来就有node14&#xff0c;所以需要先卸载 原来的node&#xff0c;建议在软件目录自带的node文件夹中点…

Java学习笔记NO.20

Java流程控制 1. 用户交互 Scanner Java中的Scanner类用于获取用户输入&#xff0c;可以从标准输入&#xff08;键盘&#xff09;读取各种类型的数据。 import java.util.Scanner; public class UserInputExample { public static void main(String[] args) { Scanner sc…

weaviate向量库安装

简介 Weaviate 是一个开源的向量数据库和搜索引擎&#xff0c;专门用于存储、搜索和分析向量数据。它提供了一个简单易用的 REST API&#xff0c;使得用户可以轻松地将向量数据存储到数据库中&#xff0c;并且能够以高效的方式进行相似向量的搜索。 以下是一些 Weaviate 向量…

面向切面的编程实战

面向切面的编程&#xff08;AOP&#xff09;就是让哥们写代码的时候更加关注核心业务的实现&#xff0c;将核心业务代码前后的日志等不重要的通过注解的方式&#xff0c;交给其他部分完成&#xff0c;使得代码有更高的可维护性。 具体使用 先定义一个注解 Target(ElementTyp…

[Java、Android面试]_08_强软弱虚四种引用及应用场景

本人今年参加了很多面试&#xff0c;也有幸拿到了一些大厂的offer&#xff0c;整理了众多面试资料&#xff0c;后续还会分享众多面试资料。 整理成了面试系列&#xff0c;由于时间有限&#xff0c;每天整理一点&#xff0c;后续会陆续分享出来&#xff0c;感兴趣的朋友可关注收…

SpringBoot3框架,基础特性

MyBatis整合 导入MyBatis整合的依赖&#xff1a; <!-- <https://mvnrepository.com/artifact/org.mybatis.spring.boot/mybatis-spring-boot-starter> --> <dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-…

电机驱动器不确定性建模

跟踪误差信号和执行器驱动信号在控制系统的设计中也很重要&#xff01;&#xff01;&#xff01; 不确定度可分为扰动信号和动态扰动两类。前者包括输入和输出干扰&#xff08;如飞机上的阵风&#xff09;、传感器噪声和执行器噪声等。后者表示数学模型与系统在运行中的实际动…

Geostationary IR Channel Brightness Temperature - GridSat B1 -- shell下载

进入网页 https://www.ncei.noaa.gov/products/gridded-geostationary-brightness-temperature 然后进入数据目录&#xff0c;通过https的方式进行下载&#xff1a; 点击后进入如下界面&#xff1a; 点击任意年份进行下载 这里以2004年为例&#xff0c;如下所示&#xff1…

【CSS练习】万年历 html+css+js

效果图 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name"viewport" content"widthdevice-width, initial-scale1.0" /><title>Document</title><style>bod…

实现:mysql-5.7.42 到 mysql-8.2.0 的升级(二进制方式)

实现&#xff1a;mysql-5.7.42 到 mysql-8.2.0 的升级&#xff08;二进制方式&#xff09; 1、操作环境1、查看当前数据库版本2、操作系统版本3、查看 Linux 系统上的 glibc&#xff08;GNU C 库&#xff09;版本&#xff08;**这里很重要&#xff0c;要下载对应的内核mysql版本…

软件设计师

计算机系统知识 浮点数 运算&#xff1a;小阶对齐大阶 海明码 数据位n校验位k&#xff0c;必须满足 2k-1≥nk 吞吐率 p为最长子过程的倒数 数据结构 图 深度遍历时间复杂度&#xff1a; 邻接矩阵n2 邻接表ne 操作系统 进程 信号量P、V、S P申请资源&#xff0c;V释…

Linux 进程管理工具top ps

概述 top 和 ps 是 Linux 系统中两个非常重要的用于管理和监控进程的命令工具。以下是它们的主要功能和区别&#xff1a; top&#xff1a; 动态视图&#xff1a;top 提供了一个实时动态更新的视图&#xff0c;能够持续显示系统中当前正在运行的进程信息及其资源占用情况。 系统…

安卓面试题多线程11-15

11. 如何使用thread dump?你将如何分析Thread dump?在UNIX中你可以使用kill -3,然后thread dump将会打印日志,在windows中你可以使用”CTRL+Break”。非常简单和专业的线程面试问题,但是如果他问你怎样分析它,就会很棘手。🚀🚀🚀🚀🚀🚀12. Java中你怎样唤醒一…

注意力机制 self-attention 的原理探究

一、点积的认识 向量的点积可以表示相似性的原因在于它衡量了两个向量之间的方向是否相似。当两个向量的方向趋于一致时&#xff0c;它们的点积会更大&#xff1b;当两个向量的方向趋于相互垂直时&#xff0c;它们的点积会接近于0。这种性质使得点积在衡量向量之间的相似性和相…

聚合函数和GROUP BY

1、聚合函数 1.1 聚合函数概念 聚合函数是用于对一组数值进行计算并返回单一数值作为结果的函数。在数据库查询中&#xff0c;它们通常用于对数据进行汇总和统计分析。常见的聚合函数包括 SUM、AVG、COUNT、MAX 和 MIN 等。 1.2 函数介绍 1.2.1 SUM&#xff08;求和&#x…

Devops-02-Jpom 简而轻的低侵入式在线构建、自动部署、日常运维、项目监控软件

拓展阅读 Devops-01-devops 是什么&#xff1f; Devops-02-Jpom 简而轻的低侵入式在线构建、自动部署、日常运维、项目监控软件 代码质量管理 SonarQube-01-入门介绍 项目管理平台-01-jira 入门介绍 缺陷跟踪管理系统&#xff0c;为针对缺陷管理、任务追踪和项目管理的商业…

ins中扰动分析举例

扰动分析很重要&#xff0c;搞明白扰动分析&#xff0c;基本上就可以清楚了误差模型。 什么是扰动分析&#xff1a; 简单理解 测量值 真值 误差 这里的误差就是与测量直接对应的误差&#xff0c;例如 把误差分离出来 误差 测量值 - 真值 &#xff…

如何在海外服务器上配置静态路由?

在海外服务器上配置静态路由可以通过操作系统提供的网络配置工具来实现。下面是在常见操作系统上配置静态路由的一般步骤&#xff1a; 在 Windows 上&#xff1a; 打开命令提示符&#xff1a;在开始菜单中搜索并打开“命令提示符”(或者以管理员身份运行)。 查看当前路由表&…