web 语音通话 jssip
先把封装好的地址安上(非本人封装):webrtc-webphone: 基于JsSIP开发的webrtc软电话
jssip中文文档:jssip中文开发文档(完整版) - 简书
jssip使用文档:(我没有运行过,但是他写的很清楚,反正比我好)jssip+webrtc+freeswitch实现电话网页及遇到的488状态码问题_freeswitch 488_weixin_39715323的博客-CSDN博客
正常使用由于web限制应该在https上使用,但是http也不是不可以,我放到下一篇文章了,这就说怎么使用
我这用的是webrtc+jssip
webrtc-webphone已经实现了我的需求,所以我没有使用原生jssip
特主要实现的功能有:注册,拨叫,接听,保持,恢复
我的项目中需要静音(指我不能说话,通话人可以讲话)
所以我将hold(保持)和unhold(恢复)改成了mute和unmute

下面是完整代码和方法说明:
1.init(注册citbar)config中需要使用ip地址、端口号、extNo拨号人、extPwd密码
2.handleAgentBarBtnClick(通话状态更改)
makecall(拨号)
hangup(挂断)
hold(静音)
unhold(取消静音)
3.onbeforeunload (通话中刷新对讲群组中没有退出,导致群组中有多个同一个人)
4.beforeDestroy(切换页面后没有退出群组,刷新不走这个方法)
注意:
1.不要重复拨号,状态卡住后就能同一个设备对话了bug
2.如果想切换页面还能通话就不要beforeDestroy,但是在其他页面在回来时会导致状态不一致,而且容易出现卡状态,所以我将通话操作放在index最顶层里面
<template><div class="top"><div style="padding: 0 30px;"><div style="display: flex;padding-top: 3px;"><!-- 设备树插件 --><organizationTree ref="organizationTree"></organizationTree><div style="width:77vw;height:80vh; margin-top: 5px;"><div class="photo_date" style="position:relative"><div style="display:flex;min-width:30%"><div class="text_type photo_deviceName " v-show="groupName" style="text-align: center;">{{groupName}}</div><div class="text_type" :class="meetingStatus==2?' meetingName1':' meetingName'"style="width: 125px;text-align: center;">{{meetingStatus==2?meetingName:meetingName1}}</div></div><div style="position: absolute;right: 0;" v-show="createBy==userName"><div v-show="meetingStatus==2" class="btn_type photo_meeting_btn" @click="meetingAll"style="position:absolute; right:135px;width: 140px;height: 35px;line-height: 35px;">邀请全部成员</div><div class="bg_btn_type photo_meeting_btn" @click="meeting"style="position:absolute; right:0;width: 125px;height: 35px;line-height: 35px;">{{meetingStatus==1?'开始会议':'结束会议'}}</div></div></div><div class=""><div class="deviceList_title"><div class="deviceList_title_text" style="width:15%">名称</div><div class="deviceList_title_text" style="width:15%">imei</div><div class="deviceList_title_text" style="width:15%">类型</div><div class="deviceList_title_text" style="width:15%">状态</div><div class="deviceList_title_text" style="width:15%">会议状态</div><div class="deviceList_title_text" style="width:24%">操作</div><!-- <div class="deviceList_title_text">操作</div> --></div><div v-show="deviceList" class="deviceList"><div class="deviceList_list" :class="item.id==itemId?'deviceList_list1':''"v-for="(item,index) in deviceList" :key="item.id" @mouseover="mouseover(item.id)"@mouseleave="mouseout()"><!-- <el-tooltip :content="item.name" placement="bottom" effect="light"> --><div class="deviceList_title_text" style="width:15%">{{item.devName}}</div><!-- </el-tooltip> --><div class="deviceList_title_text" style="width:15%">{{item.imei}}</div><div class="deviceList_title_text" style="width:15%">{{item.devTypeName}}</div><div class="deviceList_title_text" style="width:15%">{{dictionary(item.devStatus,'dev_status',item.imei)}}</div><div class="deviceList_title_text" style="width:15%">{{dictionary(item.memberStatus,'meeting_member_status')}}</div><div style="width:24%;"><div v-if="meetingStatus==2"><div v-if="item.imei == createBy&&item.imei == userName"><div v-if="item.devStatus==3||item.devStatus==4||item.devStatus==5||item.devStatus==1"><div style="width:100%;justify-content: center;" class="deviceList_operate"><div class="deviceList_title_text1" @click="speak('request')"v-if="item.memberStatus!=3&&item.memberStatus!=1&&item.memberStatus!=4&&item.memberStatus!=5"><div>开始发言</div></div><div class="deviceList_title_text1" @click="speak('request')" v-if="item.memberStatus==3"><div>结束发言</div></div><div class="deviceList_title_text1" @click="outMeeting" v-if="item.memberStatus==2">离开会议</div><div class="deviceList_title_text1" @click="inMeeting" v-if="item.memberStatus==1">进入会议</div></div></div></div><div v-if="item.imei != createBy"><div v-if="item.devStatus==3||item.devStatus==4||item.devStatus==5||item.devStatus==1"><div style="width:100%;justify-content: center;" class="deviceList_operate"v-show="createBy==userName&&isInOrOutMeeting&&deviceList[0].memberStatus==2"><div class="deviceList_title_text1" @click="speak('call',item.imei,'start')"v-if="item.memberStatus!=3&&item.memberStatus!=1&&item.memberStatus!=4&&item.memberStatus!=5"><div>点名发言</div></div><div class="deviceList_title_text1" @click="speak('call',item.imei,'end')"v-if="item.memberStatus==3"><div>结束发言</div></div><div class="deviceList_title_text1" @click="inOrOut('out',item.imei)"v-if="item.memberStatus==2">请离会议</div><div class="deviceList_title_text1" @click="inOrOut('in',item.imei)"v-if="item.memberStatus==1">拉入会议</div></div></div></div></div></div></div></div></div></div></div></div></div></template>
<script>import Header from "../home/header/index";import Footer from "../home/footer/index";import webSocketClass from "@/utils/webSocket";import { postWarnStatus } from "@/api/AlarmRecord";import organizationTree from "./deviceTree/organizationTree"import { devicetree } from "@/api/system/deviceTree";import { timestampToTime } from "../../../utils/time.js"import { addGroup, delGroup, getGroup, listGroup, updateGroup, updateMeetingStatus, selectDeviceGroupDetailList, deviceRequestTalking, inOrOutMeeting } from "@/api/system/group";import { listData } from "@/api/system/dict/data";import Ctibar from './AgentBar/ctibar.js';var audio = document.getElementById('audio');var constraints = {audio: true,video: true,mandatory: {maxWidth: 640,maxHeight: 360}};URL = window.URL || window.webkitURL;var eventHandlers = {'progress': function (e) {console.log('call is in progress');},'failed': function (e) {console.log('call failed: ', e);},'ended': function (e) {console.log('call ended : ', e);},'confirmed': function (e) {console.log('call confirmed');}};export default {dicts: ["warn_type"],components: {Header,Footer,organizationTree},data() {return {// 以下群组isGroup: false,createBy: '',isInOrOutMeeting: false,isSpeak: false,itemId: '',meetingStatus: '',groupDetail: {},isMike: false,deviceList: null,meetingName1: "会议未开始",meetingName: "会议中",groupName: "",dataList: null,userId: JSON.parse(sessionStorage.getItem("userInfo")).userId,userName: JSON.parse(sessionStorage.getItem("userInfo")).userName,// 查询参数queryParams: {pageNum: 1,pageSize: 10,deptId: null,planName: null,status: null,},total: 0,deviceTreeList: [],title: "",num: 1,groupId: '',dictionaryList: [],websocket: null,//初始化SDK所需要的配置config: {host: '39.152.2.103',port: '5066',proto: false,extNo: '',extPwd: '20181231',autoRegister: true,debug: true,//stunServer: 'stun.1.google.com', 可自行修改使用stun服务器地址stateEventListener: this.stateEventListener},//坐席分机号agentNo: '',//客户号码customerNo: '',//拨号弹窗showDial: false,//转接弹窗showTransferDial: false,//转接号码transNum: '',numList: ['1', '2', '3', '4', '5', '6', '7', '8', '9', '*', '0', '#',],agentStatus: 'DISCONNECTED',statusMap: {CONNECTED: '已连接',DISCONNECTED: '网络断开',REGISTERED: '已注册',UNREGISTERED: '未注册',REGISTER_FAILED: '注册失败',IN_CALL: '通话中',INCOMING_CALL: '来电振铃',OUTGOING_CALL: '外呼振铃',HOLD: '保持中',CALL_END: '通话结束'},timer: null,timerString: '00:00:00',outNum: '',isHold: true};},computed: {classObject() {const bool1 = this.alarmArr.length > 1;const bool2 = this.alarmArr.length === 1;return {tanchuangbox: true,"tanchuangbox-height-multi": bool1,"tanchuangbox-height-single": bool2,};},},mounted() {this.init()},methods: {// 以下群组inMeeting() {this.loadingFun()var body = {devImei: this.userName,flag: 'in',groupId: this.groupId,}inOrOutMeeting(body).then(response => {if (response.data.success) {} else {this.$modal.msgError(response.data.message);}this.loading.close();},error => {this.loading.close();});},outMeeting() {this.loadingFun()var body = {devImei: this.userName,flag: 'out',groupId: this.groupId,}inOrOutMeeting(body).then(response => {if (response.data.message == '已离开!') {} else {this.$modal.msgError(response.data.message);}this.loading.close();},error => {this.loading.close();});},inOrOut(flag, devImei) {this.loadingFun()var body = {devImei: devImei,flag: flag,groupId: this.groupId,}inOrOutMeeting(body).then(response => {console.log("123123123", response)if (response.data.success) {this.$modal.msgSuccess(response.data.message);} else {this.$modal.msgError(response.data.message);}this.loading.close();},error => {this.loading.close();});},loadingFun() {this.loading = this.$loading({lock: true,text: 'Loading',spinner: 'el-icon-loading',background: 'rgba(0, 0, 0, 0.7)'});},speak(type, devImei, flag) {this.loadingFun()var flagg = ''if (type == 'request') {flagg = !this.isSpeak ? 'start' : 'end'devImei = this.userName} else {flagg = flag}var body = {devImei: devImei,flag: flagg,groupId: this.groupId,type: type,}deviceRequestTalking(body).then(response => {if (response.data.success) {if (type == 'request') {}this.$modal.msgSuccess(response.data.message);//恢复发言} else {this.$modal.msgError(response.data.message);this.hold()}this.loading.close();},error => {this.loading.close();});},// 1、进入元素mouseover(index) {this.itemId = index},// 4、离开元素mouseout() {this.itemId = ''},ws() {console.log('{"groupId":' + this.groupId + '}')this.websocket.webSocketSendMsg('{"groupId":' + this.groupId + '}')},devStatus(devStatus) {for (const i in this.deviceList) {if (this.deviceList[i].devStatus == devStatus) {this.deviceList[i].devStatus = devStatus}}},dictionary(e, type, imei) {for (const i in this.dictionaryList) {if (this.createBy == imei && e == 4) {return '在线'}if (this.dictionaryList[i].dictValue == e && this.dictionaryList[i].dictType == type) {return this.dictionaryList[i].dictLabel}}},handleAdd() {// this.reset();// this.open = true;this.title = "添加群组";},tableRowClassName({ row, rowIndex }) {return 'photo';},rowClass({ row, rowIndex }) {return 'text-align: center;background-color: #1A1D30;color: #fff'},meetingAll() {var meetingStatusAll = 2var params = {groupId: this.groupId,meetingStatus: meetingStatusAll}updateMeetingStatus(params).then(response => {if (response.code == 200) {this.$modal.msgSuccess(response.msg);} else {this.$modal.msgError(response.msg);}});},meeting() {this.loadingFun()if (this.deviceList != null) {console.log('meetingStatusmeetingStatus', this.meetingStatus)var params = {groupId: this.groupId,meetingStatus: this.meetingStatus == 1 ? 2 : 1}updateMeetingStatus(params).then(response => {setTimeout(() => {if (response.code == 200) {if (this.meetingStatus == 1) {if (sessionStorage.getItem('groupId') == this.groupId) {this.handleAgentBarBtnClick('hangup')sessionStorage.setItem('groupId', '')}this.isInOrOutMeeting = falsethis.isHold = truethis.loading.close()}}}, 5000);});}},//孙组件向父组件传递数据wsMeetingStatus(isInterface) {console.log('isMeeting状态:', isInterface)this.meetingStatus = isInterface},groupDeviceItemClick(item) {// this.handleAgentBarBtnClick('hangup')this.isSpeak = falsethis.deviceList = []this.groupId = item.idthis.meetingStatus = item.meetingStatusthis.groupName = item.groupNamethis.createBy = item.createBythis.item = itemvar params = { groupInfoId: item.id, pageNum: 0, pageSize: 0, }selectDeviceGroupDetailList(params).then(response => {this.deviceList = response.rowsthis.total = this.deviceList.lengththis.ws()if (this.deviceList[0].memberStatus == 3 &&this.deviceList[0].imei == this.userName) {this.isSpeak = true;}if (this.deviceList[0].memberStatus == 2 &&this.deviceList[0].imei == this.userName) {if (sessionStorage.getItem("groupId") == this.groupId) {this.isInOrOutMeeting = truereturn}if (sessionStorage.getItem("groupId")) {} else {this.call()}}});},onClickDialOutside(event) {console.log(event)this.showDial = false},onClickTransDialOutside(event) {this.showTransferDial = false;},handleAgentBarBtnClick(name) {console.log(name + '当前')if (name === 'login') {this.login();} else if (name === 'logout') {this.logout();} else if (name === 'answer') {this.answer();} else if (name === 'hangup') {this.hangup();} else if (name === 'makecall') {this.makeCall('9*' + this.groupId)} else if (name === 'hold') {this.hold();} else if (name === 'unhold') {this.unhold();} else if (name === 'transfer') {this.transfer(this.transNum)}},login() {this.init()Ctibar.register()},logout() {Ctibar.unregister()},makeCall(phone) {if (phone === "" || phone === undefined) {console.error('无效的号码,请重新输入!');return}Ctibar.makecall(phone);},hold() {Ctibar.hold();},unhold() {Ctibar.unhold();},answer() {Ctibar.answer();},hangup() {Ctibar.hangup();},transfer(phone) {console.info("触发转接", phone)Ctibar.transfer(phone);},//外呼拨号盘handleDialBtnClick(val) {this.outNum += val;this.$refs.outNumInput.focus();},//转接拨号盘handleTransDialBtnClick(val) {this.transNum += val;this.$refs.transNumInput.focus();},//参数为时间差秒数,返回这两个时间差并格式化computeTimeDiff(diff) {diff = Math.round(diff / 1000);let hour = Math.floor(diff / 3600).toString().padStart(2, '0');let min = Math.floor((diff - hour * 3600) / 60).toString().padStart(2, '0');let sec = (diff % 60).toString().padStart(2, '0');return hour + ':' + min + ':' + sec;},//重置时间restoreTime(origin) {clearInterval(this.timer);this.timerString = '00:00:00';this.timer = setInterval(() => {this.timerString = this.computeTimeDiff(new Date().getTime() - origin);}, 1000);},//状态变更回调stateEventListener(event, data) {//debug使用console.log('当前event为: ' + event + ', 当前data为: ' + JSON.stringify(data))this.agentStatus = eventlet origin = new Date().getTime();switch (event) {case "CONNECTED":this.agentNo = data.localAgentthis.restoreTime(origin);break;case "DISCONNECTED":this.restoreTime(origin);break;case "UNREGISTERED":this.restoreTime(origin);break;case "OUTGOING_CALL":this.customerNo = data.otherLegNumber;this.restoreTime(origin);break;case "INCOMING_CALL":this.customerNo = data.otherLegNumber;//播放来电振铃音this.playRingMedia();this.restoreTime(origin);break;case "IN_CALL":this.stopPlayRingMedia();this.restoreTime(origin);// this.timer = setInterval(() => {// }, 1000);console.log('当前是否hold', this.isHold)if (this.isHold) {setTimeout(() => {this.handleAgentBarBtnClick('hold')this.isHold = false// 方法区}, 500);}break;case "CALL_END":this.stopPlayRingMedia();//挂机铃声this.playHangupMedia()this.restoreTime(origin);break;default:}},//播放挂机铃声playHangupMedia() {const _this = this;var hangupAudio = document.getElementById("hangupMediaAudioId")if (!hangupAudio) {hangupAudio = document.createElement('audio');hangupAudio.id = 'hangupMediaAudioId';hangupAudio.hidden = true;hangupAudio.src = 'wav/hangup.wav'document.body.appendChild(hangupAudio);}hangupAudio.play();},//播放来电振铃playRingMedia() {const _this = this;_this.stopPlayRingMedia();var ringAudio = document.getElementById("ringMediaAudioId")if (!ringAudio) {ringAudio = document.createElement('audio');ringAudio.id = 'ringMediaAudioId';ringAudio.hidden = true;ringAudio.src = 'wav/ring.wav';ringAudio.loop = 'loop';document.body.appendChild(ringAudio);}ringAudio.play();},//停止播放来电振铃stopPlayRingMedia() {const _this = this;var ringAudio = document.getElementById("ringMediaAudioId");if (ringAudio) {document.body.removeChild(ringAudio);}},//初始化方法init() {this.config.extNo = this.userNameif (sessionStorage.getItem("freeSwitchWs") != null) {this.config.host = sessionStorage.getItem("freeSwitchWs").split(":")[0]this.config.port = sessionStorage.getItem("freeSwitchWs").split(":")[1]}Ctibar.initSDK(this.config)let url = `/ws/` + this.userId + '/group/device/push';this.websocket = new webSocketClass(url)this.websocket.getWebSocketMsg(evt => {// 客户端接收服务端返回的数据var data = JSON.parse(evt.data);console.log("websocket返回的数据123:", data);switch (data.flag) {case "group"://会议状态this.$refs.organizationTree.setGroupList(data, this.groupId)console.log("websocket返回的数据123:", data);breakcase "memberStatus"://成员状态for (const i in this.deviceList) {console.log('123123132', data.member);if (this.deviceList[i].imei == data.member) {this.deviceList[i].devStatus = data.memberStatus;}}breakcase "memberMeetingStatus"://成员会议状态for (const i in this.deviceList) {if (this.deviceList[i].imei == data.member) {this.deviceList[i].memberStatus = data.memberMeetingStatus;}}if (this.groupId == data.groupId && this.userName == data.member && this.createBy == data.member) {if (data.memberMeetingStatus == 3) {this.isSpeak = true;this.unhold()console.log('数据this.isInOrOutMeeting1111', this.isSpeak)} else {this.isSpeak = false;this.hold()}}if (data.memberMeetingStatus == 4) {this.loading.close()}if (!this.isInOrOutMeeting && this.groupId == data.groupId && this.userName == data.member && this.createBy == data.member && data.memberMeetingStatus == 2) {this.hold()if (sessionStorage.getItem("groupId") &&sessionStorage.getItem("groupId") !== this.groupId) {} else {console.log('this.isInOrOutMeeting1111', data.memberMeetingStatus)this.call()}}if (this.createBy == data.member && data.memberMeetingStatus == 1 && this.userName == data.member) {this.handleAgentBarBtnClick('hangup')sessionStorage.setItem("groupId", '')this.isInOrOutMeeting = falsethis.isSpeak = falsethis.isHold = true}break}})},setGroup(group) {this.isGroup = group},call() {this.handleAgentBarBtnClick('makecall')sessionStorage.setItem("groupId", this.groupId)this.isInOrOutMeeting = trueif (this.deviceList[0].imei != this.createBy) {// this.groupDeviceItemClick(this.item)}var that = thiswindow.onbeforeunload = (e) => {console.log('this.isInOrOutMeeting', that.isInOrOutMeeting)if (that.isInOrOutMeeting) {that.handleAgentBarBtnClick('hangup')sessionStorage.setItem("groupId", '')that.websocket.closeSocket()window.onbeforeunload = null}}this.loading.close()this.isInOrOutMeeting = truethis.isHold = true}},beforeDestroy() { //进行监听销毁console.log('1231232131232132131,', this.isInOrOutMeeting)if (this.isInOrOutMeeting) {this.handleAgentBarBtnClick('hangup')sessionStorage.setItem("groupId", '')this.websocket.closeSocket()window.onbeforeunload = null}},};
</script>
相关文章:
web 语音通话 jssip
先把封装好的地址安上(非本人封装):webrtc-webphone: 基于JsSIP开发的webrtc软电话 jssip中文文档:jssip中文开发文档(完整版) - 简书 jssip使用文档:(我没有运行过,但…...
随风摇曳的她——美蕨(matlab实现)
目录 1 随风摇曳的她 2 摇曳带来的哲思 3 Matlab代码实现 1 随风摇曳的她 梦幻的场景、浪漫的气息,带上心爱的人,拥抱在这片花海之下,便有了电影男女主角的氛围感; 就算阅尽了世间风貌,也抵不上和她在一起时锦短情长&a…...
时序数据库的流计算支持
一、时序数据及其特点 时序数据(Time Series Data)是基于相对稳定频率持续产生的一系列指标监测数据,比如一年内的道琼斯指数、一天内不同时间点的测量气温等。时序数据有以下几个特点: 历史数据的不变性数据的有效性数据的时效…...
springboot启动流程 (3) 自动装配
在SpringBoot中,EnableAutoConfiguration注解用于开启自动装配功能。 本文将详细分析该注解的工作流程。 EnableAutoConfiguration注解 启用SpringBoot自动装配功能,尝试猜测和配置可能需要的组件Bean。 自动装配类通常是根据类路径和定义的Bean来应…...
ansible-roles模块
roles用于层次性,结构化地组织playbook,roles能够根据层次型结构自动装载变量文件,tasks以及handlers等。要使用只要载playbook中使用include指令引入即可。 (roles就是通过分别将变量,文件,任务ÿ…...
聊聊我做 NeRF-3D重建性能优化经历
我们新推出大淘宝技术年度特刊《长期主义,往往从一些小事开始——工程师成长总结专题》,专题收录多位工程师真诚的心路历程与经验思考,覆盖终端、服务端、数据算法、技术质量等7大技术领域,欢迎一起沟通交流。 本文为此系列第四篇…...
未磁科技全球首台64通道无液氦心磁图仪及首个培训基地落户北京安贞医院
【全球首台64通道无液氦心磁图仪在北京安贞医院举行开机仪式】 近日,在北京安贞医院举行了未磁科技全球首台64通道无液氦心磁图仪开机仪式,中国医学装备协会赵自林理事长、北京安贞医院纪智礼书记、张宏家院长、宋现涛教授,以及未磁科技蔡宾…...
SpringBoot 如何使用 ApplicationEventPublisher 发布事件
SpringBoot 如何使用 ApplicationEventPublisher 发布事件 在 SpringBoot 应用程序中,我们可以使用 ApplicationEventPublisher 接口来发布事件。事件可以是任何对象,当该对象被发布时,所有监听该事件的监听器都会收到通知。 下面是一个简单…...
【深度学习】2-3 神经网络-输出层设计
前馈神经网络(Feedforward Neural Network),之前介绍的单层感知机、多层感知机等都属于前馈神经网络,它之所以称为前馈(Feedforward),或许与其信息往前流有关:数据从输入开始,流过中间计算过程,最后达到输出…...
Python网络爬虫开发:使用PyQt5和WebKit构建可定制的爬虫
部分数据来源:ChatGPT 引言 在网络爬虫开发中,使用Web浏览器模拟用户行为是非常重要的。而在这个过程中,基于 WebKit 的框架可以提供比其他技术更紧密的浏览器集成,以及更高效、更多样化的页面交互方式。 在本文中,我们将通过一个使用基于 WebKit 的爬虫示例,并与类似…...
Laya3.0游戏框架搭建流程(随时更新)
近两年AI绘图技术有了长足发展,准备把以前玩过的游戏类型重制下,也算是圆了一个情怀梦。 鉴于unity商用水印和启动时间的原因,我决定使用Laya来开发。目前laya已经更新到了3.0以上版本,就用目前比较新的版本。 之后关于开发中遇到…...
.net 软件开发模式——三层架构
三层架构是一种常用的软件开发架构模式,它将应用程序分为三个层次:表示层、业务逻辑层和数据访问层。每一层都有明确的职责和功能,分别负责用户交互、业务处理和数据存储等任务。这种架构模式的优点包括易于维护和扩展、更好的组织结构和代码…...
SpringBoot如何优雅的实现重试功能
文章目录 使用背景spring-retry介绍快速使用加入依赖开启Retry使用参数 使用背景 在有些特定场景,如和第三方对接。 我们调用接口时需要支持重试功能,第一次调用没成功,我们需要等待x秒后再次调用。 通常会设置重试次数,避免业务…...
【CEEMDAN-VMD-GRU】完备集合经验模态分解-变分模态分解-门控循环单元预测研究(Python代码实现)
💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…...
OpenText Exceed TurboX(ETX)—— 适用于 UNIX、Linux 和 Windows 的远程桌面解决方案
由于新技术的采用,以及商业全球化和全球协作的现实,几乎所有企业(无论其规模和所处行业)的员工的工作方式、时间和地点都发生了重大变化。业务领导者正在推动其 IT 部门提出解决方案,以帮助其远程员工提高工作效率&…...
【人工智能】— 逻辑回归分类、对数几率、决策边界、似然估计、梯度下降
【人工智能】— 逻辑回归分类、对数几率、决策边界、似然估计、梯度下降 逻辑回归分类Logistic Regression ClassificationLogistic Regression: Log OddsLogistic Regression: Decision BoundaryLikelihood under the Logistic ModelTraining the Logistic ModelGradient Desc…...
k8s pod “cpu和内存“ 资源限制
转载用于收藏学习:原文 文章目录 Pod资源限制requests:limits:docker run命令和 CPU 限制相关的所有选项如下: Pod资源限制 为了保证充分利用集群资源,且确保重要容器在运行周期内能够分配到足够的资源稳定运行&#x…...
datagrip 连接 phoenix
jar替换完后尽量重启datagrip. 然后重新连接即可. 不重启貌似报错... 效果:...
黑客入侵的常法
1.无论什么站,无论什么语言,我要渗透,第一件事就是扫目录,最好一下扫出个上传点,直接上传 shell ,诸位不要笑,有时候你花很久搞一个站,最后发现有个现成的上传点,而且很容…...
VB报警管理系统设计(源代码+系统)
可定时显示报警系统是一个能够定时并及时报警,提醒人们安全有效地按计划完成任务的系统。本论文从软件工程的角度,对可定时显示报警系统做了全面的需求分析,简要说明了该系统的构思、特点及开发环境;阐述了系统的主要功能,论述了它的设计与实现,并且叙述了系统的测试与评…...
Linux应用开发之网络套接字编程(实例篇)
服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …...
iOS 26 携众系统重磅更新,但“苹果智能”仍与国行无缘
美国西海岸的夏天,再次被苹果点燃。一年一度的全球开发者大会 WWDC25 如期而至,这不仅是开发者的盛宴,更是全球数亿苹果用户翘首以盼的科技春晚。今年,苹果依旧为我们带来了全家桶式的系统更新,包括 iOS 26、iPadOS 26…...
IGP(Interior Gateway Protocol,内部网关协议)
IGP(Interior Gateway Protocol,内部网关协议) 是一种用于在一个自治系统(AS)内部传递路由信息的路由协议,主要用于在一个组织或机构的内部网络中决定数据包的最佳路径。与用于自治系统之间通信的 EGP&…...
解锁数据库简洁之道:FastAPI与SQLModel实战指南
在构建现代Web应用程序时,与数据库的交互无疑是核心环节。虽然传统的数据库操作方式(如直接编写SQL语句与psycopg2交互)赋予了我们精细的控制权,但在面对日益复杂的业务逻辑和快速迭代的需求时,这种方式的开发效率和可…...
Cinnamon修改面板小工具图标
Cinnamon开始菜单-CSDN博客 设置模块都是做好的,比GNOME简单得多! 在 applet.js 里增加 const Settings imports.ui.settings;this.settings new Settings.AppletSettings(this, HTYMenusonichy, instance_id); this.settings.bind(menu-icon, menu…...
springboot整合VUE之在线教育管理系统简介
可以学习到的技能 学会常用技术栈的使用 独立开发项目 学会前端的开发流程 学会后端的开发流程 学会数据库的设计 学会前后端接口调用方式 学会多模块之间的关联 学会数据的处理 适用人群 在校学生,小白用户,想学习知识的 有点基础,想要通过项…...
使用Spring AI和MCP协议构建图片搜索服务
目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式(本地调用) SSE模式(远程调用) 4. 注册工具提…...
AirSim/Cosys-AirSim 游戏开发(四)外部固定位置监控相机
这个博客介绍了如何通过 settings.json 文件添加一个无人机外的 固定位置监控相机,因为在使用过程中发现 Airsim 对外部监控相机的描述模糊,而 Cosys-Airsim 在官方文档中没有提供外部监控相机设置,最后在源码示例中找到了,所以感…...
AI语音助手的Python实现
引言 语音助手(如小爱同学、Siri)通过语音识别、自然语言处理(NLP)和语音合成技术,为用户提供直观、高效的交互体验。随着人工智能的普及,Python开发者可以利用开源库和AI模型,快速构建自定义语音助手。本文由浅入深,详细介绍如何使用Python开发AI语音助手,涵盖基础功…...
解析两阶段提交与三阶段提交的核心差异及MySQL实现方案
引言 在分布式系统的事务处理中,如何保障跨节点数据操作的一致性始终是核心挑战。经典的两阶段提交协议(2PC)通过准备阶段与提交阶段的协调机制,以同步决策模式确保事务原子性。其改进版本三阶段提交协议(3PC…...
