【Linux】【网络】不同子网下的客户端和服务器通信

news2025/2/22 23:32:42

【Linux】【网络】不同子网下的客户端和服务器通信

前两天在进行socket()网络编程并进行测试时,发现在不同wifi下两个电脑无法进行连接,大概去查找了如何解决 看到可以使用
frp 这个快速反向代理实现。

  • frp 可让您将位于 NAT 或防火墙后面的本地服务器暴露到互联网。它目前支持TCP和UDP,以及HTTP和HTTPS协议,允许通过域名将请求转发到内部服务。
  • github官网:https://github.com/fatedier/frp?tab=readme-ov-file#tcp-stream-multiplexing

先提一些基础概念,为什么在不同wifi下无法进行通信:

不同wifi下无法进行通信原因

1公网 IP与 内网 IP

IP地址是网络中的唯一标识符,用于区分网络中不同设备的位置

  • 公网 IP地址由互联网服务提供商(ISP)分配给用户,可以唯一地标识全球设备,以实现互联网上的通信。
  • 内网 IP地址旨在用于组织内部网络,不会在全球互联网上路由,从而确保内部网络的安全。
1.1公网 IP

定义:公网 IP 是由互联网服务提供商(ISP)分配给你设备的 IP 地址,它是唯一的,且在互联网上是可以直接访问的。
作用:公网 IP 用于设备之间的通信,允许设备通过互联网相互访问。例如,当你访问一个网站时,浏览器会使用你的公网 IP 发送请求。

  1. 可以直接在互联网上被访问。
  2. 每个公网 IP 是唯一的,全球只有一个设备可以使用一个特定的公网 IP 地址。
  3. 公网 IP 的分配是有限的,IP 地址资源稀缺。
1.2 内网 IP

定义:内网 IP 是在局域网(LAN)内部使用的 IP 地址,它们不能在互联网上直接访问。内网设备可以通过 NAT(网络地址转换)技术与公网通信,但公网设备无法直接访问内网设备。

作用:内网 IP 用于局域网内设备之间的通信,通常由路由器通过 DHCP(动态主机配置协议)分配。

  1. 只能在局域网内使用,无法直接访问互联网。
  2. 由于内网 IP 地址的重复性,多个局域网可以使用相同的内网 IP 地址。
  3. 内网 IP地址范围是预定义的,常见的内网 IP 地址段有:
    Class A:10.0.0.0 ~ 10.255.255.255
    Class B:172.16.0.0 ~ 172.31.255.255
    Class C:192.168.0.0 ~ 192.168.255.255
1.3区分公网 IP 和内网 IP

可以通过以下几个步骤来分辨一个 IP 地址是公网 IP 还是内网 IP:

  • a. 查看 IP 地址是否在内网地址范围内
    内网 IP 地址有固定的地址段,如果某个 IP 地址属于以下任意一个范围,那么它就是内网 IP:
    10.0.0.0 ~ 10.255.255.255 (Class A)
    172.16.0.0 ~ 172.31.255.255 (Class B)
    192.168.0.0 ~ 192.168.255.255 (Class C)

  • b. 检查是否可通过外部访问
    如果你能够直接访问某个 IP 地址并且该地址位于互联网,那么它是公网 IP。
    内网 IP 地址只能在同一局域网内使用,无法通过互联网直接访问。

解决方案

拥有一台有公网IP的云服务器作为中转站,将局域网下的电脑将数据信息发送给中转的服务器,然后这个中转的服务器将收到的数据转给另外一台电脑,这样就可以实现两台电脑之间的互相通信。

原因:我们可以实现在局域网下的通信而不能在不是同一局域网下的通信是因为,不同的私网之间是无法通信的,我们使用的192.168.x.x都是私网,但是所有的私网却都可以和公网ip直接通信的。所以。想要在两个私网之间通信的话,我们就需要多一个步骤,也就是需要一个公网的IP作为中转站。

在这里插入图片描述

1云服务器

我的是阿里云服务器 当然只要是云服务器都可以
在这里插入图片描述

2 frp

2.1 云服务器上的配置

github下载frp网站:https://github.com/fatedier/frp/releases?page=5
因为我参考的文档使用的是0.33.0版本 我也就用了这个

