局域网内点对点传输字符串与小型文件?

RT,我去年夏天的时候分布式系统课写了个 python 小程序,可以在一个局域网的电脑之间传输字符串和比较小的文件,目标是替代 U 盘和手工抄写字符串。

实现逻辑是用 Zeroconf + 一次性随机码来搜索目标及握手,再用 UDP 传输数据。

刚开始写的时候我想调用一个简单的多线程 http 服务器 + 接收端的 curl 或者 wget 来接收文件,但碍于课程要求(需要直接使用 socket)选择了手工 UDP 这种拉跨的方案。

我想让这个程序尽量的轻,本身不会占用太多内存和 CPU。

现在这套方案有如下问题:

  1. 传输速度上不去
    因为每台电脑的发 UDP 包的速度是固定的,而 UDP 包一个也不大,所以速度也很惨不忍睹。小的字符串还好,大一点的文件真的不如用 U 盘。临时的解决办法是增大 UDP 包大小。
  2. 过大的 UDP 包会造成兼容性问题
    已知 macOS 无法用过大的 UDP 包。
  3. 数据完整性欠佳
    UDP 包是没有顺序的,在理想情况下发送端按什么顺序发出去的包,接收端也会以同样的顺序收到,并写入文件即可。但现实是如果文件大小达到了 50M 左右的时候有几个 UDP 包的顺序会变,导致接收到的文件损坏。临时的解决办法是在每个包之间人为的加入一点间隔,但这种不治本的办法确实不行,文件损坏的问题还是有。

我目前有 2 个方案:

  1. 魔改当前 UDP 操作,加上多线程,手工给每个 UDP 包标号。接收端整个 buffer 按标号排序后写入文件。
    问题是这个 buffer 的大小控制不好容易把内存挤爆,尤其是文件过大的时候,而且自己造轮子非常麻烦而且质量不行。
  2. 把现有的 UDP 协议换成 http 服务器 + curl 的操作

现在的问题是:

  1. UDP 多线程传输文件有现成的库么?别的语言也可以
  2. 轻量又多线程的 HTTP 服务器推荐?

这个东西如果成了,我还想把它做到各个发行版里,写在简历上好看一点:joy:

1赞

多线程,UDP,现成的 py。

这好像就是 Python3 新出的自带的那个 Asyncio。里面有 UDP echo server/client 的例子。

轻量又多线程,大概就是基于 Asyncio 实现的 aiohttp (github 上 10k+ stars)

PS: :see_no_evil: 我在你隔壁的省

1赞

仰望滑铁卢大佬

试试 iptux?

如果一定要自己实现传输功能,试试 kcp,局域网内应该没有问题。虽然我个人建议直接上 aiohttp 作服务器就是了。

asyncio,不过这个是协程方式;py 自带 threadingsocketServer,上面套一层 http 协议,多线程,两个都不会阻塞 io,大差不差。
魔改 udp 的话,其实这个 buf 不一定在内存里,每个 udp 包大小可以固定的,就可以在没到的序号固定大小填 0,包到的时候在 seek 到对应位置写上数据,应该就不怕内存爆了。传的慢就在加上压缩,就成了 http 的 gzip 了。所以为啥不能直接在 nc 上套一层发现。哈哈

1赞

为嘛不用 TCP?

一个类似你魔改方案的东东 =>局域网传输工具 Syncthing 有自己定义一个 Block Exchange Protocol 来切分文件和握手,每个文件 128kb 到 16mb,然后用 google protocol-buffers 实现的, Interesting (:

https://docs.syncthing.net/specs/bep-v1.html
https://docs.syncthing.net/dev/device-ids.html
google proto3 https://developers.google.com/protocol-buffers

软件质量 & 用户体验 :star2::star2::star2:

zypper in syncthing

从命令行直接输入 syncthing 会自动出现浏览器界面,然后鼠标点一点就可以了。

Android 和 Mac 也有客户端。

brew install --cask syncthing

1赞

古老的 bt 下载 和 ed2k 网络也有过类似的协议把。bt/ed2k 都能以任何顺序下载文件的一部分,然后 “拼” 起来。不过 ed2k 估计已经没人用了。

BT 种子就是一” 块 “一” 块 “的 hash 拼出来的

https://en.wikipedia.org/wiki/Torrent_file

这个没有 iOS 软件

我决定了,用socketserver来重写 socket 部分,改用 TCP,用aiohttpcurl来传输文件

局域网里面一般直接用 tcp,别用 UDP. 如果是 python 的话,也犯不着用 aiohttp 那么麻烦,python 标准库内置的 http 服务器和 http 客户端足够了。

现在这种东东,麻烦的地方是写 GUI,有些人想要进度条,有些人想要断点续传,有些人想要自动发现或者 P2P,写 GUI 的时候特别麻烦。至于发送文件的协议千万种,根本不是问题。

还有功能之外的,有些人想要 100k 的可执行文件,超过了就觉得软件不绿色。你用 pyinstaller 打包出来几十 M,放出来肯定被喷死。还有些人既要支持 Mac 也要支持 LINUX,最好也支持 DOS,特别烦。做自己用的简单,做成产品太难了。

如果觉得 pyinstaller 打包太大,可以试试 Nuitka,体积会小很多。

我根本都没考虑过 gui,可能上了移动端或者 windows 才考虑一个,到时候就考虑用 C# 重写了
unix 下用 python 可以保持高可移植性,别的 C# 都能搞定
觉得安装包大就不用这种人建议让他有本事自己写一个,反正也不难

c# 写也不容易。我自己写过一个,所以很了解这里面的坑。IM、文件传输表面看都是很简单的技术,实际挖下来,这两个领域非常的艰深。有非常非常多的需求可以做。