You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何获取TCP服务器中客户端连接使用的域名地址

Great question! The key thing to realize here is that TCP itself doesn't carry domain name information—it operates at the transport layer, only knowing the client's IP address and port. The domain name you're targeting (test.127.0.0.1.xip.io) is resolved to an IP before the TCP connection is even established, so that detail isn't part of the raw TCP handshake.

Here are the most common solutions depending on what kind of traffic your server is handling:

1. If you're dealing with HTTP traffic

Since you tested with a URL (http://test.127.0.0.1.xip.io:3333/), this is likely your case. HTTP requests include a Host header that specifies the domain the client intended to reach. You have two options here:

Option A: Convert your TCP server to an HTTP server

Go's standard net/http package makes this straightforward. Here's how to modify your code:

package main

import (
	"fmt"
	"net/http"
	"os"
)

const (
	CONN_HOST = "localhost"
	CONN_PORT = "3333"
)

func main() {
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		// Get the domain from the Host header
		clientDomain := r.Host
		fmt.Printf("Client connected using domain: %s\n", clientDomain)
		w.Write([]byte("Message received."))
	})

	fmt.Println("Listening on " + CONN_HOST + ":" + CONN_PORT)
	err := http.ListenAndServe(CONN_HOST+":"+CONN_PORT, nil)
	if err != nil {
		fmt.Println("Error listening:", err.Error())
		os.Exit(1)
	}
}

Option B: Parse HTTP manually in your existing TCP server

If you need to keep the raw TCP server but still handle HTTP traffic, you can parse the incoming request to extract the Host header:

package main

import (
	"fmt"
	"net"
	"os"
	"strings"
)

const (
	CONN_HOST = "localhost"
	CONN_PORT = "3333"
	CONN_TYPE = "tcp"
)

func main() {
	l, err := net.Listen(CONN_TYPE, CONN_HOST+":"+CONN_PORT)
	if err != nil {
		fmt.Println("Error listening:", err.Error())
		os.Exit(1)
	}
	defer l.Close()
	fmt.Println("Listening on " + CONN_HOST + ":" + CONN_PORT)
	for {
		conn, err := l.Accept()
		if err != nil {
			fmt.Println("Error accepting: ", err.Error())
			os.Exit(1)
		}
		go handleRequest(conn)
	}
}

func handleRequest(conn net.Conn) {
	buf := make([]byte, 1024)
	_, err := conn.Read(buf)
	if err != nil {
		fmt.Println("Error reading:", err.Error())
		conn.Close()
		return
	}

	// Parse the HTTP request to extract the Host header
	requestStr := string(buf)
	lines := strings.Split(requestStr, "\r\n")
	for _, line := range lines {
		if strings.HasPrefix(line, "Host: ") {
			clientDomain := strings.TrimPrefix(line, "Host: ")
			fmt.Printf("Client connected using domain: %s\n", clientDomain)
			break
		}
	}

	conn.Write([]byte("Message received."))
	conn.Close()
}

2. If you're dealing with HTTPS (TLS) traffic

If your server uses TLS, clients will send an SNI (Server Name Indication) during the TLS handshake, which includes the domain they're trying to reach. You can access this with Go's crypto/tls package:

package main

import (
	"crypto/tls"
	"fmt"
	"net"
	"os"
)

const (
	CONN_HOST = "localhost"
	CONN_PORT = "3333"
)

func main() {
	// Load your TLS certificate and private key (use self-signed for testing)
	cert, err := tls.LoadX509KeyPair("server.crt", "server.key")
	if err != nil {
		fmt.Println("Error loading cert/key:", err.Error())
		os.Exit(1)
	}

	config := &tls.Config{Certificates: []tls.Certificate{cert}}
	l, err := tls.Listen("tcp", CONN_HOST+":"+CONN_PORT, config)
	if err != nil {
		fmt.Println("Error listening:", err.Error())
		os.Exit(1)
	}
	defer l.Close()

	fmt.Println("Listening on " + CONN_HOST + ":" + CONN_PORT)
	for {
		conn, err := l.Accept()
		if err != nil {
			fmt.Println("Error accepting:", err.Error())
			continue
		}
		// Type assert to tls.Conn to access SNI data
		if tlsConn, ok := conn.(*tls.Conn); ok {
			if err := tlsConn.Handshake(); err == nil {
				clientDomain := tlsConn.ConnectionState().ServerName
				fmt.Printf("Client connected using domain: %s\n", clientDomain)
			}
		}
		go handleRequest(conn)
	}
}

func handleRequest(conn net.Conn) {
	buf := make([]byte, 1024)
	_, err := conn.Read(buf)
	if err != nil {
		fmt.Println("Error reading:", err.Error())
	}
	conn.Write([]byte("Message received."))
	conn.Close()
}

3. If you're using a custom TCP protocol

If you're not relying on HTTP/HTTPS, you'll need to modify your client to explicitly send the domain name right after establishing the TCP connection. Then your server can read this value first before processing other data:

  • Client side: After connecting, send the domain string (e.g., append a newline to mark the end: test.127.0.0.1.xip.io\n)
  • Server side: In handleRequest, first read the domain from the connection buffer before handling other payloads.

Why your original code didn't work

The net.Conn object only exposes transport-layer details (like conn.RemoteAddr() for the client's IP:port). Since the domain is resolved to an IP address before the TCP connection is initiated, that information isn't preserved in the TCP layer—it's up to the application layer (HTTP, TLS, or your custom protocol) to pass along the domain name.

内容的提问来源于stack exchange,提问作者Romeo Mihalcea

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 18:42:50