ps:需要注意你的云服务器架构是什么

  • ARM架构下arm版本
  • x86_64架构选择amd 版本 我是这个版本的
    在这里插入图片描述
    可以使用命令下载:
wget https://github.com/fatedier/frp/releases/download/v0.33.0/frp_0.33.0_linux_amd64.tar.gz

然后解压缩:

tar xzvf frp_0.33.0_linux_amd64.tar.gz

将解压后的文件重命名:

mv frp_0.33.0_linux_amd64 frp       

查看文件内容:

cd frp
ls

frp 默认给出两个服务端配置文件,一个是简版的 frps.ini,另一个是完整版本 frps_full.ini。我们这里通过简版的 frps.ini配置,快速的搭建起一个 frp服务端。

查看frps.ini的配置:

cat frps.ini
#输出
[common]
bind_port = 7000 

由于默认配置中监听的是 7000 端口,但是用户可根据自己实际情况修改,我这里就没有修改了

启动frp服务端:

./frps -c ./frps.ini

输出:

root@iZ2vc4j4f5dy4g5cif3dnxZ:~/frp_set/frp# ./frps -c ./frps.ini
2025/02/20 14:13:02 [I] [service.go:178] frps tcp listen on 0.0.0.0:7000
2025/02/20 14:13:02 [I] [root.go:209] start frps success
2025/02/20 14:13:09 [I] [service.go:432] [e17730b293054812] client login info: ip [223.104.11.108:15309] version [0.33.0] hostname [] os [linux] arch [amd64]

在这里插入图片描述

2.2 云服务器上打开对应端口

可参考这个:https://blog.csdn.net/aa390481978/article/details/96837655
在这里插入图片描述
在这里插入图片描述

服务器配置

同样先下载,再解压,然后修改配置文件,之后启动
下载:

wget https://github.com/fatedier/frp/releases/download/v0.33.0/frp_0.33.0_linux_amd64.tar.gz

解压缩:

tar xzvf frp_0.33.0_linux_amd64.tar.gz

将解压后的文件重命名:

mv frp_0.33.0_linux_amd64 frp       

修改查看frpc.ini的配置:

[common]
server_addr = your_server_ip  # 公网服务器 IP 地址
server_port = 7000           # FRP 服务器端口

[ssh]
type = tcp
local_ip = 192.168.x.x       # 局域网电脑的 IP 地址
local_port = 23              # 局域网中要转发的服务端口(例如 SSH)
remote_port = 6001           # 在公网服务器上暴露的端口

server_addr是你服务器的公网ip
在这里插入图片描述

启动frp服务端:

./frpc -c ./frpc.ini

输出:

025/02/20 14:17:46 [I] [service.go:282] [c78168a348dd212e] login to server success, get run id [c78168a348dd212e], server udp port [0]
2025/02/20 14:17:46 [I] [proxy_manager.go:144] [c78168a348dd212e] proxy added: [ssh]
2025/02/20 14:17:46 [I] [control.go:179] [c78168a348dd212e] [ssh] start proxy success
客户端配置

同样先下载,再解压,然后修改配置文件,之后启动
下载:

wget https://github.com/fatedier/frp/releases/download/v0.33.0/frp_0.33.0_linux_amd64.tar.gz

解压缩:

tar xzvf frp_0.33.0_linux_amd64.tar.gz

将解压后的文件重命名:

mv frp_0.33.0_linux_amd64 frp       

修改查看frpc.ini的配置:

[common]
server_addr = your_server_ip  # 公网服务器 IP 地址
server_port = 7000           # FRP 服务器端口

[ssh]
type = tcp
local_ip = 192.168.x.x       # 局域网电脑的 IP 地址
local_port = 22              # 局域网中要转发的服务端口(例如 SSH)
remote_port = 6000           # 在公网服务器上暴露的端口

server_addr是你服务器的公网ip
在这里插入图片描述
启动frp服务端:

./frpc -c ./frpc.ini

输出:
在这里插入图片描述

注意事项
  • 1 客户端和服务器的local_port = 22,remote_port = 6000 要设置为不一致的
  • 2 客户端和服务器的名称也要设置为不一致的 ssh和ssh1
  • 3 云服务器打开对应端口
    ps:这边1,2设置为一致的是会导致 端口号 名称被占用的问题 但是按理说不应该 这边后续可以再试试
