SimpleVPN 写好了以后,感觉比较简单,我觉得只有简单的东西才经得起折腾,才能全民折腾,所以说 SimpleVPN 还不够简单,本文来一个更加简单的,展示一个超级简单的点对点聊天程序,而且还带简单加密哦。顺便,我们再来看下,到底什么是 VPN 以及怎样实现它。 QQ 如今才刚刚行过成年之礼,典型的 90 后 00 前,却早已到了后浪把前浪拍到岸边的砍儿,果不其然,被 10 后的微信给逆袭了... 好在都是腾讯的,这就把竞争收敛到了公司内部,不然这将意味着一个巨人的倒下,太可怕了。多年前,很多人逆向过 QQ 的协议,然后做了各种各样的第三方客户端,这在腾讯看来是在搞根据地抢饭碗,这是无法接受的,所以加强了各种安全措施,让你第三方无法接入这个私有化的 QQ 系统... 此后,第三方的 QQ 软件渐渐消失了,只剩下了 "腾讯 QQ"。不过,在我看来,腾讯封闭 QQ 协议不见得是件好事,你能指望一个 QQ 终端能做出什么大动作呢?充其量腾讯 QQ 是一个非常棒的产品,但是微信出来之后呢?如果微信不是 T 家的呢... 所以说啊,让所有人都接受 T 家的通讯协议才是真正的霸道,从业务侧不一定是这般,至少从网络侧看是这样的。这样一来,即便哪天阿里做出了新的社交产品,还是 "基于腾讯的 XXX 协议,兼容 QQv.. 版本,兼容微信 v... 版本",你看那些伟大的公司,很多都贡献了一个协议或者规范,比如 HTTP,HHTPS,SSL/TLS,Android... 除了 QQ 之外,还有一类软件是我们熟悉的,那就是迅雷和电驴。不管是 QQ,还是迅雷,电驴,它们的共同点都是在 TCP/IP 网络之上重新构建了一个新的点对点网络,即 P2P 网络。所谓的 P2P 网络指的是网络中的节点都是对等关系,任意两个节点之间,一个节点和多个节点之间均可以对等通信。事实上,P2P 根本就没有什么神奇的,我们最底层的 IP 网络就是一个 P2P 网络,任意两个节点之间都可以实现没有主从关系的单播通信,而一个节点和多个节点之间则可以用组播进行通信,只是 IP 名称早已有之,因此 P2P 就特指应用层的组网模式了。简单点说,如果说 IP 网络是在各种互通的链路层之上构建的一个点对点网络的话,那么 P2P 网络就是构建于 TCP/IP 之上的对点对网络。至于说这个点对点上跑什么,那就取决于网络构建者的意愿了。 如果在点对点网络上跑人与人之间互发的消息,那它就是个聊天软件,比如 QQ,微信这种,如果在点对点网络上跑文件数据,那就是 P2P 下载,那它就是个 P2P 下载软件,比如迅雷,电驴这种,类似的,如果在点对点网络上跑 IP 数据报文或者以太帧,那它就是个 Overlay 技术,比如 VXLAN,GRE 这种,如果将以上这些 Overlay 数据进行加密,那它就是 VPN。不管怎样,名称并不重要。 以上这些都是闲扯,不是本文的核心。 本文的核心在于展示一下从 VPN 到聊天程序的过渡是多么简单。 上一篇文章《假期跟我一起写一个点对点 VPN-SimpleVPN 详解》中,我展示了一个非常简单的点对点 VPN 框架,本文中,我来将它改成一个非常简单的聊天程序。功能如下:
1. 用户登录可以获取在线用户列表;2. 用户登录后可以通知其它在线用户该用户登录;3. 登录用户可以随时获取在线用户列表;4. 登录用户可以给指定在线用户发送消息;5. 支持在线用户间的群聊。基本上,除了不支持留言,基本该有的都有了。我们来看下怎么改。 其实,TCP/IP 任何层的对等通讯都是在 "聊天",只是类似社交软件中的聊天是在人与人之间进行的,而 TCP/IP 对等层 "聊天" 是协议与协议之间进行的。协议与协议之间的聊天需要一个寻址的过程,不管是 DNS,IP 路由,ARP 解析,MAC / 端口查找... 都是为了确认并找到要把消息发给谁。而人与人之间的聊天在发消息之前也要在头脑中经过一个类似的过程,也就是说,当你按下回车键的那一刻,你已经很明确这条消息是发给谁的了,这与网络协议之间的对等通信完全不同,后者需要协议来完成寻址,而人则在自己的大脑中完成寻址过程,所以说,改法很简单:
1. 添加消息的发送和接收chat 程序直接接收用户的输入,而不是从 TAP 中读取以太帧,所以不需要 tap_fd,改为 con_fd 了,其实就是 console,因此需要将 read_from_tap 和 write_to_tap 改为 read_from_console 和 write_to_console:
2. 删除寻址和学习机制
- int read_from_console(struct process_handler *obj, struct frame *frame)
- {
- size_t len = 0;
- int fd = obj->conf->con_fd;
- struct list_head *tmp;
- struct node_info *peer;
- char buf[1024];
- // 从标准输入读取
- len = read(fd, buf, 1024);
- // 如果是展示在线用户列表,则将邻居表展示出来后退出call_stack
- if (len > 0 && !strncmp(buf, "list", strlen("list"))) {
- list_for_each(tmp, &obj->conf->peers) {
- peer = list_entry(tmp, struct node_info, list);
- printf("ID:%d online\n", peer->tuple.id);
- }
- return 1;
- } else {
- // 否则将用户输入的信息发给指定的节点,格式为:
- // $指定节点ID:$消息内容
- // 比如:"2:皮鞋爆炸"的意思就是把"皮鞋爆炸"发给节点ID为2的用户
- char IDchar[4] = {0};
- int ID = 0;
- strncpy(IDchar, buf, 1);
- ID = atoi(IDchar);
- list_for_each(tmp, &obj->conf->peers) {
- peer = list_entry(tmp, struct node_info, list);
- if (peer->tuple.id == ID) {
- obj->peer = peer;
- }
- }
- if (!obj->peer) {
- return -1;
- }
- len = strlen(buf) - 2;
- strncpy(frame->data, buf+2, len);
- frame->len = len;
- }
- return 0;
- }
- int write_to_console(struct process_handler *obj, struct frame *frame)
- {
- int ret = 0;
- int fd = obj->conf->con_fd;
- size_t len;
- // 非常简单,就是把消息展示出来,加上来源ID,比如"1:皮鞋爆炸"的意思就是"节点ID为1的用户发来一句'皮鞋爆炸'"
- printf("From %d:%s\n", frame->sid, frame->data);
- return ret;
- }
由于寻址已经在人的大脑中完成,故不再需要寻址,因此去掉了以下的 handler:
3. 增加在线用户列表显示功能
- static struct process_handler routing_handler = {
- .send = frame_routing,
- .receive = mac_learning,
- };
详见 1 的用户输入解析。当输入 list 的时候,会显示在线用户。现假设有 ID 为 1,2,3 的 3 个用户登录系统,用户 3 输入 list 时,以下是输出:
ID:1 onlineID:2 online然后同样在用户 3 的终端前输入 2:aaaaaaaaaaaaaaaa,那么用户 2 的终端将显示:
From 3:aaaaaaaaaaaaaaaa也许你会觉得这不像个聊天程序,那是因为它少一个漂亮的 GUI,而我并不擅长这个。------------------------ 此时应该知道 frame 中 sid,did 这两个 ID 的作用了,它可以用来支持群聊,就跟它在 VPN 中支持组播一样... 关于这个的代码,我已经放进了 github 的 SimpleVPN 那个目录:https://github.com/marywangran/SimpleVPN/blob/master/SimpleChat.c 通过以上,我们可以看出,这类技术可以改头换面叫做任何不同的名称,关键还是看你怎么用它了。不管它叫 VPN,管它叫 chat,管它叫 overlay 吧,或者直接 overlaychat...
其实,要什么 VPN,如果你和你的 QQ 好友能把自己的 QQ 输入输出和本地的一个 TAP 网卡字符设备的输入输出对接起来,那大 QQ 就可以当成是一个 VPN 客户端,同样的,如果你用迅雷,电驴什么的来对接一个虚拟网卡传输以太帧或者 IP 报文而不是传输文件,那么迅雷,电驴构建出来的 P2P 网络就是一个 VPN 网络...
让我们来畅想一下如何来应景。在装了 QQ 的 Windows 机器上,有一个文件,它是 "C:/Tap.frame",针对它的读写实际上就是在读写 TAP 虚拟网卡设备,这个用 Windows 驱动非常容易办到... 此时,我们把这个文件用 QQ 传送给好友,并且好友那边也有一个这样的文件,会怎样?我们岂不是通过 QQ 搭建了一条隧道吗?Overlay?嗯,是的,这叫做 IP over QQ 吧,或者 Everything over APP?管它呢,名词不重要!
这是分层模型给我们带来的好处!只要你的 IP 报文或者以太帧在本地形成了,除了直接发送到网线上之外,还有别的运输方式,比如你可以用 UDP 将其送出,可以用一个新的 IP,当然这些都是常规的... 本文中,我们看到,你还可以用 QQ,迅雷,电驴之类的软件将其送出,甚至,你可以用集装箱将其送出,这就是 IP over 集装箱技术,哈哈。
------------------------ 悲哀的五一结束了,突然间的搬家扰乱了我一切的计划,本来还想去广州看看五口通商时的殖民地文化,然而因为搬家泡汤了,不由感觉不爽。看来以后真的什么都不能去计划!一大堆的出游计划全部泡汤,于是利用假期第一天的早上和假期最后一天的晚上写了两篇文章,作为补偿。
来源: http://blog.csdn.net/dog250/article/details/71076357