qcr
A small chat room on tcp protocol.
1 License
This program is released under LGPL-3.0-only.
2 简介
qcr是一个实验性的点对点网络通信程序,可以实现基本的聊天以及文件、目录和链接的共享,如果有需要也可实现某些自动化的功能。
3 构建系统
过去使用make和Makefile进行构建,由于作者能力有限始终无法实现对更多平台和系统的支持,目前已弃用。
从v0.1.3开始使用zuo进行构建(dependencies见"info.rkt")。
"main.zuo"提供以下target:clean、install、uninstall、test、setup、exe、dist。要执行特定的任务,请使用zuo . [target name]。
前五个target为PHONY target,target name即为其本身的名称;exe的target name为"main"(windows系统需加扩展名".exe");dist的target name格式为"qcr-[system]-[arch].zip"。
功能上,
clean:删除现有构建产物。
install:类似于raco pkg install,但在安装前会卸载已安装的同名包(如果有的话)。
uninstall:同raco pkg remove qcr。
test:同raco test main.rkt。
setup:同raco setup qcr。
exe:同raco exe main.rkt
dist:将stand-alone executable及其依赖打包为Zip归档文件。
执行某一特定任务时,zuo总是首先读取"main.zuo",而这一文件导入了"check.zuo",后者会对运行环境进行一些检查,以确定哪些target可用。使用当前不支持的target会引起一个错误。
4 安装使用
[1]已经安装好Racket。
raco pkg install qcr
racket -e "(require (submod qcr main))" -- [命令行参数]
[2]使用编译好的可分发包。
解压并进入"main"/"main.exe"可执行程序所在目录并执行命令即可。
使用--help查看使用说明。
5 工作流程
通过命令行参数设置密码、主机、端口、模式。
建立TCP连接。
交换RSA公钥,并使用RSA加密交换AES密钥和初始化向量,然后进行密码验证。
开始聊天,数据使用AES算法加密。
聊天结束,Ctrl-c退出。
6 协议
传输层使用TCP协议,不赘述。
应用层协议基于Racket port构建。
数据包有message、link、file、dir、command、unsafecommand和localcommand七种类型。
每一个数据包都包含数据包类型(message类型数据包无类型信息)、校验和、MD5校验码和实际数据四个部分。
file和dir两种类型数据包的实际数据部分包含其名称。
MD5校验码和实际数据均经过AES加密。
7 数据包生成和处理
数据包的生成和处理理应相互独立以便分为两个Racket thread并发执行,但由于两个过程中都需要从标准输入中读取数据,因此不得不使用sync置于同一Racket thread中执行。
程序针对每一行输入只生成一个数据包。
message和link强调时效性,因此数据包中包含时间信息。
link类型数据包处理时提供可选的重定向到浏览器的功能,但运行时并不会检查此功能是否可用。
dir类型数据包生成时首先将目录打包为Zip归档文件,再对文件进行传输,接收端处理时直接以文件形式保存。
command evaluator使用racket/sandbox实现,unsafe-command evaluator是对eval函数的封装。
因此,
不推荐使用此程序分享大的文件或目录,除非你的目的就在于传输数据。
不建议以过高的频率输入指令或消息。无论发送还是接收数据,以上数据包类型的processor在处理完毕后都会在终端中换行作为与前后的分隔。 这一定程度上可以作为“可以继续进行”的标志。
8 抽象和扩展
8.1 Logging
(require qcr/logging) | package: qcr |
logger
filesystem-logger : logger?
logger
network-logger : logger?
logger
eval-logger : logger?
log-receiver
filesystem-error-log-receiver : log-receiver?
log-receiver
eval-error-log-receiver : log-receiver?
log-receiver
eval-info-log-receiver : log-receiver?
log-receiver
network-error-log-receiver : log-receiver?
log-receiver
network-debug-log-receiver : log-receiver?
dispatcher
: (hash/c (or/c 'none 'fatal 'error 'warning 'info 'debug) (listof log-receiver?) #:immutable #t)
8.2 数据包
parameter
(all-confirm) → any/c
(all-confirm v) → void? v : any/c
= #f
parameter
(download-location) → path-element?
(download-location v) → void? v : path-element?
= "file"
parameter
(allow-eval) → any/c
(allow-eval v) → void? v : any/c
= #f
parameter
(allow-unsafe-eval) → any/c
(allow-unsafe-eval v) → void? v : any/c
= #f
请注意执行对方发送的指令时可以对以上这些参数进行修改,如果不是绝对信任请不要授予不必要的权限。
|
method
(send a-processor make) → input-port?
make方法必须返回一个input port供后续加密和传输使用,而parse方法可以返回任意值。此接口就是针对这两个方法的行为进行检查。如需自定义数据包类型,无需将processor作为此接口的一个实现,只须实现为一个符合以上描述的类即可,如需边界检查请自行添加。
以下为extension模块原生支持的processor。
| ||
superclass: object% | ||
|
| ||
superclass: message-processor% | ||
|
| ||
superclass: object% | ||
|
| ||
superclass: file-processor% | ||
|
| ||
superclass: object% | ||
|
| ||
superclass: command-processor% | ||
|
| ||
superclass: unsafe-command-processor% | ||
|
parser
port : input-port?
如需自定义此函数(如使用++import标记时)请将数据包类型信息从此port中消耗掉。 此外,在通用的预处理过程中'message总是作为保留类型而被特殊对待,因为其数据包中无类型信息。
dispatcher
: (hash/c symbol? (implementation?/c processor<%>) #:immutable #t)
在自定义数据包时,一般首先实现processor,然后通过<type>?规定(current-input-port)和TCP port中的类型信息,并将代表类型信息的symbol和processor打包为registry哈希表, 最后通过++import从模块中导入自定义的<type>?和registry(一定记得在这两者中预留'message和对应的processor)。
9 兼容性问题
windows上在控制台中无输入时无论TCP port中是否有数据read-line-evt都会使得sync阻塞住。 (原因和折中方案详见关于windows console, 其中折中方案可能涉及修改Racket源码重新编译)
10 更新
后续更新
弃用OpenSSL1.1,全部使用3.0版本API。
修复了logging system的一些小问题。
v0.1.8
2022.9.3
添加了测试,并相应更新了诸多配置文件和文档。
v0.1.7
2022.9.1
用AES算法取代vigenere算法以提升性能。
添加了一种新的数据包类型。
完善了文档。
v0.1.6
2022.8.29
完善了文档。
重构了extension模块,丢掉了一些历史包袱。
更多更新。
v0.1.5
2022.8.25
添加了一些命令行标记。
添加了logging system。
修复了一些已知问题。
更多更新。
v0.1.4
2022.8.18
添加了两个命令行标记和三个命令行参数。
添加了两种新数据包类型。
修复了几个已知问题。
更多修改。
11 项目状态
此项目是作者用于自学网络编程和Racket语言的实验性项目,这个目的已经基本达到了,因此不会再添加新的功能,但仍会继续维护。
有任何bug和好的想法欢迎提issue至github。