[W] [control.go:177] [0a1ee9193b4f3b0e] [ssh] start error: proxy name [ssh] is already in use
[W] [control.go:177] [0b9fe4453b7ae8ea] [ssh1] start error: port already used

3测试连接

配置完成后 测试客户端和服务器能否连接成功
下面是我的测试代码:

3.1 服务器
#include <iostream>
#include <cstring>
#include <unistd.h>
#include <arpa/inet.h>

int main() {
    const char* host_ip = "192.168.xx.xx";  // A 局域网服务器的内网 IP 地址
    int host_port = 23;  // 局域网服务端口

    // 创建 socket
    int server_socket = socket(AF_INET, SOCK_STREAM, 0);
    if (server_socket < 0) {
        std::cerr << "Socket creation failed!" << std::endl;
        return -1;
    }

    sockaddr_in server_address;
    server_address.sin_family = AF_INET;
    server_address.sin_port = htons(host_port);
    server_address.sin_addr.s_addr = inet_addr(host_ip);

    // 绑定并监听
    if (bind(server_socket, (sockaddr*)&server_address, sizeof(server_address)) < 0) {
        std::cerr << "Binding failed!" << std::endl;
        return -1;
    }

    if (listen(server_socket, 5) < 0) {
        std::cerr << "Listening failed!" << std::endl;
        return -1;
    }

    std::cout << "Server A is waiting for connections..." << std::endl;

    // 接受连接
    sockaddr_in client_address;
    socklen_t client_len = sizeof(client_address);
    int client_socket = accept(server_socket, (sockaddr*)&client_address, &client_len);
    if (client_socket < 0) {
        std::cerr << "Connection acceptance failed!" << std::endl;
        return -1;
    }

    std::cout << "Connection established with " << inet_ntoa(client_address.sin_addr) << std::endl;

    char buffer[1024];
    int bytes_received = recv(client_socket, buffer, sizeof(buffer), 0);  // 接收数据
    if (bytes_received > 0) {
        buffer[bytes_received] = '\0';
        std::cout << "Received from client: " << buffer << std::endl;
    }

    const char* response = "Hello, Client B!";
    send(client_socket, response, strlen(response), 0);  // 发送响应

    // 关闭连接
    close(client_socket);
    close(server_socket);

    return 0;
}

3.2 客户端
#include <iostream>
#include <cstring>
#include <unistd.h>
#include <arpa/inet.h>

int main() {
    const char* server_ip = "xx.xx.xx.xx";  // 云服务器的公网 IP
    int server_port = 6001;  // FRP 映射的端口

    // 创建 socket
    int client_socket = socket(AF_INET, SOCK_STREAM, 0);
    if (client_socket < 0) {
        std::cerr << "Socket creation failed!" << std::endl;
        return -1;
    }

    sockaddr_in server_address;
    server_address.sin_family = AF_INET;
    server_address.sin_port = htons(server_port);
    server_address.sin_addr.s_addr = inet_addr(server_ip);

    // 连接到服务器
    if (connect(client_socket, (sockaddr*)&server_address, sizeof(server_address)) < 0) {
        std::cerr << "Connection failed!" << std::endl;
        return -1;
    }

    const char* message = "Hello, Server A!";
    send(client_socket, message, strlen(message), 0);  // 发送数据

    char buffer[1024];
    int bytes_received = recv(client_socket, buffer, sizeof(buffer), 0);  // 接收数据
    if (bytes_received > 0) {
        buffer[bytes_received] = '\0';
        std::cout << "Received from server: " << buffer << std::endl;
    }

    // 关闭连接
    close(client_socket);

    return 0;
}
连接结果

在这里插入图片描述
在这里插入图片描述

注意事项
  • 服务器绑定的端口是23 小于1024 要切换到管理员状态 否则会绑定失败
    在这里插入图片描述

参考文章:
https://blog.csdn.net/weixin_44917390/article/details/106685219
https://blog.csdn.net/weixin_51354739/article/details/144422320
https://blog.csdn.net/qq_34623639/article/details/140506034

下个文章说一下frp具体是如何实现能够将客户端的连接准确转发给服务器的

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2303655.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringBoot教程(十四) SpringBoot之集成Redis

