RTSP,Java实现简单的RTSP报文交换

news/2024/5/8 20:29:11/文章来源:https://blog.csdn.net/qq_41709801/article/details/127339210

这里写目录标题

    • RTSP协议是什么
    • 报文实例:
      • 1. OPTIONS
      • 2. DESCRIBE
      • 4. SETUP
      • 5. PLAY
    • Java实现简单的RTSP报文交换

  1. 了解RTSP协议
  2. 使用Java程序编写RTSP客户端 访问 RTSP服务端,实现拉流

RTSP协议是什么

RTSP是一种基于文本的协议,用CRLF(回车换行)作为每一行的结束符,其好处是,在使用过程中可以方便地增加自定义参数,也方便抓包分析。从消息传送方向上来分,RTSP的报文有两类:请求报文和响应报文。请求报文是指从客户端向服务器发送的请求(也有少量从服务器向客户端发送的请求),响应报文是指从服务器到客户端的回应。

RTSP请求报文的常用方法与作用
在这里插入图片描述

一次基本的RTSP交互过程如下,C表示客户端,S表示服务端。
在这里插入图片描述

  1. OPTION请求
    -> 响应
  2. DESCRIBE请求
    -> 响应
    如果响应无权限, 那么需要带上用户名密码
  3. SETUP请求
    -> 响应
  4. PLAY请求
    -> 响应

-> 流数据
-> 流数据
-> 流数据

报文实例:

1. OPTIONS

OPTIONS rtsp://39.170.35.150:1554/h264/ch0/1 RTSP/1.0
CSeq: 2
User-Agent: LibVLC/3.0.16 (LIVE555 Streaming Media v2016.11.28)
RTSP/1.0 200 OK
CSeq: 2
Public: OPTIONS, DESCRIBE, PLAY, PAUSE, SETUP, TEARDOWN, SET_PARAMETER, GET_PARAMETER
Date:  Sat, Mar 05 2022 15:39:55 GMT

2. DESCRIBE

DESCRIBE rtsp://39.170.35.150:1554/h264/ch0/1 RTSP/1.0
CSeq: 3
User-Agent: LibVLC/3.0.16 (LIVE555 Streaming Media v2016.11.28)
Accept: application/sdp
RTSP/1.0 401 Unauthorized
CSeq: 3
WWW-Authenticate: Digest realm="2857be191e08", nonce="5b960b3d4673be2908666321f64d2bff", stale="FALSE"
WWW-Authenticate: Basic realm="2857be191e08"
Date:  Sat, Mar 05 2022 15:39:55 GMT

发现无权, 使用用户名密码进行授权

DESCRIBE rtsp://39.170.35.150:1554/h264/ch0/1 RTSP/1.0
CSeq: 4
Authorization: Digest username="admin", realm="2857be191e08", nonce="5b960b3d4673be2908666321f64d2bff", uri="rtsp://39.170.35.150:1554/h264/ch0/1", response="3cfc28bcf70670c2120acc3b5d1357d3"
User-Agent: LibVLC/3.0.16 (LIVE555 Streaming Media v2016.11.28)
Accept: application/sdp
RTSP/1.0 200 OK
CSeq: 4
Content-Type: application/sdp
Content-Base: rtsp://39.170.35.150:1554/h264/ch0/1/
Content-Length: 569v=0
o=- 1646494795935543 1646494795935543 IN IP4 10.2.144.4
s=Media Presentation
e=NONE
b=AS:5050
t=0 0
a=control:rtsp://39.170.35.150:1554/h264/ch0/1/
m=video 0 RTP/AVP 96
c=IN IP4 0.0.0.0
b=AS:5000
a=recvonly
a=x-dimensions:1920,1080
a=control:rtsp://39.170.35.150:1554/h264/ch0/1/trackID=1
a=rtpmap:96 H264/90000
a=fmtp:96 profile-level-id=420029; packetization-mode=1; sprop-parameter-sets=Z00AKpWoHgCJ+WbgICAgQA==,aO48gA==
a=Media_header:MEDIAINFO=494D4B48010100000400000100000000000000000000000000000000000000000000000000000000;
a=appversion:1.0

