专栏首页Eureka伽罗的技术时光轴内网穿透 TCP打洞 【c语言实现】

内网穿透 TCP打洞 【c语言实现】

上篇文章中做了UDP打洞,这篇当然就会是TCP打洞了,两个处于不同内网的两台机器如何通过TCP/IP协议进行链接通讯呢?这其实跟UDP打洞差不多,基本步骤是这个样子的。 假设我们有两台处于不同内网的两台机器A和B和一台众所周知外网IP的服务器S,而机器A中运行着通讯的服务端程序B运行着通讯的客户端程序,那么

1、A连接S,S记录A的外网IP与通讯的端口 2、B连接S 3、S将A与此通讯的端口号返回给A 4、S将A与此连接的IP与端口号返回给B 5、A在程序中将服务绑定并侦听在从S返回的端口 6、B使用从S返回的IP与端口连接A

这样A与B就成功连接了,这里需要注意的一点就是两个socket在同一个端口绑定的问题,socket提供了setsockopt函数,其中参数SO_REUSEADDR可以解决这个问题

下面是c语言代码示例

S中的程序

  1. #include <stdio.h>
  2. #include <sys/socket.h>
  3. #include <sys/types.h>
  4. #include <stdlib.h>
  5. #include <string.h>
  6. #include <errno.h>
  7. #include <arpa/inet.h>
  8. #include <netinet/in.h>
  9. typedef struct sockaddr SA;
  10. typedef struct sockaddr_in SA_IN;
  11. typedef struct
  12. {
  13. struct in_addr ip;
  14. int port;
  15. }IP; //记录ip与端口
  16. int main(int argc,char **argv)
  17. {
  18. SA_IN server,addr;
  19. int sockfd;
  20. IP ip;
  21. char s;
  22. socklen_t addrlen=sizeof(SA_IN);
  23. sockfd=socket(AF_INET,SOCK_STREAM,0);
  24. if(sockfd == -1)
  25. {
  26. perror("socket");
  27. return -1;
  28. }
  29. bzero(&server,sizeof(SA_IN));
  30. server.sin_port=htons(8888);
  31. server.sin_family=AF_INET;
  32. server.sin_addr.s_addr=INADDR_ANY;
  33. if(bind(sockfd,(SA *)&server,sizeof(SA_IN)) == -1)
  34. {
  35. perror("bind");
  36. return -1;
  37. }
  38. if(listen(sockfd,20) == -1)
  39. {
  40. perror("listen");
  41. return -1;
  42. }
  43. while(1)
  44. {
  45. int newfd[2];
  46. newfd[0]=accept(sockfd,(SA *)&addr,&addrlen);
  47. //接收两个心跳包
  48. recv(newfd[0],&s,sizeof(char),0);
  49. memcpy(&ip.ip,&addr.sin_addr,sizeof(struct in_addr));
  50. ip.port=addr.sin_port;
  51. printf("%s\t%d OK\n",inet_ntoa(ip.ip),ntohs(ip.port));
  52. newfd[1]=accept(sockfd,(SA *)&addr,&addrlen);
  53. printf("%s\t%d OK\n",
  54. inet_ntoa(addr.sin_addr),ntohs(addr.sin_port));
  55. send(newfd[0],&ip,sizeof(IP),0);
  56. send(newfd[1],&ip,sizeof(IP),0);
  57. close(newfd[0]);
  58. close(newfd[1]);
  59. }
  60. return 0;
  61. }

A中的程序

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <sys/socket.h>
  5. #include <sys/types.h>
  6. #include <arpa/inet.h>
  7. #define SER "xxx.xxx.xxx.xxx"
  8. #define PORT 8888
  9. typedef struct
  10. {
  11. struct in_addr ip;
  12. int port;
  13. }IP; //ip与端口
  14. typedef struct sockaddr SA;
  15. typedef struct sockaddr_in SA_IN;
  16. //回射服务
  17. void echo_ser(int sockfd)
  18. {
  19. char buf[1024];
  20. while(1)
  21. {
  22. bzero(buf,sizeof(buf));
  23. //接收B发来的数据
  24. recv(sockfd,buf,sizeof(buf)-1,0);
  25. printf("%s",buf);
  26. //向B发送数据
  27. send(sockfd,buf,strlen(buf),0);
  28. buf[strlen(buf)-1]='\0';
  29. if(strcmp(buf,"exit") == 0)
  30. break;
  31. }
  32. }
  33. int main(int argc,char **argv)
  34. {
  35. int sockfd,sockfd2;
  36. SA_IN server,addr;
  37. IP ip;
  38. socklen_t addrlen=sizeof(SA_IN);
  39. char s='a';
  40. int flags=1;
  41. sockfd=socket(AF_INET,SOCK_STREAM,0);
  42. bzero(&server,sizeof(SA_IN));
  43. server.sin_family=AF_INET;
  44. server.sin_addr.s_addr=inet_addr(SER);
  45. server.sin_port=htons(PORT);
  46. if(setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&flags,sizeof(int)) == -1)
  47. perror("setsockopt sockfd");
  48. connect(sockfd,(SA *)&server,sizeof(SA_IN));
  49. send(sockfd,&s,sizeof(char),0);
  50. recv(sockfd,&ip,sizeof(IP),0);
  51. close(sockfd);
  52. sockfd2=socket(AF_INET,SOCK_STREAM,0);
  53. if(sockfd2 == -1)
  54. perror("sockfd2");
  55. if(setsockopt(sockfd2,SOL_SOCKET,SO_REUSEADDR,&flags,sizeof(int)) == -1)
  56. perror("setsockopt sockfd2");
  57. server.sin_addr.s_addr=INADDR_ANY;
  58. server.sin_port=ip.port;
  59. if(bind(sockfd2,(SA *)&server,sizeof(SA_IN)) == -1)
  60. perror("bind sockfd");
  61. if(listen(sockfd2,20) == -1)
  62. perror("listen");
  63. echo_ser(accept(sockfd2,(SA *)&addr,&addrlen));
  64. close(sockfd2);
  65. return 0;
  66. }