SpringBoot教程&#xff08;十四&#xff09; | SpringBoot之集成Redis 一、Redis集成简介二、集成步骤 2.1 添加依赖2.2 添加配置2.3 项目中使用之简单使用 &#xff08;举例讲解&#xff09;2.4 项目中使用之工具类封装 &#xff08;正式用这个&#xff09;2.5 序列化 &…

OpenHarmony分布式数据管理子系统

OpenHarmony分布式数据管理子系统 简介 目录 组件说明 分布式数据对象数据共享分布式数据服务Key-Value数据库首选项关系型数据库标准数据化通路 相关仓 简介 子系统介绍 分布式数据管理子系统支持单设备的各种结构化数据的持久化&#xff0c;以及跨设备之间数据的同步、…

单片机 Bootloade与二进制文件的生成

单片机的 Bootloader 是一种特殊的程序&#xff0c;负责在单片机上电后初始化硬件、更新用户应用程序&#xff08;固件&#xff09;&#xff0c;并将控制权移交给用户程序。以下是其运行机制和关键流程的详细说明&#xff1a; 1、单片机 Bootloader 的核心作用 固件更新&…

MySQL数据库(3)—— 表操作

目录 一&#xff0c;创建表 1.1 创建表的SQL 1.2 演示 二&#xff0c;查看表 三&#xff0c;修改表 四&#xff0c;删除表 常用的表操作会涉及到两种SWL语句 DDL&#xff08;Data Definition Language&#xff09;数据定义语言&#xff1a;建表、改表、删表等&#xff0…

Springboot + Ollama + IDEA + DeepSeek 搭建本地deepseek简单调用示例

1. 版本说明 springboot 版本 3.3.8 Java 版本 17 spring-ai 版本 1.0.0-M5 deepseek 模型 deepseek-r1:7b 需要注意一下Ollama的使用版本&#xff1a; 2. springboot项目搭建 可以集成在自己的项目里&#xff0c;也可以到 spring.io 生成一个项目 生成的话&#xff0c;如下…

七星棋牌源码高阶技术指南:6端互通、200+子游戏玩法深度剖析与企业级搭建实战(完全开源)

在棋牌游戏行业高速发展的今天&#xff0c;如何构建一个具备高并发、强稳定性与多功能支持的棋牌游戏系统成为众多开发者和运营团队关注的焦点。七星棋牌全开源修复版源码 凭借其 六端互通、200子游戏玩法、多省区本地化支持&#xff0c;以及 乐豆系统、防沉迷、比赛场、AI智能…

HarmonyOS 开发套件 介绍 ——上篇

HarmonyOS 开发套件 介绍 ——上篇 在当今科技飞速发展的时代&#xff0c;操作系统作为智能设备的核心&#xff0c;其重要性不言而喻。而HarmonyOS&#xff0c;作为华为推出的全新操作系统&#xff0c;正以其独特的魅力和强大的功能&#xff0c;吸引着越来越多的开发者和用户的…

网络空间安全(1)web应用程序的发展历程

前言 Web应用程序的发展历程是一部技术创新与社会变革交织的长卷&#xff0c;从简单的文档共享系统到如今复杂、交互式、数据驱动的平台&#xff0c;经历了多个重要阶段。 一、起源与初期发展&#xff08;1989-1995年&#xff09; Web的诞生&#xff1a; 1989年&#xff0c;欧洲…

JUC并发—9.并发安全集合三

大纲 1.并发安全的数组列表CopyOnWriteArrayList 2.并发安全的链表队列ConcurrentLinkedQueue 3.并发编程中的阻塞队列概述 4.JUC的各种阻塞队列介绍 5.LinkedBlockingQueue的具体实现原理 6.基于两个队列实现的集群同步机制 1.并发安全的数组列表CopyOnWriteArrayList …

Baklib云智协同:数字资产赋能企业效能跃升

内容概要 在数字化转型加速的背景下&#xff0c;Baklib通过构建智能化的知识中台架构&#xff0c;为企业打造了贯穿知识采集、整合、应用的全链路解决方案。该平台以动态知识图谱为核心技术底座&#xff0c;支持文档、音视频、代码等20余种格式的数字资产全生命周期管理&#…

