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

http://blog.163.com/lixiangqiu_9202/blog/static/535750372015128113734761/


上篇文章中做了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.  
  10. typedef   struct  sockaddr SA;
  11. typedef   struct  sockaddr_in SA_IN;
  12.  
  13. typedef   struct
  14. {
  15.   struct  in_addr ip;
  16.   int  port;
  17. }IP;   //记录ip与端口
  18.  
  19. int  main ( int  argc, char   **argv )
  20. {
  21.  SA_IN server,addr;
  22.   int  sockfd;
  23.  IP ip;
  24.   char  s;
  25.  socklen_t addrlen = sizeof (SA_IN );
  26.  
  27.  sockfd =socket (AF_INET,SOCK_STREAM, 0 );
  28.   if (sockfd   ==   -1 )
  29.   {
  30.   perror ( "socket" );
  31.     return   -1;
  32.   }
  33.  bzero ( &server, sizeof (SA_IN ) );
  34.  server. sin_port =htons ( 8888 );
  35.  server. sin_family =AF_INET;
  36.  server. sin_addr. s_addr =INADDR_ANY;
  37.   if (bind (sockfd, (SA   * ) &server, sizeof (SA_IN ) )   ==   -1 )
  38.   {
  39.   perror ( "bind" );
  40.     return   -1;
  41.   }
  42.   if (listen (sockfd, 20 )   ==   -1 )
  43.   {
  44.   perror ( "listen" );
  45.     return   -1;
  46.   }
  47.  
  48.   while ( 1 )
  49.   {
  50.     int  newfd [ 2 ];
  51.  
  52.   newfd [ 0 ] =accept (sockfd, (SA   * ) &addr, &addrlen );
  53.     //接收两个心跳包
  54.   recv (newfd [ 0 ], &s, sizeof ( char ), 0 );
  55.   memcpy ( &ip. ip, &addr. sin_addr, sizeof ( struct  in_addr ) );
  56.   ip. port =addr. sin_port;
  57.     printf ( "%s\t%d OK\n",inet_ntoa (ip. ip ),ntohs (ip. port ) );
  58.  
  59.   newfd [ 1 ] =accept (sockfd, (SA   * ) &addr, &addrlen );
  60.     printf ( "%s\t%d OK\n",
  61.     inet_ntoa (addr. sin_addr ),ntohs (addr. sin_port ) );
  62.  
  63.   send (newfd [ 0 ], &ip, sizeof (IP ), 0 );
  64.   send (newfd [ 1 ], &ip, sizeof (IP ), 0 );
  65.  
  66.   close (newfd [ 0 ] );
  67.   close (newfd [ 1 ] );
  68.   }
  69.  
  70.   return   0;
  71. }

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

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

  • 5
    点赞
  • 43
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
YOLO高分设计资源源码,详情请查看资源内容中使用说明 YOLO高分设计资源源码,详情请查看资源内容中使用说明 YOLO高分设计资源源码,详情请查看资源内容中使用说明 YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值