Step 01 of 06
Learn the concept
A green DNS check only says you found an address. It says nothing about whether port 443 is listening, whether a firewall drops packets, or whether replies can get back. TCP connect is the first proof that the path works in both directions.
The ideas this is made of
The port is part of the destination
example.com is not enough to dial. TCP needs a destination IP and destination port, while the operating system chooses an ephemeral source port for this one connection. The resulting four-tuple identifies the socket. That is why example.com:443 can work while example.com:81 refuses or times out on the same host.
The handshake proves bidirectional reachability
TCP opens with SYN, SYN-ACK, ACK. The server's SYN-ACK proves the client's packet arrived and a reply could return. After the final ACK, both sides agree on sequence numbers for a reliable byte stream. Connect time is usually about one round trip, plus kernel queues, packet loss retries and load-balancer delay.
Different connect errors name different failure shapes
connection refused is an active no: something reachable rejected the port, often with RST. i/o timeout is silence: packets left, but no useful reply arrived before the deadline. network is unreachable usually means the local stack or a router had no route. Those strings are not cosmetics. They decide who investigates first.
Address fallback keeps one bad answer from deciding the check
DNS can return IPv4 and IPv6 addresses, and not all are reachable from every network. Good clients try alternatives; many use Happy Eyeballs to avoid long IPv6 stalls. Beacon's first version is simpler: try resolved addresses in order and report the one that connected. Even that beats pretending the first address was the only truth.
Closing the connection is part of the measurement
A TCP socket holds kernel state, a file descriptor and often server-side state. A prober opens short-lived sockets all day. Leak a few per minute and the machine eventually hits too many open files or runs out of ephemeral ports. defer conn.Close() belongs immediately after a successful dial, before later code finds a new way to return early.
package main
import (
"context"
"fmt"
"net"
"time"
)
func main() {
dialer := net.Dialer{}
start := time.Now()
conn, err := dialer.DialContext(context.Background(), "tcp", "example.com:443")
elapsed := time.Since(start)
if err != nil {
fmt.Println("connect failed:", err)
return
}
defer conn.Close()
fmt.Println("connected in:", elapsed)
fmt.Println("remote:", conn.RemoteAddr())
}This opens TCP and stops. No TLS handshake. No HTTP request. The output answers one question: did this address and port accept a connection from this machine, and how long did that proof take?
Connect outcomes that look similar in dashboards
| Outcome | What happened | Usual first suspect |
|---|---|---|
Connected | Handshake completed | Move to TLS or HTTP |
Refused | Peer actively said no | Listener or port policy |
Timed out | No useful reply | Firewall, route or loss |
Unreachable | No route known | Local network or routing |
What these are called on the job
Port — A service number on a host. HTTPS normally uses TCP
443.SYN — The TCP segment that starts connection establishment.
RTT — Round-trip time: a packet there and a reply back.
RST — A TCP reset, commonly seen when a port is actively refused.
Happy Eyeballs — A client strategy that avoids long delays when one address family is broken.
