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
|
|||
|
|
|||
|
|
|||
|
|
|||
|
```
|
|||
|
|