在 Go 语言里编写 TCP 服务或者基于 TCP 的 HTTP 服务时,服务端经常需要识别发起连接的客户端地址。Go 的标准库通过 net.Conn 抽象了连接对象,我们可以从中取出对端的网络地址并解析出 IP 与端口。

从 net.Conn 获取远程地址
每一个接入的 TCP 连接在实现上都是一个 net.Conn 接口实例。该接口提供了 RemoteAddr 方法,返回值是 net.Addr 接口,里面包含了网络类型和地址字符串。
类型断言到 *net.TCPAddr
由于我们需要具体的 IP 和端口,应当把 net.Addr 断言为 *net.TCPAddr,这样就能直接访问 IP 和 Port 字段。
package main
import (
"fmt"
"net"
)
func handleConn(conn net.Conn) {
defer conn.Close()
// 获取远程地址接口
remote := conn.RemoteAddr()
// 类型断言为 TCPAddr
tcpAddr, ok := remote.(*net.TCPAddr)
if !ok {
fmt.Println("不是 TCP 连接")
return
}
// 分别获取 IP 和端口
clientIP := tcpAddr.IP.String()
clientPort := tcpAddr.Port
fmt.Printf("客户端 IP: %s, 端口: %dn", clientIP, clientPort)
}
func main() {
ln, err := net.Listen("tcp", ":8080")
if err != nil {
panic(err)
}
defer ln.Close()
for {
conn, err := ln.Accept()
if err != nil {
continue
}
go handleConn(conn)
}
}
直接通过字符串解析
如果不想做类型断言,也可以调用 Address 的 String 方法拿到形如 192.168.0.1:54321 的字符串,再用 net.SplitHostPort 拆分。
package main
import (
"fmt"
"net"
)
func printClient(addr net.Addr) {
host, port, err := net.SplitHostPort(addr.String())
if err != nil {
fmt.Println("解析地址失败:", err)
return
}
fmt.Printf("host=%s port=%sn", host, port)
}
常见误区
- 在 HTTP 服务中直接读 http.Request.RemoteAddr 可能拿到代理 IP,真实客户端需在 X-Forwarded-For 或 X-Real-IP 头里获取。
- 把 RemoteAddr 字符串当 IP 使用,忘记端口部分会导致逻辑错误。
- 未做类型断言就直接访问 Port 字段,会引发编译错误。
总结
在 Go 中正确获取 TCP 客户端 IP 和端口的核心是使用 conn.RemoteAddr 并转为 *net.TCPAddr,或者借助 net.SplitHostPort 解析字符串。理解这两种方式能避免地址处理上的常见 bug,让服务端逻辑更加健壮。
GoTCPclient_IP_port修改时间:2026-07-26 02:39:09