字节流的博客

aria2 及 DLNA 服务 Docker 部署 -(3)

tv

前两篇谈到了 aria2 服务,Web 页面,以及从百度云下载和 BT 种子 tracker list 的更新。这次我们说说下载文件的多终端共享。

Samba

说到文件共享,最先想到的 Samba。Samba 是一款实现 SMB(Server Messages Block)协议的免费软件,用来为局域网的不同操作系统的计算机提供文件及打印机等资源的共享服务。我开始就是用 Samba 用来共享下载下来的视频,并且简单的设置了目录和用户权限,用户密码等基本配置。使用了 joebiellik/samba-server 这个镜像,很容易就实现了局域网文件共享。

docker-compose.yml 文件内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
version: '3.1'
services:
samba:
image: joebiellik/samba-server:latest
container_name: samba
restart: always
network_mode: 'host'
volumes:
- ./data:/mnt
- ./conf.d/smb.conf:/config/smb.conf
- /etc/localtime:/etc/localtime:ro
environment:
- USERNAME=samba
- PASSWORD=samba
logging:
driver: "json-file"
options:
max-size: "1m"

局域网内的手机,电视和 iPad 很容易就搜到了这个服务,并且浏览和播放视频资源。用了一段时间,感觉还可以,平常都播放一些几百兆不是很大的美剧,没觉得什么问题。但是后来下载一些几个 G 的高清电影的时候,比较吃力了,基本上加载不动,感觉可能就需要流服务了。🤗

MiniDLNA

MiniDLNA 是一个服务端软件,旨在为兼容 DLNA/UPnP 的客户端提供媒体文件(音乐、图片和视频)。MiniDLNA 功能简单,轻量级,没有管理页面来配置和管理,只能用配置文件来配置。并且不能像 Samba 一样配置用户名和密码等,设置访问权限。但是对我们来说,已经足够了。

MiniDLNA 使用的是 vladgh/minidlna 这个镜像,配置简单,docker-compose.yml 文件内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
version: '3.1'
services:
minidlna:
image: vladgh/minidlna
container_name: minidlna
restart: always
network_mode: 'host'
environment:
- MINIDLNA_MEDIA_DIR=/media
- MINIDLNA_FRIENDLY_NAME=MiniDLNA
- MINIDLNA_INOTIFY=yes
- MINIDLNA_NOTIFY_INTERVAL=3
volumes:
- ./cache/minidlna:/var/lib/minidlna
- ./data:/media
logging:
driver: "json-file"
options:
max-size: "1m"

其中 network_mode 设置的 host ,一定要设定为 host ,如果以 bridge 的方式,会出一些网络相关的问题。inotify 配置为 yes ,是使用 inotify 服务,发现文件变更的时候,会刷新 MiniDLNA 数据库;如果设置为 no 的话,有新下载下来的文件的时候,还得手动重启服务才能更新数据库,较为麻烦。然后打开防火墙的 1900/udp8200/tcp 端口。

刚开始配置完,启动服务,电视上使用的 Moli Player 立即就搜索到了 MiniDLNA 服务,并且可以浏览目录,播放视频文件,速度飞快,快进无感。但是过了一会儿,就再也找不到 MiniDLNA 这个服务了。

然后搜索问题,看到官方 Troubleshooting 里面有写:

Server not visible on Wireless behind a router

On some network configurations when the machine hosting MiniDLNA server is connected to the router through Ethernet, there may be problems accessing MiniDLNA server on WiFi (same router). To solve this, make sure that “Multicast Isolation” is turned off on the router. For example, on ADB / Pirelli P.RG EA4202N router, connect to the configuration page, then Settings->Bridge and VLAN->Bridge List->click edit on Bridge Ethernet WiFi->set Multicast Isolation to No->Apply.

哦,看来是无线路由器的问题,无线路由器的多播隔离,影响到了 MiniDLNA 的多播。但是一想,也不对啊,服务刚启动的时候,是能发现的,是过了一会儿,才搜索不到服务的。如果是这个问题的话,一开始就不可能发现服务。

接着 Troubleshooting 往下看:

DLNA server stops being visible after some time when being shared on a bridge device

If you are using ReadyMedia to “broadcast” on a bridged device (such as an OpenVPN device bridged to an Ethernet device), the server may stop being seen by the clients after some time (which may vary from a few seconds to half a day). In order to solve this you need to disable ‘multicast snooping’. You can do it instantly with the following command:

1
# echo 0 >> /sys/devices/virtual/net/br0/bridge/multicast_snooping

这个标题描述的很对症啊,但是细看描述,又不太像。前面我们着重说了 network_mode 使用的是 host 模式,相当于在宿主机上直接跑的进程,并没有涉及到桥接设备,看来也不是这个原因。那该如何是好?😓

启动服务前,我们配置防火墙打开了 1900/udp 端口,这个端口就是 SSDP 的服务端口,MiniDLNA 就是使用了 SSDP 协议提供服务的发现。那解决问题前,我们先了解下 SSDP 的协议的实现:

按照协议的规定,当一个控制点(客户端)接入网络的时候,它可以向一个特定的多播地址的 SSDP 端口使用 M-SEARCH 方法发送 “ssdp:discover” 消息。当设备监听到这个保留的多播地址上由控制点发送的消息的时候,设备会分析控制点请求的服务,如果自身提供了控制点请求的服务,设备将通过单播的方式直接响应控制点的请求。

类似的,当一个设备接入网络的时候,它应当向一个特定的多播地址的 SSDP 端口使用 NOTIFY 方法发送 “ssdp:alive” 消息。控制点根据自己的策略,处理监听到的消息。考虑到设备可能在没有通知的情况下停止服务或者从网络上卸载,“ssdp:alive” 消息必须在 HTTP 协议头 CACHE-CONTROL 里面指定超时值,设备必须在约定的超时值到达以前重发 “ssdp:alive” 消息。如果控制点在指定的超时值内没有再次收到设备发送的 “ssdp:alive” 消息,控制点将认为设备已经失效。

当一个设备计划从网络上卸载的时候,它也应当向一个特定的多播地址的 SSDP 端口使用 NOTIFY 方法发送 “ssdp:byebye” 消息。但是,即使没有发送 “ssdp:byebye” 消息,控制点也会根据 “ssdp:alive” 消息指定的超时值,将超时并且没有再次收到的 “ssdp:alive” 消息对应的设备认为是失效的设备。

通过上面的描述可知,我们的 MiniDLNA 在刚接入网络的时候,NOTIFY 发送的 “ssdp:alive” 消息是成功的,并且客户端也是通过 “ssdp:discover” 消息发现了 MiniDLNA。但是后续的不清楚是 MiniDLNA 在超时值之前没有重发 “ssdp:alive” 消息,还是由于 Troubleshotting 里面所说的网络问题,客户端没有接到来自 MiniDLNA 的存活消息。但是不管怎么样,先能用了再说。

notify_interval 是用来配置 MiniDLNA 服务的 SSDP NOTIFY 时间间隔,默认时间是 895 秒。那我减小这个间隔,在超时值范围内就可以被客户端一直显示这个共享服务的存在。这里我配置了 3s,虽然有点小,但是可以接受(对路由器的网络拥堵影响不是很大)。基本上在客户端可以一直看到 MiniDLNA 的存在,问题算是从表面上解决了。后面有时间再研究下具体原因。

玩得开心 🤠

参考链接

  1. ReadyMedia
  2. Samba
  3. MiniDLNA
  4. minidlna.conf
  5. ReadyMedia Repo
Thanks! 😊