在两个私网客户端上如何实现TCPsocket通信,使用云服务器作为中转客户端

目录

文章目录

前言

一、TCP为什么不能直接在两个私网客户端之间通信?

二、使用步骤

1.申请阿里云esc云服务器

2.在两个客户端运行客户端代码

三、运行服务端客户端代码

总结


前言

本人最近在学习TCP通信的时候发现TCP只能实现在局域网下任意两个客户端的通信,但是对于非局域网内的客户端,并不能直接访问,查询了众多资料后,终于找到了解决办法,能够实现任意两个或者多个非局域网客户端的相互通信,在此介绍给大家!


一、TCP为什么不能直接在两个私网客户端之间通信?

这就设计到网络通信的原理了,在网络通信中,任意两个局域网的设备之间是可以直接访问的,但是如果两台设备不在同一个局域网下,是不能直接访问的。但是如果其中一台设备拥有公网域名或者公网ip,他们两个之间就可以直接访问。根据这个原理,我们可以借用一台拥有公网IP的设备作为中转站服务器,然后服务器接收客户端A的信息,再将客户端A的信息转发给客户端B,实现了非局域网TCP通信。

二、使用步骤

1.申请阿里云esc云服务器

 在阿里云官网申请ESC云服务器,新用户可以免费试用七天。然后配置阿里云服务器,首先设置安全组,如下图所示:

 配置完云服务器后可以直接通过远程登陆登陆到阿里云服务器上,第一次登陆可能会让你设置密码账号,界面如下:

 然后我们将服务端代码移植到服务器上就可以了

如果你能够在局域网下实现TCP通信以及多线程的相关操作,那么一下代码是能够看懂的。

有几个关键点总结一下:

1.服务端的代码中的IP地址要填阿里云服务器的公网IP地址。

2.这里的原理是通过多线程实现的,当检测到有客户端连接时,通过pthread_create()函数创建子进程与客户端通信,父进程依旧在检测等待第二个客户端连接。

3.服务端是如何区分两个客户端的?是通过accept()函数的返回值描述符来区分的,通过将客户端返回的描述符存放在数组c_fd[2]中,然后通过write()函数分别发送。

代码如下(示例):


#include "stdio.h"
#include "stdlib.h"
#include "assert.h"
#include "string.h"
#include "sys/types.h"
#include "sys/socket.h"
#include "arpa/inet.h"
#include "netinet/in.h"
#include "unistd.h"
#include "pthread.h"



int ret;
int i=0;
int c_fd[2];
struct sockaddr_in saddr,caddr;
pthread_t t1;
pthread_t t2;
char BUFF1[256];
char BUFF2[256];
int read_1;
int read_2;
int param=100;



void *thread1(void *arg)
{
while(1)

{
memset(BUFF1,0,sizeof(BUFF1));
printf("Client1 address is %s\n",inet_ntoa(caddr.sin_addr));
read_1=read(c_fd[0],BUFF1,255);
if(read_1==-1) {printf("read client1 is error");}
else { printf("I read client1:%s\n",BUFF1);
write(c_fd[1],BUFF1,strlen(BUFF1));
}

}

}

void *thread2(void *arg)
{

while(1)
{
memset(BUFF2,0,sizeof(BUFF2));
printf("client2 address is %s\n",inet_ntoa(caddr.sin_addr));
read_2=read(c_fd[1],BUFF2,255);
if(read_2==-1) {printf("read client2 is error");}
else { printf("I read client2:%s\n",BUFF2);
write(c_fd[0],BUFF2,strlen(BUFF2));
}

}

}


int main()
{



        int sockfd=socket(AF_INET,SOCK_STREAM,0);
        assert(sockfd!=-1);
//      struct sockaddr_in saddr,caddr;
        memset(&saddr,0,sizeof(saddr));
        saddr.sin_family=AF_INET;
        saddr.sin_port=htons(8000);
        saddr.sin_addr.s_addr=inet_addr("172.17.124.48");
        int res=bind(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));
        assert(res!=-1);
        res=listen(sockfd,5);
        assert(res!=0);

        int len=sizeof(caddr);


        while(1)
        {
           if(i==0)
           {
           c_fd[i]=accept(sockfd,(struct sockaddr*)&caddr,&len);
                if(c_fd[i]<0){continue;}
i=1;
                printf("I am client1\n");
           }else {

              c_fd[i]=accept(sockfd,(struct sockaddr*)&caddr,&len);
             if(c_fd[i]<0){continue;}
              i=2;
              printf("I am client2\n");
         }

 if(c_fd[0]==-1)
      {printf("client1 is connect error");}
        else
        { ret=pthread_create(&t1,NULL,thread1,(void *)&param);
        assert(ret!=-1);
        }

if(c_fd[1]==-1)
        {printf("client2 is connect error");}
        else
        { ret =pthread_create(&t2,NULL,thread2,(void *)&param);assert(res!=-1);}





        }

        return 0;
}

