使用go做一个返回公网IP的web服务

简介: 使用go做一个返回公网IP的web服务

在我们日常运维中,特别是在云服务器环境下,其使用基本上都是弹性网卡,所以使用ip a只能获取其内网地址,若想要获取其公网ip,除了上云平台查看机器信息以外,只有通过其他服务来协助返回公网地址了。



我们应该如何获取公网地址


前些天,我们已经看了http相关基础报文,我们可以知晓,从http报文而言来看,我们是无法获取其来访者IP的,那么我们究竟应当如何获取呢?


那在报文中,哪里有记录来访者IP呢? 答案是TCP/IP4层协议中的网络层中有定义源IP地址和目标IP地址,其报文架构大致如下:


下图来源于: rfc791 网址: www.rfc-editor.org/rfc/rfc791

image.png


我们能够直接在应用中获取其IP层的数据么?答案是不能的,因为网络包来了,若只有IP层的数据,这是给哪个进程的呢? 所以这个时候就需要引入我们的传输层的TCP报文协议了。

下图来源于: rfc793 网址: www.rfc-editor.org/rfc/rfc793.…


image.png

可以看到,在IP报文的基础上,TCP报文又定义了源端口 和 目标端口,端口是为了解决不同主机和不通进程之间的通信所建立的规则,结合起来可以形成一个四元组,即: 源IP地址,源端口号 | 目标IP地址,目标端口号,这个我们也称之为是TCP套接字四元组


所以,回到问题,返回来访者IP地址,我们就将其四元组的信息返回回去就可以了。



编写返回来访者IP的web服务


根据上述信息,我们可以直接编写一个tcpdemo,返回源IP数据。

package main
import (
  "fmt"
  "net"
  "time"
)
func main() {
  l , _ := net.Listen("tcp","0.0.0.0:8082")
  conn , _ := l.Accept()
  fmt.Println("来访者IP:" , conn.RemoteAddr().String())
  time.Sleep(3 * time.Second)
}


我们将其程序执行后,可得直接如下


image.png


我们可以来分析下,该TCP套接字四元组信息是什么,首先,服务器端口是8082,而服务器IP监听所有的网卡,根据客户端的信息,暂时定义为127.0.0.1 , 而客户端端口为54953,客户端IP为127.0.0.1,所以可以这样理解为


源IP地址 源端口号 目标IP地址 目标端口号
127.0.0.1 54953 127.0.0.1 8082

这里的54953端口是客户端临时使用的,使用完后会撤销回去,怎么? 你不认为这2个确实建立了连接? 那我们可以测试下,使用netstat命令可以查看TCP连接信息,我们暂时将代码中time.Sleep(3 * time.Second) 给修改为time.Sleep(30 * time.Second) ,以便于我们稍后观察。即程序如下:

image.png



我们将转移阵地到linux环境下测试代码。

启动服务器后,我们使用curl 127.0.0.1:8082来访问其数据。

image.png

会得到客户端的端口号,我们将在其没有没有close连接的时候,我们使用netstat -an | grep 39440可以查询TCP连接信息。

image.png


其中-a参数是显示网卡所有的连接信息,-n是显示ip地址,而非主机名。


那我们要返回其来访者IP地址,并将其打造为web服务,那也简单,我们仅需嵌套一层http报文就行了。


我们将其程序改写如下即可。

package main
import (
  "fmt"
  "net"
  "strings"
)
func main() {
  l , err := net.Listen("tcp","0.0.0.0:8082");if err != nil {
    panic(err)
  }
  for {
    conn , err := l.Accept();if err != nil {
      continue
    }
    ip := strings.Split(conn.RemoteAddr().String(),":")[0]
    conn.Write([]byte(fmt.Sprintf("HTTP/1.1 200 OK\r\nContent-Length: %d\r\n\r\n%s",len(ip),ip)))
  }
}


如上代码,在服务器启动后,使用curl IP:8082后可以得到IP地址,我们尝试一下。

image.png

若是放在公网上,则显示的是公网的地址信息。



关于反向代理如何获取地址


反向代理是一个很有意思的事情,我们通过如上方法,若经过代理,我们所获取的remoteIP则是代理服务器的ip,而非客户端Ip,流程如下图。


image.png


那么如何解决这个问题呢? 很显然,修改网络层报文,这个是很不现实的,也是不可能的,所以我们可以另辟蹊径,由于我们做的是web服务器,所以我们可以在代理服务器上设置将客户端的remoteIP添加到请求报文中去,一同发给真实web服务器,而服务器拿到后,则不从TCP套接字获取IP,而直接从http报文获取IP即可,这个只要代理服务器和真实web服务器将相关规则约定好即可,我们拿nginx举例:


image.png

例如我们配置如上,那么在真实web服务器就应该使用请求头为X-Real-IP来获取客户端IP地址。



总结


返回来访者IP地址,在很多业务场景,尤其是目前云服务器中。在获取过程中,我们可以将其分为2种,第一种是web服务器直接面对客户端,第二种是经过一层代理服务器,不管怎么样,我们都需要从tcp请求中获取客户端的地址,经过某种方式,从而返回给客户端,怎么样,好玩吧,快来试试吧。


相关文章
|
2月前
|
XML JSON 安全
Web服务是通过标准化的通信协议和数据格式
【10月更文挑战第18天】Web服务是通过标准化的通信协议和数据格式
163 69
|
25天前
|
中间件 Go API
Go语言中几种流行的Web框架,如Beego、Gin和Echo,分析了它们的特点、性能及适用场景,并讨论了如何根据项目需求、性能要求、团队经验和社区支持等因素选择最合适的框架
本文概述了Go语言中几种流行的Web框架,如Beego、Gin和Echo,分析了它们的特点、性能及适用场景,并讨论了如何根据项目需求、性能要求、团队经验和社区支持等因素选择最合适的框架。
66 1
|
1月前
|
Go UED
Go Web服务中如何优雅平滑重启?
在生产环境中,服务升级时如何确保不中断当前请求并应用新代码是一个挑战。本文介绍了如何使用 Go 语言的 `endless` 包实现服务的优雅重启,确保在不停止服务的情况下完成无缝升级。通过示例代码和测试步骤,详细展示了 `endless` 包的工作原理和实际应用。
42 3
|
1月前
|
JSON Go UED
Go Web服务中如何优雅关机?
在构建 Web 服务时,优雅关机是一个关键的技术点,它确保服务关闭时所有正在处理的请求都能顺利完成。本文通过一个简单的 Go 语言示例,展示了如何使用 Gin 框架实现优雅关机。通过捕获系统信号和使用 `http.Server` 的 `Shutdown` 方法,我们可以在服务关闭前等待所有请求处理完毕,从而提升用户体验,避免数据丢失或不一致。
24 1
|
1月前
|
缓存 前端开发 中间件
go语言中Web框架
【10月更文挑战第22天】
44 4
|
1月前
|
XML 安全 PHP
PHP与SOAP Web服务开发:基础与进阶教程
本文介绍了PHP与SOAP Web服务的基础和进阶知识,涵盖SOAP的基本概念、PHP中的SoapServer和SoapClient类的使用方法,以及服务端和客户端的开发示例。此外,还探讨了安全性、性能优化等高级主题,帮助开发者掌握更高效的Web服务开发技巧。
|
2月前
|
XML JSON 安全
定义Web服务
【10月更文挑战第18天】定义Web服务
70 12
|
1月前
【Azure App Service】PowerShell脚本批量添加IP地址到Web App允许访问IP列表中
Web App取消公网访问后,只允许特定IP能访问Web App。需要写一下段PowerShell脚本,批量添加IP到Web App的允许访问IP列表里!
|
2月前
|
XML JSON API
ServiceStack:不仅仅是一个高性能Web API和微服务框架,更是一站式解决方案——深入解析其多协议支持及简便开发流程,带您体验前所未有的.NET开发效率革命
【10月更文挑战第9天】ServiceStack 是一个高性能的 Web API 和微服务框架,支持 JSON、XML、CSV 等多种数据格式。它简化了 .NET 应用的开发流程,提供了直观的 RESTful 服务构建方式。ServiceStack 支持高并发请求和复杂业务逻辑,安装简单,通过 NuGet 包管理器即可快速集成。示例代码展示了如何创建一个返回当前日期的简单服务,包括定义请求和响应 DTO、实现服务逻辑、配置路由和宿主。ServiceStack 还支持 WebSocket、SignalR 等实时通信协议,具备自动验证、自动过滤器等丰富功能,适合快速搭建高性能、可扩展的服务端应用。
151 3
|
1月前
|
设计模式 前端开发 数据库
Python Web开发:Django框架下的全栈开发实战
【10月更文挑战第27天】本文介绍了Django框架在Python Web开发中的应用,涵盖了Django与Flask等框架的比较、项目结构、模型、视图、模板和URL配置等内容,并展示了实际代码示例,帮助读者快速掌握Django全栈开发的核心技术。
162 45