123 lines
3.6 KiB
Markdown
123 lines
3.6 KiB
Markdown
## Android Smb开发笔记
|
||
|
||
### 一、SMB的基本操作
|
||
|
||
Android的SMB开发会用到jcifs这个库。这个库提供了SMB的底层操作功能。
|
||
|
||
根据URI打开一个SMB。
|
||
|
||
```java
|
||
// 指定SMB的路径
|
||
String uri = "smb://administrator:351002@192.168.31.52/H/琅琊榜 全54集 1080P/";
|
||
// 网络的相关操作必须通过新线程的方式启动,否则会触发Android的错误
|
||
new Thread(new Runnable() {
|
||
@Override
|
||
public void run() {
|
||
try {
|
||
// 根据uri打开SmbFile
|
||
SmbFile smbFile = new SmbFile(uri);
|
||
String fileName = smbFile.getName();
|
||
Log.d("Test", fileName);
|
||
// 控制台打印SMB路径下的文件
|
||
try{
|
||
String[] FileList = smbFile.list();
|
||
for (String s : FileList) {
|
||
Log.d("Test", s);
|
||
}
|
||
}catch (SmbException e){
|
||
e.printStackTrace();
|
||
}
|
||
} catch (MalformedURLException e) {
|
||
throw new RuntimeException(e);
|
||
}
|
||
}
|
||
}).start();
|
||
```
|
||
|
||
### 二、SMB转HTTP
|
||
|
||
当我们把SMB的Uri提供给播放器后,播放器会请求GET视频。对于一个完整的视频,Http的请求如下所示。
|
||
|
||
如果我们在解析请求头的时候没有收到请求的范围信息,那么默认就是返回全部的内容。
|
||
|
||
```shell
|
||
GET /smb/192.168.31.52/I/XXX.mp4 HTTP/1.1
|
||
User-Agent: ExoPlayerTime/1.0 (Linux;Android 12) ExoPlayerLib/2.7.1
|
||
Accept-Encoding:identity
|
||
Host: 127.0.0.1:2222
|
||
Connection: Keep-Alive
|
||
```
|
||
|
||
当我们拖动进度条的时候,此时视频不是从0开始播放,所以视频播放器会请求包含Range的信息:
|
||
|
||
```Shell
|
||
GET /smb/192.168.31.52/I/XXX.mp4 HTTP/1.1
|
||
User-Agent: ExoPlayerTime/1.0 (Linux;Android 12) ExoPlayerLib/2.7.1
|
||
Range: bytes=1207598076-
|
||
Accept-Encoding:identity
|
||
Host: 127.0.0.1:2222
|
||
Connection: Keep-Alive
|
||
```
|
||
|
||
上述情况下,如果我们收到包含Range信息的请求时,返回的时候就需要额外指定一些信息。HTTP的返回有如下的规则:
|
||
|
||
```Java
|
||
// 如果用户拖动了进度条,那么HttpRequest就会包含Range信息
|
||
// 1.此时contentLength = end - st, 需要返回Content-Length:头
|
||
"Content-Length: " + contentLength + "\r\n"
|
||
// 2.此时请求的是部分的信息,所以返回的Responce的类型是206,表示部分内容
|
||
HttpStatus.PARTIAL_CONTENT = 206
|
||
```
|
||
|
||
|
||
|
||
```Java
|
||
// 获取文件长度bytes
|
||
long contentLen = file.length();
|
||
// 从文件获得输入流
|
||
InputStream contentIn = file.getInputStream();
|
||
// 检查输入数据流是否正常
|
||
if (contentLen <= 0 || contentIn == null) {
|
||
httpReq.returnBadRequest();
|
||
return;
|
||
}
|
||
// 创建Http返回请求
|
||
HTTPResponse httpRes = new HTTPResponse();
|
||
// 指定视频数据格式
|
||
httpRes.setContentType("video/mpeg4");
|
||
|
||
if(startFrom == 0 && endAt == 0){
|
||
// 请求没有范围信息则返回全部内容,状态OK(200)表示全部内容
|
||
httpRes.setStatusCode(HTTPStatus.OK);
|
||
}else if(startFrom > 0){
|
||
// 如果是包含RangeCotent,则需要返回PARTIAL_CONTENT(206)
|
||
httpRes.setStatusCode(HTTPStatus.PARTIAL_CONTENT);
|
||
httpRes.setContentRange(startFrom,endAt, contentLen);
|
||
}
|
||
// 设置内容总长度
|
||
httpRes.setContentLength(contentLen);
|
||
// 指定内容数据流
|
||
httpRes.setContentInputStream(contentIn);
|
||
// HttpReq提交数据
|
||
httpReq.post(httpRes);
|
||
contentIn.close();
|
||
```
|
||
|
||
HTTP 视频请求
|
||
|
||
```Java
|
||
// 已知信息
|
||
File_length = 2794939639
|
||
File_Range_st = bytes=2792308814
|
||
// 分析
|
||
st = 2792308814
|
||
// 由于文件长度是2794939639,所以换算的索引是0~2794939639-1
|
||
ed = 2794939639 - 1
|
||
content_lenght = ( ed - st + 1 )= File_length - 1 - st + 1
|
||
= ed - st
|
||
|
||
|
||
|
||
```
|
||
|