2.在两个客户端运行客户端代码

这里的代码与同一局域网下的代码几乎没有什么区别,主要在于IP地址需要更改,这里的IP要填阿里云服务器的内网IP,记住!是内网IP,然后其他几乎没有什么变化,端口号也要一致。

代码如下(示例):

#include "stdio.h"
#include "stdlib.h"
#include "sys/socket.h"
#include "sys/types.h"
#include "unistd.h"
#include "assert.h"
#include "arpa/inet.h"
#include "string.h"
#include "netinet/in.h"


int main()
{

	
int sockfd=socket(AF_INET,SOCK_STREAM,0);
assert(sockfd!=-1);
printf("socket=%d\n",sockfd);
struct sockaddr_in saddr;
memset(&saddr,0,sizeof(saddr));
saddr.sin_family=AF_INET;
saddr.sin_port=htons(8000);
saddr.sin_addr.s_addr=inet_addr("39.103.227.125");
int res=connect(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));
assert(res!=-1);
while(1)
{

printf("please input:\n");
char buff[255]={0};

fgets(buff,255,stdin);
if(strncmp(buff,"end",3)==0){break;}
send(sockfd,buff,strlen(buff)-1,0);

char date[255]={0};
int n=recv(sockfd,date,254,0);
printf("i recive to aliyun:%s\n",date);



}

close(sockfd);
}

第二个客户端的代码就不给出了,与这个几乎没有区别

三、运行服务端客户端代码

先运行云服务器上面的客户端代码,再运行两个客户端代码

左上角为虚拟机,左下角为另一局域网下的树莓派,右边为阿里云服务器,现在连接成功后服务端成功打印


 通过实例可以看出代码正常运行,能够达到我们的要求效果

总结

这个公网TCP通信头疼了我好几天,因为一直不知道服务端如何区分客户端,因为在父进程和子进程中套接字和端口号都是一样的,后来在翻阅资料发现可以通过accept()函数的描述符区分客户端,然后成功编写了如下代码,效果跟预想一样。

  • 3
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论
本软件由服务端 、 客户端和采集端三部分组成,用于将采集端计算机上的 TCP 端口映射 到客户端计算机 上,使 客户端计算机上的应用软件可以像访问本机上的 TCP 端口一样访问采 集端计算机上的 TCP 端口。注:采集端也被称作监测点。 本软件的采集端可以运行在 X86-Linux 、 ARM7-ucLinux 或 Windows 2000/XP 系统 上,本软件的客户端和服务端只能运行在 Windows 2000/XP 系统上。 本软件要解决的问题:如下图所示,采集端计算机(采集端 1)是一台运行 Linux 操作系 统的X86 嵌入式计算机,通过ADSL 接入Internet,该计算机上开有Telnet服务(TCP-23) 。 因网络设备限制,只允许该计算机访问外界计算机,而外界计算机无法访问该计算机的 TCP- 23 端口。客户端计算机(客户端 3)是某公司内部网络中的一台运行 Windows2000 操作系 统的计算机,通过公司的交换机接入 Internet。因为采集端计算机网络设备的限制,客户端 计算机无法访问采集端计算机上的 Telnet 服务。 为使采集端计算机上的 Telnet 服务可被客户端计算机 访问,在 客户端计算机上运行 TCP 中转客户端软件,在采集端计算机上运行 TCP 中转站采集端软件。运行 TCP 中转站服务 端软件的服务器,是一台运行 Windows2000 系统有公网 IP 的计算机,客户端计算机和采 集端计算机均可以访问该服务器。 TCP 中转站软件将把采集端计算机的 TCP-23 端口映射到客户端计算机上,使用客户端 计算机的操作者用 Telnet 命令或 PuTTY 软件访问本机的 TCP-23 端口,即可与采集端计算 机的 TCP-23(Telnet 服务)通讯。每个客户端计算机可以映射多个采集端计算机的多个 TCP 端口,在客户端计算机上为每个映射的采集端计算机分配一个私有 IP:127.1.0.X 。例如: 客户端计算机与三台采集端计算机建立了映射,则这三台采集端计算机分别映射到这台客户 端计算机的 127.1.0.11、127.1.0.12 和 127.1.0.13 三个私有 IP 地址上,如果客户端计 算机上的应用软件(例如 PuTTY)访问本台计算机私有 IP 127.1.0.11 的 TCP23 端口,则应 用软件(PuTTY)实际访问的是采集端计算机 1 的 TCP-23 端口。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Hello_Yangyi

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值