wordpress adrotate插件 文件上传漏洞

当你爆破进wordpress后台但权限不是管理员的时&#xff0c;如果你有adrotate插件操作权限可以用adrotate的文件上传功能get webshell 该漏洞需要AdRotate版本 < 5.13.3 第一步按顺序点击上传文件 在这里文件一定要压缩成zip格式&#xff0c;上传的时候也是上传这个zip 上…

Python爬虫入门到精通:从零开始的数据采集之旅

一、网络世界的"小蜘蛛":什么是爬虫? 想象一下,你是一只勤劳的小蜘蛛,每天在互联网这张巨大的网上爬来爬去。你不需要自己织网,只需要顺着别人织好的网络路径,把有价值的信息收集到自己的小篮子里。这就是爬虫最形象的比喻——一个自动化的信息采集程序。 Py…

Transformer解析——(四)Decoder

本系列已完结&#xff0c;全部文章地址为&#xff1a; Transformer解析——&#xff08;一&#xff09;概述-CSDN博客 Transformer解析——&#xff08;二&#xff09;Attention注意力机制-CSDN博客 Transformer解析——&#xff08;三&#xff09;Encoder-CSDN博客 Transforme…

毕业项目推荐:基于yolov8/yolov5/yolo11的番茄成熟度检测识别系统(python+卷积神经网络)

文章目录 概要一、整体资源介绍技术要点功能展示&#xff1a;功能1 支持单张图片识别功能2 支持遍历文件夹识别功能3 支持识别视频文件功能4 支持摄像头识别功能5 支持结果文件导出&#xff08;xls格式&#xff09;功能6 支持切换检测到的目标查看 二、数据集三、算法介绍1. YO…

Blaze RangePartitioning 算子Native实现全解析

引言&#xff1a;本文将全面且深入地解析Blaze RangePartitioning算子的Native实现过程。相较于原生Spark&#xff0c;RangePartitioning的Native实现在执行时间上达到了30%的显著下降&#xff0c;同时在资源开销方面节省了高达76%。这一改进大幅降低了运行成本&#xff0c;展现…

1、Window Android 13模拟器 将编译的映像文件导入Android Studio

1、环境准备 编译环境&#xff1a;Ubuntu-18.04.5编译版本&#xff1a;android13-release下载地址&#xff1a;清华大学开源软件镜像站AOSP # 下载repo # 同步代码&#xff1a;repo init -u https://mirrors.tuna.tsinghua.edu.cn/git/AOSP/platform/manifest -b android13-r…

MTK-Android13-包安装器PackageInstaller 静默安装实现

目的 我们最终是为了搞明白安装的整个流程。一方面通过安卓系统自带的包安装器来了解PMS 安装流程&#xff1b;另一方面熟悉框架层Framework 针对Android apk 安装流程。 前两篇文章分析了PackagerInstaller 安装流程。 Android13-包安装器PackageInstaller-之apk安装跳转 An…

基于ffmpeg+openGL ES实现的视频编辑工具-opengl相关逻辑(五)

在我们的项目中,OpenGL ES 扮演着至关重要的角色,其主要功能是获取图像数据,经过一系列修饰后将处理结果展示到屏幕上,以此实现各种丰富多样的视觉效果。为了让大家更好地理解后续知识,本文将详细介绍 OpenGL 相关代码。需要注意的是,当前方案将对 OpenGL 的所有操作都集…

【数据库系统概论】第第12章 并发控制

12.1 并发控制概述 并发控制是指数据库管理系统&#xff08;DBMS&#xff09;通过控制多个事务同时执行&#xff0c;保证数据的一致性和隔离性&#xff0c;避免事务间的相互干扰。 事务串行执行不能充分利用系统资源 并发执行的优点&#xff1a;能够减少处理机的空闲 时间&a…

HTML应用指南:利用GET请求获取全国泸溪河门店位置信息

随着新零售业态的快速发展,门店位置信息的获取变得越来越重要。作为新兴烘焙品牌之一,泸溪河自2013年在南京创立以来,一直坚持“健康美味,香飘世界”的企业使命,以匠人精神打造新中式糕点。为了更好地理解和利用这些数据,本篇文章将深入探讨GET请求的实际应用,并展示如何…