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

【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具体是如何实现能够将客户端的连接准确转发给服务器的

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于Python+django+mysql旅游数据爬虫采集可视化分析推荐系统

2024旅游推荐系统爬虫可视化&#xff08;协同过滤算法&#xff09; 基于Pythondjangomysql旅游数据爬虫采集可视化分析推荐系统 有文档说明 部署文档 视频讲解 ✅️基于用户的协同过滤推荐算法 卖价就是标价~ 项目技术栈 Python语言、Django框架、MySQL数据库、requests网络爬虫…

基于 go-wrk 在 Windows 环境下对 Go Web 应用进行 HTTP 压力测试

基于 go-wrk 在 Windows 环境下对 Go Web 应用进行 HTTP 压力测试 这部分内容参考并搬运自 q1mi 老师的技术博客&#xff0c;原文的链接为&#xff1a;https://liwenzhou.com/posts/Go/benchmark-tools/。 压测相关术语 响应时间&#xff08;RT&#xff09;&#xff1a;指系…

CSS 媒体查询:从入门到精通,打造跨设备完美体验

在当今移动互联网时代&#xff0c;用户访问网站的设备早已不再局限于桌面电脑&#xff0c;手机、平板等各种屏幕尺寸的设备层出不穷。为了确保用户在不同设备上都能获得良好的浏览体验&#xff0c;响应式网页设计应运而生。而 CSS 媒体查询&#xff0c;正是实现响应式设计的核心…

如何在 macOS 上配置 MySQL 环境变量

如何在 macOS 上配置 MySQL 环境变量 步骤 1: 查找 MySQL 安装路径 打开终端&#xff0c;使用以下命令查找 mysql 的可执行文件路径&#xff1a; which mysql如果该命令没有返回结果&#xff0c;可以使用 find 命令&#xff1a; sudo find / -name "mysql" 2>/de…

Gin从入门到精通 (五)数据绑定与验证

数据绑定与验证 数据绑定是指将请求数据&#xff08;如 JSON、表单、URL 参数等&#xff09;绑定到 Go 语言中的结构体。Gin 提供了便捷的方法将请求中的数据映射到预定义的结构体字段上&#xff0c;使得开发者可以像访问结构体字段一样访问请求数据。 数据验证是对绑定到结构…

计算机毕业设计SpringBoot+Vue.jst网上超市系统(源码+LW文档+PPT+讲解)

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 作者简介&#xff1a;Java领…

【论文解读】《Training Large Language Models to Reason in a Continuous Latent Space》

论文链接 1. 背景与动机 语言空间与推理的矛盾 目前大多数大语言模型&#xff08;LLMs&#xff09;在解决复杂问题时采用链式思维&#xff08;Chain-of-Thought, CoT&#xff09;方法&#xff0c;即利用自然语言逐步推导出答案。然而&#xff0c;论文指出&#xff1a; 自然语言…

DevEco Studio常用快捷键以及如何跟AndroidStudio的保持同步

DevEco Studio快捷键 DevEco Studio是华为推出的用于开发HarmonyOS应用的集成开发环境&#xff0c;它提供了丰富的快捷键以提高开发效率&#xff0c;以下为你详细介绍不同操作场景下的常用快捷键&#xff1a; 通用操作快捷键 操作描述Windows/Linux 快捷键Mac 快捷键打开设置窗…

4. MySQL 逻辑架构说明

4. MySQL 逻辑架构说明 文章目录 4. MySQL 逻辑架构说明1. 逻辑架构剖析1.1 服务器处理客户端请求1.2 Connectors(连接器)1.3 第1层&#xff1a;连接层1.4 第2层&#xff1a;服务层1.5 第3层&#xff1a;引擎层1.6 存储层 2. SQL执行流程2.1 MySQL 中的 SQL 执行流程 2.2 MySQL…

基于 Python Django 的校园互助平台(附源码,文档)

博主介绍&#xff1a;✌Java徐师兄、7年大厂程序员经历。全网粉丝13w、csdn博客专家、掘金/华为云等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;&#x1f3fb; 不…

【CVPR2024-工业异常检测】PromptAD:与只有正常样本的少样本异常检测的学习提示