4. SETUP

这里得URL后会带上control后的trackID
这里的Transport表示要使用的传输方式, TCP表示使用tcp传输, 也可以使用UDP

SETUP rtsp://39.170.35.150:1554/h264/ch0/1/trackID=1 RTSP/1.0
CSeq: 5
Authorization: Digest username="admin", realm="2857be191e08", nonce="5b960b3d4673be2908666321f64d2bff", uri="rtsp://39.170.35.150:1554/h264/ch0/1/", response="80324f6c8f797633475816843f329b61"
User-Agent: LibVLC/3.0.16 (LIVE555 Streaming Media v2016.11.28)
Transport: RTP/AVP/TCP;unicast;interleaved=0-1
RTSP/1.0 200 OK
CSeq: 5
Session:       2007782907;timeout=60
Transport: RTP/AVP/TCP;unicast;interleaved=0-1;ssrc=762c0e39;mode="play"
Date:  Sat, Mar 05 2022 15:39:55 GMT

5. PLAY

PLAY rtsp://39.170.35.150:1554/h264/ch0/1/ RTSP/1.0
CSeq: 6
Authorization: Digest username="admin", realm="2857be191e08", nonce="5b960b3d4673be2908666321f64d2bff", uri="rtsp://39.170.35.150:1554/h264/ch0/1/", response="f88f707756441a9437f162d68ec5adbb"
User-Agent: LibVLC/3.0.16 (LIVE555 Streaming Media v2016.11.28)
Session: 2007782907
Range: npt=0.000-
RTSP/1.0 200 OK
CSeq: 6
Session:       2007782907
RTP-Info: url=rtsp://39.170.35.150:1554/h264/ch0/1/trackID=1;seq=40895;rtptime=1378373026
Date:  Sat, Mar 05 2022 15:39:56 GMT

后续就会有二进制流进来.

Java实现简单的RTSP报文交换

RTSP端口默认为:1554
通过TCP对目标主机端口发起连接,然后使用RTSP格式的报文进行交换信息即可。

下面是报文拼凑的代码,使用建立TCP连接后安装RTSP规定的通讯顺序发送即可。

	// 定义协议头和通用信息private String transport = "RTP/AVP/TCP;unicast;interleaved=0-1";private static final String VERSION = " RTSP/1.0";private static final String RTSP_OK = "RTSP/1.0 200 OK";  private String address =  "rtsp://admin:shinemo123@39.170.35.150:1554/h264/ch0/1";  // RTSP URI 包含目标ip和账号密码private String sessionid;  // RTSP 是有状态的,通讯成功后需要记录 sessionIdprivate void doTeardown() {  StringBuilder sb = new StringBuilder();  sb.append("TEARDOWN ");  sb.append(this.address);  sb.append("/");  sb.append(VERSION);sb.append(System.lineSeparator());sb.append("Cseq: ");sb.append(seq++);  sb.append(System.lineSeparator());sb.append("User-Agent: RealMedia Player HelixDNAClient/10.0.0.11279 (win32)");sb.append(System.lineSeparator());sb.append("Session: ");  sb.append(sessionid);sb.append(System.lineSeparator());sb.append(System.lineSeparator());send(sb.toString().getBytes());  }private void doPlay() {  StringBuilder sb = new StringBuilder();  sb.append("PLAY ");  sb.append(this.address);  sb.append(VERSION);sb.append(System.lineSeparator());sb.append("Session: ");sb.append(sessionid);  sb.append(System.lineSeparator());sb.append("Cseq: ");sb.append(seq++);sb.append(System.lineSeparator());sb.append("Range: npt=0.000-");sb.append(System.lineSeparator());sb.append(System.lineSeparator());send(sb.toString().getBytes());  }private void doSetup() {  StringBuilder sb = new StringBuilder();  sb.append("SETUP ");  sb.append(this.address);  sb.append("/");  sb.append(trackInfo);  sb.append(VERSION);sb.append(System.lineSeparator());sb.append("Cseq: ");  sb.append(seq++);  sb.append(System.lineSeparator());sb.append("Transport: ");sb.append(transport);sb.append(System.lineSeparator());sb.append(System.lineSeparator());send(sb.toString().getBytes());  }  private void doOption() {  StringBuilder sb = new StringBuilder();  sb.append("OPTIONS ");  sb.append(this.address.substring(0, address.lastIndexOf("/")));  sb.append(VERSION);sb.append(System.lineSeparator());sb.append("Cseq: ");  sb.append(seq++);  sb.append(System.lineSeparator());sb.append(System.lineSeparator());send(sb.toString().getBytes());  }  private void doDescribe() {  StringBuilder sb = new StringBuilder();  sb.append("DESCRIBE ").append(this.address).append(VERSION).append(System.lineSeparator());sb.append("Cseq: ").append(seq++).append(System.lineSeparator());sb.append("Accept: application/sdp").append(System.lineSeparator());sb.append(System.lineSeparator());System.out.println(sb.toString());  send(sb.toString().getBytes());  }  private void doPause() {  StringBuilder sb = new StringBuilder();  sb.append("PAUSE ");  sb.append(this.address);  sb.append("/");  sb.append(VERSION);sb.append(System.lineSeparator());sb.append("Cseq: ");  sb.append(seq++);  sb.append(System.lineSeparator());sb.append("Session: ");  sb.append(sessionid);sb.append(System.lineSeparator());sb.append(System.lineSeparator());send(sb.toString().getBytes());  }

