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

来源:互联网 发布:网店加实体店加盟知乎 编辑:程序博客网 时间:2024/05/20 05:29

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. }

阅读全文
0 0
原创粉丝点击