搜索内网穿透,蹦出来一大堆的内网穿透工具,这不禁让我怀疑人生:已经有这么成熟的产品了,还研究内网穿透干啥?
事实证明,这些内网穿透的工具,从原理上看,一是用的开源代码FRP、NGROK包装的,然后就是走的公网服务器中转。
并不是我想要的TCP-P2P穿透通信。1
而且调研过程中发现一个非常令人失望的事情,如图:
可惜成功率不高
只不过是中转,有什么意义呢?
可见,目前比较成熟的内网穿透的FRP,尚且对P2P-TCP的成功率不高(可能原理上讲无法穿透对称型NAT),然后另一个小众的穿透工具的设计大佬直接就说了,穿透用的就是转发。
所以说对我而言,P2P 点对点的内网穿透,并不是这些穿透工具所实现的,虽然有开源的FRP、NGROK,但是都没有实现点对点的内网穿透。
同时,在纯粹的P2P网络研究论文来说,TCP的内网穿透也是难以实现的,因为对称型NAT的存在,使得P2P穿透几乎变成了不可能的事情。
所以,内网穿透的研究暂时告一段落,结论:UDP穿透是成熟可行的,已经试验通过。TCP穿透试验失败,尚不清楚原因。
无论是哪一种穿透,都无法穿透对称型NAT,虽然可以采用基于端口预测的方式来穿透,但是暂时看来这种想法只能存在与理论之中。
现阶段的两种方式:STUN/TURN就是点对点穿透和中转,中转为了应付对称型NAT。ICE方式大家都说好,找遍全网找不到相关文档,只找到一个15年前的官方文档,但是却又不说应用只说怎么编写。ICE真的有人用吗?GITHUB都没多少人关注。
网上的内网穿透工具,本质原理分为Frp和ngrok两种,这两种原理一句话来说,就是中转数据。
查阅frp文档发现,frp已经在研究点对点的TCP大数据穿透了,但是却有一个括号说成功率不高,令人失望,我也没时间去试验了,毕竟人家frp商业软件都说不行...(还是懒)
然后看了看国内比较多的内网穿透工具:
NATAPP
NAT123
小蚂蚁内网穿透
花生壳
FRP
哲西信科续断
https://www.jianshu.com/p/cdc446e51675
但要使用第三方的公网服务器就必须为第三方付费,并且这些服务都有各种各样的限制,此外,由于数据包会流经第三方,因此对数据安全也是一大隐患。
http://www.ngrok.cc/_book/start/frp_windows.html
https://github.com/fatedier/frp
https://developer.github.com/webhooks/configuring/
最后,附上我写的测试Natapp的测试代码:测试成功,公网程序和局域网程序实现TCP通信。(但是又有什么意义呢?这样的转发一个是安全问题,一个是效率问题,都是无法商用的)
/*
文件:server.c
PS:第一个连接上服务器的客户端,称为client1,第二个连接上服务器的客户端称为client2
这个服务器的功能是:
1:对于client1,它返回"first",并在client2连接上之后,将client2经过转换后的IP和port发给client1;
2:对于client2,它返回client1经过转换后的IP和port和自身的port,并在随后断开与他们的连接。
*/
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <arpa/inet.h>
#include <mysql/mysql.h>
#define MAXLINE 128
#define SERV_PORT 7788
//发生了致命错误,退出程序
void error_quit(const char *str) {
fprintf(stderr, "%s", str);
//如果设置了错误号,就输入出错原因
if (errno != 0)
fprintf(stderr, " : %s", strerror(errno));
printf("\n");
exit(1);
}
int main(void) {
int res, cur_port;
int connfd, firstfd, listenfd;
int count = 0;
char str_ip[MAXLINE] = {0}; //当前IP地址
char str_ip1[MAXLINE] = {0}; //缓存IP地址1
char cur_inf[MAXLINE] = {0}; //当前的连接信息[IP+port]
char first_inf[MAXLINE] = {0}; //第一个链接的信息[IP+port]
char buffer[MAXLINE] = {0}; //临时发送缓冲区
struct sockaddr_in cliaddr;
struct sockaddr_in servaddr;
socklen_t clilen;
int aport