代码链接 摘要 摘要写作总结&#xff1a; 1.提出 两个关键点 &#xff08;视觉语言模型【模型】 少量工业异常检测【方向】&#xff09; 2.想要解决的问题 3.针对上述问题&#xff0c;本文提出了一种什么【方法】的什么【应用方面】方法【模型名】 4.具体讲方法的步骤 5.实验…

WPF框架学习

WPF 可以想winfrom 那样在cs文件修改 属性数据&#xff1b; 为了前后端分离 而解耦合&#xff0c;有了M-V-VM模式 常见框架有 MVVMlight / Prism 等 ------------------------------------------------------------------------------------- 一、前提&#xff1a;有一定基…

网络运维学习笔记 017 HCIA-Datacom综合实验01

文章目录 综合实验1实验需求总部特性 分支8分支9 配置一、 基本配置&#xff08;IP二层VLAN链路聚合&#xff09;ACC_SWSW-S1SW-S2SW-Ser1SW-CoreSW8SW9DHCPISPGW 二、 单臂路由GW 三、 vlanifSW8SW9 四、 OSPFSW8SW9GW 五、 DHCPDHCPGW 六、 NAT缺省路由GW 七、 HTTPGW 综合实…

git,bash - 从一个远端git库只下载一个文件的方法

文章目录 git,bash - 从一个远端git库只下载一个文件的方法概述笔记写一个bash脚本来自动下载get_github_raw_file_from_url.shreanme_file.shfind_key_value.sh执行命令 END git,bash - 从一个远端git库只下载一个文件的方法 概述 github上有很多大佬上传了电子书库&#xf…

【废物研究生零基础刷算法】DFS与递归(一)典型题型

文章目录 跳台阶递归实现指数级枚举递归实现排列型枚举上面两题总结 递归实现组合型枚举P1036选数 跳台阶 思路&#xff1a; 如果 n 1&#xff0c;只有一种走法&#xff08;走 1 级&#xff09;。如果 n 2&#xff0c;有两种走法&#xff08;11 或 2&#xff09;。对于 n &g…

Java-01-源码篇-04集合-05-ConcurrentHashMap(1)

1.1 加载因子 加载因子&#xff08;Load Factor&#xff09;是用来决定什么时候需要扩容的一个参数。具体来说&#xff0c;加载因子 当前元素数量 / 桶的数量&#xff0c;当某个桶的元素个数超过了 桶的数量 加载因子 时&#xff0c;就会触发扩容。 我们都知道 ConcurrentHas…

AI赋能的未来城市:如何用智能化提升生活质量?

这会是我们憧憬的未来城市吗&#xff1f; 随着技术的不断进步和城市化进程的加速&#xff0c;现代城市面临着诸多挑战——交通拥堵、环境污染、能源消耗、人口老龄化等问题愈发突出。为了应对这些挑战&#xff0c;建设智慧城市已成为全球发展的重要趋势。在这一进程中&#xf…

DeepSeek各模型现有版本对比分析

文章目录 一、基础模型系列&#xff1a;V1 到 V3 的演进二、专用模型系列&#xff1a;推理与多模态三、版本选型与商业化趋势 DeepSeek作为最近特别火爆的模型&#xff0c;本文将对DeepSeek现有的主要版本进行对比分析,涵盖参数规模、训练数据、功能改进、应用场景和性能表现等…

【亲测有效】百度Ueditor富文本编辑器添加插入视频、视频不显示、和插入视频后二次编辑视频标签不显示,显示成img标签,二次保存视频被替换问题,解决方案

【亲测有效】项目使用百度Ueditor富文本编辑器上传视频相关操作问题 1.百度Ueditor富文本编辑器添加插入视频、视频不显示 2.百度Ueditor富文本编辑器插入视频后二次编辑视频标签不显示&#xff0c;在编辑器内显示成img标签&#xff0c;二次保存视频被替换问题 问题1&#xff1…

hot100_108. 将有序数组转换为二叉搜索树

hot100_108. 将有序数组转换为二叉搜索树 思路 给你一个整数数组 nums &#xff0c;其中元素已经按 升序 排列&#xff0c;请你将其转换为一棵 平衡 二叉搜索树。 示例 1&#xff1a; 输入&#xff1a;nums [-10,-3,0,5,9] 输出&#xff1a;[0,-3,9,-10,null,5] 解释&#…