B中的程序

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <sys/socket.h>
  5. #include <sys/types.h>
  6. #include <arpa/inet.h>
  7. #define SER "xxx.xxx.xxx.xxx"
  8. #define PORT 8888
  9. typedef struct
  10. {
  11. struct in_addr ip;
  12. int port;
  13. }IP; //ip与端口
  14. typedef struct sockaddr SA;
  15. typedef struct sockaddr_in SA_IN;
  16. void echo_cli(int sockfd)
  17. {
  18. char buf[1024];
  19. while(1)
  20. {
  21. bzero(buf,sizeof(buf));
  22. printf(">");
  23. fflush(stdout);
  24. fgets(buf,sizeof(buf)-1,stdin);
  25. send(sockfd,buf,strlen(buf),0);
  26. bzero(buf,sizeof(buf));
  27. recv(sockfd,buf,sizeof(buf)-1,0);
  28. printf("%s",buf);
  29. buf[strlen(buf)-1]='\0';
  30. if(strcmp(buf,"exit") == 0)
  31. break;
  32. }
  33. }
  34. int main(int argc,char **argv)
  35. {
  36. int sockfd,sockfd2;
  37. SA_IN server,addr;
  38. IP ip;
  39. socklen_t addrlen=sizeof(SA_IN);
  40. sockfd=socket(AF_INET,SOCK_STREAM,0);
  41. bzero(&server,sizeof(SA_IN));
  42. server.sin_family=AF_INET;
  43. server.sin_addr.s_addr=inet_addr(SER);
  44. server.sin_port=htons(PORT);
  45. connect(sockfd,(SA *)&server,sizeof(SA_IN));
  46. recv(sockfd,&ip,sizeof(IP),0);
  47. close(sockfd);
  48. sockfd2=socket(AF_INET,SOCK_STREAM,0);
  49. server.sin_addr=ip.ip;
  50. server.sin_port=ip.port;
  51. while(connect(sockfd2,(SA *)&server,sizeof(SA_IN)) == -1)
  52. perror("connect");
  53. echo_cli(sockfd2);
  54. close(sockfd2);
  55. return 0;
  56. }

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Windows错误码大全error code

    0000 操作已成功完成。 0001 错误的函数。 0002 系统找不到指定的文件。 0003 系统找不到指定的路径。 0004 系统无法打开文件。 ...

    战神伽罗
  • JAVA中的List的使用

    战神伽罗
  • power shell测试wmi

    战神伽罗
  • dotnet core 微服务教程

      --no-https :表示这个应用运行的时候不需要https证书,这是为了部署时方便

    Vincent-yuan
  • 近三年全球自动驾驶发生160笔投资,总额达800亿美元

    雷锋网按:对于自动驾驶赛道上的玩家来说,2016年的意义绝非凡响。在这一年,不管是科技巨头,还是老牌汽车厂商,都争相在此砸入巨资以刷存在感,创业公司作为投资对象...

    企鹅号小编
  • 2018年工业互联网加速落地,互联网如何智造中国?

    互联网正在变得越来越“重”,不只是从线上走到线下,而是在从“比特世界”深入到“原子世界”,工业互联网的兴起,更是让互联网从“轻公司”成为名副其实的“重工业”。

    罗超频道
  • 云时代的研发环境:实施路径

    在云计算的时代大背景下,我们推荐采用研发技术栈管理平台来集中管理组织中的技术栈,允许基于一个技术栈创建开发测试PaaS和生产PaaS两个PaaS服务,从而支撑开...

    云加社区
  • 从今年的安全泄露事故学到的6个教训

    大数据文摘
  • 吞了1000瓶老干妈的南山头铁鹅,Python制作千图成像(附上源代码和应用程序)

    最近的瓜可谓真有意思,南山头铁鹅也默默吞下下了1000瓶老干妈。此时用这张1000张老干妈辣椒酱图片组成的企鹅来表达最适合不过了

    行哥玩Python
  • 年终盘点 | 红帽KVM虚拟化大讲堂 | 视频讲解+实验展示+实施手册

    针对很多客户关注的KVM虚拟化方案,笔者应邀,针对金融行业一些关注KVM虚拟化方案的客户进行了讲解。为了使由于各种原因没能参加课堂的朋友也能了解到讲解的内容,笔...

    魏新宇

扫码关注云+社区

领取腾讯云代金券