完整的垃圾代码:
这里使用的是netty。

package loki.rtsp;import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;import java.io.IOException;
import java.net.InetSocketAddress;  
import java.nio.ByteBuffer;  
import java.nio.channels.SelectionKey;  
import java.nio.channels.Selector;  
import java.nio.channels.SocketChannel;  
import java.util.Iterator;
import java.util.concurrent.atomic.AtomicBoolean;public class RTSPClient extends Thread implements IEvent {  private static final String VERSION = " RTSP/1.0";private static final String RTSP_OK = "RTSP/1.0 200 OK";  /** *//** 远程地址 */  private final InetSocketAddress remoteAddress;  /** *//** * 本地地址 */  private final InetSocketAddress localAddress;  /** *//** * 连接通道 */  private SocketChannel socketChannel;  /** *//** 发送缓冲区 */  private final ByteBuffer sendBuf;  /** *//** 接收缓冲区 */  private final ByteBuffer receiveBuf;  private static final int BUFFER_SIZE = 8192;  /** *//** 端口选择器 */  private Selector selector;  private String address;  private Status sysStatus;  private String sessionid;  private String transport = "RTP/AVP/TCP;unicast;interleaved=0-1";/** *//** 线程是否结束的标志 */  private AtomicBoolean shutdown;private int seq=2;private boolean isSended;  private String trackInfo;  private enum Status {  init, options, describe, setup, play, pause, teardown  }  public RTSPClient(InetSocketAddress remoteAddress,  InetSocketAddress localAddress, String address) {  this.remoteAddress = remoteAddress;  this.localAddress = localAddress;  this.address = address;  // 初始化缓冲区  sendBuf = ByteBuffer.allocateDirect(BUFFER_SIZE);  receiveBuf = ByteBuffer.allocateDirect(BUFFER_SIZE);  if (selector == null) {  // 创建新的Selector  try {  selector = Selector.open();  } catch (final IOException e) {  e.printStackTrace();  }  }  startup();  sysStatus = Status.init;  shutdown=new AtomicBoolean(false);  isSended=false;  }  public void startup() {  try {  // 打开通道  socketChannel = SocketChannel.open();  // 绑定到本地端口  socketChannel.socket().setSoTimeout(30000);  socketChannel.configureBlocking(false);  socketChannel.socket().bind(localAddress);if (socketChannel.connect(remoteAddress)) {System.out.println("开始建立连接:" + remoteAddress);  }  socketChannel.register(selector, SelectionKey.OP_CONNECT | SelectionKey.OP_READ | SelectionKey.OP_WRITE, this);System.out.println("端口打开成功" + socketChannel.getLocalAddress() + " -> " + socketChannel.getRemoteAddress());} catch (final IOException e1) {  e1.printStackTrace();  }  }  public void send(byte[] out) {  if (out == null || out.length < 1) {  return;  }  synchronized (sendBuf) {  sendBuf.clear();  sendBuf.put(out);  sendBuf.flip();  }  // 发送出去  try {  write();  isSended=true;  } catch (final IOException e) {  e.printStackTrace();  }  }  public void write() throws IOException {  if (isConnected()) {  try {  socketChannel.write(sendBuf);  } catch (final IOException e) {  }  } else {  System.out.println("通道为空或者没有连接上");  }  }  public byte[] recieve() {  if (isConnected()) {  try {  int len = 0;  int readBytes = 0;  synchronized (receiveBuf) {  receiveBuf.clear();  try {  while ((len = socketChannel.read(receiveBuf)) > 0) {  readBytes += len;  }  } finally {  receiveBuf.flip();  }  if (readBytes > 0) {  final byte[] tmp = new byte[readBytes];  receiveBuf.get(tmp);  return tmp;  } else {  System.out.println("接收到数据为空,重新启动连接");  return null;  }  }  } catch (final IOException e) {  System.out.println("接收消息错误:");  }  } else {  System.out.println("端口没有连接");  }  return null;  }  public boolean isConnected() {  return socketChannel != null && socketChannel.isConnected();  }  private void select() {  int n = 0;  try {  if (selector == null) {  return;  }  n = selector.select(1000);  } catch (final Exception e) {  e.printStackTrace();  }  // 如果select返回大于0,处理事件  if (n > 0) {  for (final Iterator<SelectionKey> i = selector.selectedKeys()  .iterator(); i.hasNext();) {  // 得到下一个Key  final SelectionKey sk = i.next();  i.remove();  // 检查其是否还有效  if (!sk.isValid()) {  continue;  }  // 处理事件  final IEvent handler = (IEvent) sk.attachment();  try {  if (sk.isConnectable()) {  handler.connect(sk);  } else if (sk.isReadable()) {  handler.read(sk);  } else {  // System.err.println("Ooops");  }  } catch (final Exception e) {  handler.error(e);  sk.cancel();  }  }  }  }  public void shutdown() {  if (isConnected()) {  try {  socketChannel.close();  System.out.println("端口关闭成功");  } catch (final IOException e) {  System.out.println("端口关闭错误:");  } finally {  socketChannel = null;  }  } else {  System.out.println("通道为空或者没有连接");  }  }  @Override  public void run() {// 启动主循环流程  while (!shutdown.get()) {  try {  if (isConnected()&&(!isSended)) {switch (sysStatus) {case init:doOption();break;case options:doDescribe();break;case describe:doSetup();break;case setup:if(sessionid==null&&sessionid.length()>0){System.out.println("setup还没有正常返回");}else{doPlay();}break;case play:
//                        doPause();
//                        doPlay();System.out.println("PLAY start");break;case pause:doTeardown();break;default:break;}}// do selectselect();  try {Thread.sleep(1000);} catch (final Exception e) {}} catch (final Exception e) {e.printStackTrace();  }  }  shutdown();  }  public void connect(SelectionKey key) throws IOException {  if (isConnected()) {  return;  }  // 完成SocketChannel的连接  socketChannel.finishConnect();  while (!socketChannel.isConnected()) {  try {  Thread.sleep(300);  } catch (final InterruptedException e) {  e.printStackTrace();  }  socketChannel.finishConnect();  }  }  public void error(Exception e) {  e.printStackTrace();  }  public void read(SelectionKey key) throws IOException {  // 接收消息  final byte[] msg = recieve();  if (msg != null) {  handle(msg);  } else {  key.cancel();  }  }  private void handle(byte[] msg) {  String tmp = new String(msg);  System.out.println("返回内容:");  System.out.println(tmp);  if (tmp.startsWith(RTSP_OK)) {  switch (sysStatus) {  case init:  sysStatus = Status.options;  break;  case options:  sysStatus = Status.describe;  String temp =tmp.substring(tmp.indexOf("trackID"));trackInfo = temp.split("\r\n")[0];break;  case describe:  String tempSessionId = tmp.substring(tmp.indexOf("Session: ") + 9);sessionid = tempSessionId.split("\r\n")[0];sessionid = tempSessionId.split(";")[0];sessionid = sessionid.trim();if(sessionid!=null&&sessionid.length()>0){sysStatus = Status.setup;  }  break;  case setup:  sysStatus = Status.play;  break;  case play:  
//                sysStatus = Status.pause;break;  case pause:  sysStatus = Status.teardown;  shutdown.set(true);  break;  case teardown:  sysStatus = Status.init;  break;  default:  break;  }  isSended=false;  } else {  System.out.println("返回错误:" + tmp);  }  }  private void doTeardown() {  StringBuilder sb = new StringBuilder();  sb.append("TEARDOWN ");  sb.append(this.address);  sb.append("/");  sb.append(VERSION);sb.append(System.lineSeparator());sb.append("Cseq: ");sb.append(seq++);  sb.append(System.lineSeparator());sb.append("User-Agent: RealMedia Player HelixDNAClient/10.0.0.11279 (win32)");sb.append(System.lineSeparator());sb.append("Session: ");  sb.append(sessionid);sb.append(System.lineSeparator());sb.append(System.lineSeparator());send(sb.toString().getBytes());  System.out.println(sb.toString());  }private void doPlay() {  StringBuilder sb = new StringBuilder();  sb.append("PLAY ");  sb.append(this.address);  sb.append(VERSION);sb.append(System.lineSeparator());sb.append("Session: ");sb.append(sessionid);  sb.append(System.lineSeparator());sb.append("Cseq: ");sb.append(seq++);sb.append(System.lineSeparator());sb.append("Range: npt=0.000-");sb.append(System.lineSeparator());sb.append(System.lineSeparator());System.out.println(sb.toString());send(sb.toString().getBytes());  }private void doSetup() {  StringBuilder sb = new StringBuilder();  sb.append("SETUP ");  sb.append(this.address);  sb.append("/");  sb.append(trackInfo);  sb.append(VERSION);sb.append(System.lineSeparator());sb.append("Cseq: ");  sb.append(seq++);  sb.append(System.lineSeparator());sb.append("Transport: ");sb.append(transport);sb.append(System.lineSeparator());sb.append(System.lineSeparator());System.out.println(sb.toString());  send(sb.toString().getBytes());  }  private void doOption() {  StringBuilder sb = new StringBuilder();  sb.append("OPTIONS ");  sb.append(this.address.substring(0, address.lastIndexOf("/")));  sb.append(VERSION);sb.append(System.lineSeparator());sb.append("Cseq: ");  sb.append(seq++);  sb.append(System.lineSeparator());sb.append(System.lineSeparator());System.out.println(sb.toString());  send(sb.toString().getBytes());  }  private void doDescribe() {  StringBuilder sb = new StringBuilder();  sb.append("DESCRIBE ").append(this.address).append(VERSION).append(System.lineSeparator());sb.append("Cseq: ").append(seq++).append(System.lineSeparator());sb.append("Accept: application/sdp").append(System.lineSeparator());sb.append(System.lineSeparator());System.out.println(sb.toString());  send(sb.toString().getBytes());  }  private void doPause() {  StringBuilder sb = new StringBuilder();  sb.append("PAUSE ");  sb.append(this.address);  sb.append("/");  sb.append(VERSION);sb.append(System.lineSeparator());sb.append("Cseq: ");  sb.append(seq++);  sb.append(System.lineSeparator());sb.append("Session: ");  sb.append(sessionid);sb.append(System.lineSeparator());sb.append(System.lineSeparator());send(sb.toString().getBytes());  System.out.println(sb.toString());}public static void main(String[] args) {  try {  // RTSPClient(InetSocketAddress remoteAddress,  // InetSocketAddress localAddress, String address)// rtsp://admin:shinemo123@39.170.35.150:1554/h264/ch0/1RTSPClient client = new RTSPClient(  new InetSocketAddress("39.170.35.150", 1554),new InetSocketAddress("10.1.65.48", 0),"rtsp://admin:shinemo123@39.170.35.150:1554/h264/ch0/1");client.start();  } catch (Exception e) {  e.printStackTrace();  }}
}  

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

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

相关文章

PT_概率论基本概念和事件运算性质

文章目录基本概念随机试验样本点SP(ω\omegaω)例样本空间SSΩ\OmegaΩ例随机事件/事件例基本事件随机事件和基本事件的关系出现/发生必然事件Ω\OmegaΩ不可能事件事件之间的关系事件的包含事件相等交事件/积事件互斥事件(互斥/不相容)∅\varnothing∅并事件(和事件)对立事件(…

CIAGAN: Conditional Identity Anonymization Generative Adversarial Networks

CIAGAN: Conditional Identity Anonymization Generative Adversarial Networks CIAGAN&#xff1a;条件身份匿名生成对抗网络 https://github.com/dvl-tum/ciagan ABSTRCT 计算机视觉技术在社会上的使用空前增加&#xff0c;与此同时&#xff0c;人们对数据隐私的关注也日益…

[附源码]Java计算机毕业设计SSM巴州监控中心人事管理系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

北京化工大学数据结构2022/10/13作业 题解

目录 问题 A: 字符串变换 问题 B: 字符串求反 问题 C: 字符串转化为整数&#xff08;附加代码模式&#xff09; 问题 D: 字符串匹配&#xff08;朴素算法&#xff09;-附加代码模式 问题 E: 求解最长首尾公共子串-附加代码模式 问题 F: 算法4-7&#xff1a;KMP算法中的模…

AR 配置并导出IOS开发环境配置

文章目录前言一、导入插件二、设置开发环境三、搭建基础框架四、代码五、导出六、测试总结前言 最近接了公司的一个AR项目&#xff0c;需要用MacBook&#xff0c;所以赶鸭子上架&#xff0c;现学…小本本记下来 我用的unity是2020.3.15f2c1, MacBook是 2020MacBook M1, ipad是…

Azkaban(三):进阶案例-java作业类型案例、条件工作流案例、定时执行案例

目录 Javaprocess作业类型案例 条件工作流案例 运行时参数案例 预定义宏案例 定时执行案例 Javaprocess作业类型案例 Javaprocess类型可以运行一个自定义主类方法&#xff0c;type类型为javaprocess。 1.创建maven工程&#xff0c;创建类名&#xff0c;创建AzkabanCase类…

ISP图像信号处理 | GAMES204-计算成像

图像信号处理 | GAMES204-计算成像Dead Pixel CorrectionBlack Level CompensationAnti-aliasingLens Shading CorrectionNoise Reduction3ASAuto-exposureAuto FocusAWBDemosaic&#xff1a;CFA InterpolationColor CorrectionEdge EnhancementFalse Color SuppressionBrightn…

运动用品品牌排行榜,双十一运动装备选购清单

运动需要我们坚定的决心与毅力&#xff0c;因为它也是一个枯燥而艰辛的过程&#xff0c;需要无数汗水的挥洒与不断重复的坚持。为了让自己能更坚持下去运动&#xff0c;我一般都会选择用外在运动装备来辅助锻炼&#xff0c;不仅仅能提高运动效率&#xff0c;还能让运动更加快乐…

移动端自动化任务-AutoJs Pro v9使用教程(一)

官网 - Auto.js Pro Github代码示例 教程与博客 (autojs.org) 开源版文档 Pro 版 API 旧文档 Pro 版 v9新文档 一、前言 本教程是本人学习 Auto.js Pro V9 的记录&#xff0c;算是个入门教程&#xff0c;通过本文可帮你快速了解 autojs 的大体用法和开发步骤。官方文档也有中文…

【qml】QQuickPaintedItem作为代理在ListView中使用

文章目录1.说明2.程序截图3.TextBalloon 类3.1 TextBalloon.h3.2 TextBalloon.cpp3.3 textballoons.qml3.4 main.cpp1.说明 QQuickPaintedItem类提供了一种在QML场景图中使用QPainter API的方法。 QQuickPaintedItem本身作为Item&#xff0c;也可以在ListView中作为代理使用。…

机器学习笔记 - sklearn决策树(kaggle 实战 Titanic 入门)

Kaggle - Titanic 前言 这是 Kaggle 上非常典型的一道入门题&#xff0c;可以用很多机器学习或者深度学习甚至是一些“奇淫技巧”的方法来解决。因为我是一个初学者&#xff0c;所以我希望在尽可能提高正确率的情况下&#xff0c;用更简单的方法。如果这也能帮助到你&#xf…

数据库作业一

MySQL数据库 MySQL官方提供了两个不同的版本&#xff1a; 1、社区版 &#xff08;MySQL Commimity Server&#xff09;免费&#xff0c;MySQL不提供任何技术支持&#xff08;本文操作选用社区版&#xff09; 2、商业版&#xff08;MySQL Enterprise Edition&#xff09;收费&a…

[Microsoft] 通过Microsoft Spotlight 中国站云技能挑战获取微软免费考试券

这是一篇关于微软Spotlight 推出学习活动的同时&#xff0c;如何获得免费考试券的方法&#xff0c;如果该文章在未来时间已经失效&#xff0c;那么建议你关注一下这个博客&#xff0c;有Azure China Cloud最新的消息会进行更新通知。 文章目录1. 所需准备注册账号2. 参加 Micro…

二十八、Hive集成HBase分析搜索引擎用户行为数据

我们已经知道,HBase数据库没有类SQL的查询方式,因此在实际的业务中操作和计算数据非常不方便。而Hive支持标准的SQL语法(HiveQL),若将Hive与HBase集成,则可以通过HiveQL直接对HBase的表进行读写操作,让HBase支持JOIN、GROUP等SQL查询语法,完成复杂的数据分析。甚至可以…

【电源设计】13开关电源仿真与应用

0.前言 本章主要是大概了解一下开关电源仿真与应用&#xff0c;开关电源仿真设计全过程&#xff1a;包括需求分析/控制/PWM。因为本人并不是专门做电源的&#xff0c;此部分内容仅作了解&#xff0c;并不专门去学习。 文章目录0.前言1.项目需求2.方案介绍2.1DCDC级&#xff08…

互联网重提内容为王?学Netflix(奈飞)做好内容营销

Netflix 成立于1997年&#xff0c;不久便一跃成为最受瞩目的流媒体服务网站。它为什么能在短短时间内获得如此巨大的成功呢&#xff1f;答案就在于它使用的超凡 内容营销策略 和方法 —— 数据驱动 、优化内容、以流量转化为目标。 内容为王众人皆知&#xff0c;内容营销是品牌…

【计算机毕业设计】java ssm高校计算机网络考试系统(源码+论文)

提供了一些今年最新计算机毕业设计源代码、文档及帮助指导&#xff0c;公众号&#xff1a;一点毕设&#xff0c;领取更多毕设资料。 随着计算机以及网络在教学领域的高速发展&#xff0c;为了加快数字化校园的进程&#xff0c;更好的实现现代化的教育改革&#xff0c;针对于当下…

手动制作满足SARscape要求的_dem数据

手动制作满足SARscape要求的_dem数据问题描述1 下载研究区的原始DEM数据&#xff0c;在envi中镶嵌裁剪&#xff0c;得到.dat格式的数据&#xff0c;然后用envi中的Original ENVI工具把.dat转成_dem1.1 下载研究区的原始DEM数据1.2 将.tif数据转成envi格式的.dat2. 能不能直接将…

WordPress开发中常用代码(必备)

很多人在WordPress开发中常用代码&#xff0c;WordPress 相比其它网站程序&#xff0c;最突出的优势&#xff1a;主题模板多&#xff0c;插件多&#xff0c;相关技术文章多&#xff0c;只要你想到的功能&#xff0c;都可以通过插件或者代码实现。现在分享下WordPress常用代码&a…

组合关系比依赖关系耦合性更强

首先说明&#xff0c;在这里我把“关联”、“组合”、“聚合”关系都统一当做“组合”关系来说的&#xff0c;但实际上聚合&#xff08;has-a&#xff09;是关联的一种&#xff0c;组合&#xff08;cntains-a&#xff09;也是关联的一种。如果想要知道三者之间的区别&#xff0…