目录

文章目录

前言

一、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()函数的描述符区分客户端,然后成功编写了如下代码,效果跟预想一样。

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

  1. 下载丨10月数据库技术通讯:HAIP在两个私网网卡上发生互换,导致ASM实例启动失败...

    墨墨导读:为了及时共享行业案例,通知共性问题,达成共享和提前预防,我们整理和编辑了<云和恩墨技术通讯>,通过对过去一段时间的知识回顾,故障归纳,以期提供有价值的信息供大家参考.同时,我们也 ...

  2. 两个网端主机通过路由器实现通信的实例演示(华为设备)

    大家好,今天给大家分享两个网端主机通过路由器实现通信的实例演示 看网络拓扑图: 首先,我们来分析一下网络的环境: pc1 的ip 信息 : 192.168.10.10 255.255.255.0 pc ...

  3. 电脑文件如何传到云服务器上,电脑文件如何传到云服务器上

    电脑文件如何传到云服务器上 内容精选 换一换 DNS服务器用于解析弹性文件服务中文件系统的域名.DNS服务器东北区IP地址为100.125.6.250,其它区域详情请参见华为云内网DNS地址.默认情况 ...

  4. 弹性服务器怎么上传文件,上传哪个文件夹弹性云服务器

    上传哪个文件夹弹性云服务器 内容精选 换一换 华为云帮助中心,为用户提供产品简介.价格说明.购买指南.用户指南.API参考.最佳实践.常见问题.视频帮助等技术文档,帮助您快速上手使用华为云服务. 本节 ...

  5. 怎么把静态网页放到服务器上,将静态网页部署在云服务器上

    将静态网页部署在云服务器上 内容精选 换一换 部署提供可视化.一键式部署服务,支持并行部署和流水线无缝集成,实现部署环境标准化和部署过程自动化.本节通过以下五步介绍如何使用部署服务将归档在软件发布库的 ...

  6. 本地WinSCP上传文件到腾讯云服务器显示Permission Denied

    本地WinSCP上传文件到腾讯云服务器显示 Permission Denied 从字面看,就是没有权限.这时我首先想到了腾讯云服务器的安全组.先去设置安全组. 1.设置安全组 我们用的是腾讯的云服务器 ...

  7. 电脑文件怎么复制到服务器,电脑上文件怎样粘贴复制到云服务器

    电脑上文件怎样粘贴复制到云服务器 内容精选 换一换 本方式建议用于非生产系统.本方式通过使用云硬盘备份服务或云服务器备份服务,对SAP HANA的一个或多个卷执行快照,再将卷快照创建成备份,自动上传到 ...

  8. 云服务器ecs上能放几个网站,云服务器ecs能放几个站点

    云服务器ecs能放几个站点 内容精选 换一换 对于已安装Cloud-Init/Cloudbase-Init的云服务器,首次执行切换/故障切换操作,或者创建容灾演练后,系统第一次启动时会运行Cloud- ...

  9. php 访问服务器上图片不显示,php显示云服务器上图片不显示

    php显示云服务器上图片不显示 内容精选 换一换 远程登录Windows弹性云服务器后,修改分辨率设置.不同版本的Windows操作系统,操作略有差异,本节以Windows Server 2016 标 ...

最新文章

  1. java解析五元组_pcap文件解析,并且按照五元组分类
  2. 喜大普奔!GitHub官方文档推出中文版啦!
  3. solrCloud异常
  4. 《算法导论》学习总结 — 13. 第13章 红黑树(2)
  5. Linux学习记录--数据流重定向
  6. SP 2010: Getting started with Business Connectivity Services (BCS) in SharePoint 2010
  7. 支付宝支付-提现到个人支付宝
  8. 计算机组成结构IR,计算机组成与体系结构试题
  9. 解决git提交问题error: The requested URL returned error: 403 Forbidden while accessing
  10. 扩容是元素还是数组_Java中对数组的操作
  11. dede mysql语句_让dede运行php代码和mysql语句
  12. python编程工时计算_Python编程题:两个日期间的天数统计(附代码)
  13. UVA11069 A Graph Problem【递推】
  14. java 参数类型转换_java – 如何从通配符类型转换为参数化类型?
  15. 软考高级系统分析师上午历年真题
  16. 工业物联网的体系架构
  17. 六西格玛dfss_六西格玛设计咨询
  18. 零基础学爬虫大概多久?
  19. AB罗克韦尔plc指示灯详解
  20. 说话人识别的特征选取

热门文章

  1. 小学数学学习的思想方法
  2. C.H. Robinson罗宾逊全球物流推出跨欧亚铁路货运服务
  3. @2021SC@SDUSC 源码分析: core/lib/encoding
  4. 森林里的小兔子步骤(转自http://www.zcool.com.cn/article/ZNzA2NA==.html)
  5. 作图笔记 - mermaid的字体大小设置
  6. hashlib模块学习
  7. linux下图片裁剪工具,linux下图片处理工具ImageMagick使用方法
  8. 余占艳的设计沫殇包包
  9. el-input添加默认前置值,不可删除,只能在默认值之后增加
  10. hdu 5266 pog loves szh III