鸿蒙开发实战:【网络管理-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 = 0

let 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 = true
              this.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 = true
                this.login_wen = false
                localAddr.port = 8080
                oppositeAddr.port = 9090
              }
            },
              {
                value: '蚊子',
                action: () => {
                  this.user = '蚊子'
                  this.login_wen = true
                  this.login_feng = false
                  localAddr.port = 9090
                  oppositeAddr.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 = 0

let 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 = true
              this.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 = true
                this.login_wen = false
                localAddr.port = 8080
                oppositeAddr.port = 9090
              }
            },
              {
                value: '蚊子',
                action: () => {
                  this.user = '蚊子'
                  this.login_wen = true
                  this.login_feng = false
                  localAddr.port = 9090
                  oppositeAddr.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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

JavaScript高级系列(三) - JavaScript的运行过程

一. 全局代码的执行过程 1.1. ECMA的版本说明 在ECMA早期的版本&#xff08;ECMAScript3&#xff09;&#xff0c;代码的执行流程的术语和ECMAScript5以及之后的术语会有所区别&#xff1a; 目前网上大多数流行的说法都是基于ECMAScript3版本的解析&#xff0c; 并且在面试问…

实现el-table合并列

效果图如下 <el-table :data"atlasDataList" style"width: 100%" :span-method"spanMethod"><el-table-column prop"stationName" label"" width"180" /><el-table-column prop"atlasNumbe…

网络编程—DAY5

select实现的TCP并发服务器 #include <myhead.h> #define SER_PORT 8888 #define SER_IP "192.168.117.96"int main(int argc, const char *argv[]) {int sfd -1;sfd socket(AF_INET,SOCK_STREAM,0);if(sfd -1){perror("socket");return -1;}prin…

LVGL:拓展部件——键盘 lv_keyboard

一、概述 此控件特点&#xff1a; 特殊Button矩阵&#xff1a;lv_keyboard 本质上是一个经过定制的按钮矩阵控件。每个按钮都可以独立触发事件或响应。预定义的键映射&#xff1a;lv_keyboard 自带了一套预设的按键布局和对应的字符映射表&#xff0c;开发者可以根据需要选择…

【Vue3】Vue3中的编程式路由导航 重点!!!

&#x1f497;&#x1f497;&#x1f497;欢迎来到我的博客&#xff0c;你将找到有关如何使用技术解决问题的文章&#xff0c;也会找到某个技术的学习路线。无论你是何种职业&#xff0c;我都希望我的博客对你有所帮助。最后不要忘记订阅我的博客以获取最新文章&#xff0c;也欢…

大数据架构技术选型

OLAP数据库选型对比&#xff1a; AnalyticDB(阿里&#xff09;、Hologres&#xff08;阿里&#xff09;、Doris、StarRocks、ClickHouse、Hbase AnalyticDB技术架构 db是融合数据库、大数据技术于一体的云原生企业级数据仓库服务、支持高吞吐的数据实时增删改查低延时的实时分…

电脑数据安全新利器:自动备份文件的重要性与实用方案

一、数据安全的守护神&#xff1a;自动备份文件的重要性 在数字化时代&#xff0c;电脑中的文件承载着我们的工作成果、个人回忆以及众多重要信息。然而&#xff0c;数据丢失的风险无处不在&#xff0c;无论是硬件故障、软件崩溃&#xff0c;还是恶意软件的攻击&#xff0c;都…

Java基础-IO流

文章目录 1.文件1.基本介绍2.常用的文件操作1.创建文件的相关构造器和方法代码实例结果 2.获取文件相关信息代码实例结果 3.目录的删除和文件删除代码实例 2.IO流原理及分类IO流原理IO流分类 3.FileInputStream1.类图2.代码实例3.结果 4.FileOutputStream1.类图2.案例代码实例 …

(C语言)memcpy函数详解与模拟实现

目录 1. memcpy函数详解 情况一&#xff1a; 情况二&#xff1a; 情况三&#xff1a; 情况四&#xff1a; 情况五&#xff1a; 2. memcpy模拟实现 2.1 重叠情况的讨论&#xff1a; 2.2 memcpy函数超出我们的预期 1. memcpy函数详解 头文件<string.h> 这个函数和…

腾讯云服务器多少钱一个月?5元1个月,这价格没谁了

2024腾讯云服务器多少钱一个月&#xff1f;5元1个月起&#xff0c;腾讯云轻量服务器4核16G12M带宽32元1个月、96元3个月&#xff0c;8核32G22M配置115元一个月、345元3个月&#xff0c;腾讯云轻量应用服务器61元一年折合5元一个月、4核8G12M配置646元15个月、2核4G5M服务器165元…

C++ Qt开发:QUdpSocket网络通信组件

Qt 是一个跨平台C图形界面开发库&#xff0c;利用Qt可以快速开发跨平台窗体应用程序&#xff0c;在Qt中我们可以通过拖拽的方式将不同组件放到指定的位置&#xff0c;实现图形化开发极大的方便了开发效率&#xff0c;本章将重点介绍如何运用QUdpSocket组件实现基于UDP的网络通信…

网站引用图片但它域名被墙了或者它有防盗链,我们想引用但又不能显示,本文附详细的解决方案非常简单!

最好的办法就是直接读取图片文件&#xff0c;用到php中一个常用的函数file_get_contents(图片地址)&#xff0c;意思是读取远程的一张图片&#xff0c;在输出就完事。非常简单&#xff5e;话不多说&#xff0c;直接上代码 <?php header("Content-type: image/jpeg&quo…

“小白也能玩转!ES集群搭建零报错全攻略,轻松上手指南!”

&#x1f310; 全新的“Open开袁”官方网站现已上线&#xff01;https://open-yuan.com&#xff0c;汇聚编程资源、深度技术文章及开源项目地址&#xff0c;助您探索技术新境界。 &#x1f4f1; 关注微信公众号“全栈小袁”&#xff0c;随时掌握最新项目动态和技术分享&#xf…

2024地方门户源码运营版带圈子动态+加即时通讯(PC电脑端+WAP移动端+H5微信端+微信小程序+APP客户端)

2024地方门户源码运营版带圈子动态加即时通讯&#xff08;PC电脑端WAP移动端H5微信端微信小程序APP客户端&#xff09; 源码介绍&#xff1a; 包含5个端 PC电脑端WAP移动端H5微信端微信小程序APP客户端 功能介绍&#xff1a; 包含功能&#xff1a;信息资讯、二手信息、房产…

docker入门(四)—— docker常用命令详解

docker 常用命令 基本命令 # 查看 docker 版本 docker version # 查看一些 docker 的详细信息 docker info 帮助命令&#xff08;–help&#xff09;&#xff0c;linux必须要会看帮助文档 docker --help[rootiZbp15293q8kgzhur7n6kvZ /]# docker --helpUsage: docker [OPTI…

Grok ai——很牛叉的ai工具Grok-1大模型

Grok Grok 是一款仿照《银河系漫游指南》&#xff08;Hitchhikers Guide to the Galaxy&#xff09;设计的人工智能。它可以回答几乎任何问题&#xff0c;更难的是&#xff0c;它甚至可以建议你问什么问题&#xff01; Grok 是一个仿照《银河系漫游指南》设计的人工智能&#x…

数据结构:详解【顺序表】的实现

1. 顺序表的定义 顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构&#xff0c;一般情况下采用数组存储。动态顺序表与数组的本质区别是——根据需要动态的开辟空间大小。 2. 顺序表的功能 动态顺序表的功能一般有如下几个&#xff1a; 初始化顺序表打印顺序…

计算机组成原理-3-系统总线

3. 系统总线 文章目录 3. 系统总线3.1 总线的基本概念3.2 总线的分类3.3 总线特性及性能指标3.4 总线结构3.5 总线控制3.5.1 总线判优控制3.5.2 总线通信控制 本笔记参考哈工大刘宏伟老师的MOOC《计算机组成原理&#xff08;上&#xff09;_哈尔滨工业大学》、《计算机组成原理…

spring suite搭建springboot操作

一、前言 有时候久了没开新项目了&#xff0c;重新开发一个新项目&#xff0c;搭建springboot的过程都有点淡忘了&#xff0c;所有温故知新。 二、搭建步骤 从0开始搭建springboot 1&#xff0e;创建work空间。步骤FileNewJava Working Set。 2.选择Java Working Set。 3.自…

微信小程序接口请求出错:request:fail url not in domain list:xxxxx

一、微信小程序后台和开发者工具配的不一样导致了这个错误 先说结论&#xff1a; 开发者工具配置了https://www.xxx.cn/prod-api/ 微信后台配置了 https://www.xxx.cn 一、最开始 开发者工具配置了https://www.xxx.cn:7500 微信后台配置了 https://www.xxx.cn 报错:reques…