|
package main |
|
|
|
import ( |
|
"flag" |
|
"fmt" |
|
"net" |
|
"os" |
|
"strconv" |
|
"time" |
|
) |
|
|
|
func main() { |
|
// Parse command-line flags |
|
port := flag.Int("port", 8080, "Port to listen on") |
|
closeType := flag.String("close", "graceful", "Type of close: 'graceful', 'immediate', or 'half'") |
|
delayBeforeClose := flag.Int("delay", 3, "Seconds to wait before closing connection") |
|
flag.Parse() |
|
|
|
// Create listener |
|
addr := ":" + strconv.Itoa(*port) |
|
listener, err := net.Listen("tcp", addr) |
|
if err != nil { |
|
fmt.Printf("Failed to listen on %s: %v\n", addr, err) |
|
os.Exit(1) |
|
} |
|
defer listener.Close() |
|
|
|
fmt.Printf("Server listening on %s\n", addr) |
|
fmt.Printf("Close type: %s with %d seconds delay\n", *closeType, *delayBeforeClose) |
|
|
|
for { |
|
// Wait for a connection |
|
conn, err := listener.Accept() |
|
if err != nil { |
|
fmt.Printf("Error accepting connection: %v\n", err) |
|
continue |
|
} |
|
|
|
// Handle connection in a new goroutine |
|
go handleConnection(conn, *closeType, *delayBeforeClose) |
|
} |
|
} |
|
|
|
func handleConnection(conn net.Conn, closeType string, delaySeconds int) { |
|
defer func() { |
|
fmt.Println("Connection handler completed") |
|
}() |
|
|
|
// Log client connection |
|
remoteAddr := conn.RemoteAddr().String() |
|
fmt.Printf("New connection from: %s\n", remoteAddr) |
|
|
|
// Write initial message |
|
initialMsg := "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nConnection: close\r\n\r\nStarting data transmission...\n" |
|
_, err := conn.Write([]byte(initialMsg)) |
|
if err != nil { |
|
fmt.Printf("Error sending initial message: %v\n", err) |
|
conn.Close() |
|
return |
|
} |
|
|
|
// Start a goroutine to read from the connection |
|
go func() { |
|
buffer := make([]byte, 1024) |
|
for { |
|
n, err := conn.Read(buffer) |
|
if err != nil { |
|
fmt.Printf("Read from client error: %v\n", err) |
|
return |
|
} |
|
if n > 0 { |
|
fmt.Printf("Received %d bytes from client: %s\n", n, string(buffer[:n])) |
|
} |
|
} |
|
}() |
|
|
|
// Send some data periodically |
|
dataCount := 0 |
|
ticker := time.NewTicker(500 * time.Millisecond) |
|
defer ticker.Stop() |
|
|
|
// Set timer for connection close |
|
timer := time.NewTimer(time.Duration(delaySeconds) * time.Second) |
|
defer timer.Stop() |
|
|
|
for { |
|
select { |
|
case <-ticker.C: |
|
dataCount++ |
|
data := fmt.Sprintf("Data packet #%d sent at %s\n", dataCount, time.Now().Format(time.RFC3339)) |
|
_, err := conn.Write([]byte(data)) |
|
if err != nil { |
|
fmt.Printf("Error sending data: %v\n", err) |
|
return |
|
} |
|
fmt.Printf("Sent packet #%d to %s\n", dataCount, remoteAddr) |
|
|
|
case <-timer.C: |
|
fmt.Printf("Time to close connection to %s using %s method\n", remoteAddr, closeType) |
|
|
|
switch closeType { |
|
case "graceful": |
|
// Graceful close - close the connection normally |
|
fmt.Println("Performing graceful close") |
|
conn.Close() |
|
return |
|
|
|
case "immediate": |
|
// Immediate close - set linger to 0 and close |
|
fmt.Println("Performing immediate close (with RST)") |
|
tcpConn := conn.(*net.TCPConn) |
|
tcpConn.SetLinger(0) // Send RST instead of FIN |
|
conn.Close() |
|
return |
|
|
|
case "half": |
|
// Half-close - shutdown write side only |
|
fmt.Println("Performing half-close (shutdown write side)") |
|
tcpConn := conn.(*net.TCPConn) |
|
tcpConn.CloseWrite() |
|
|
|
// Keep reading from client after half-close |
|
fmt.Println("Server is now only reading (half-closed state)") |
|
buffer := make([]byte, 1024) |
|
for { |
|
n, err := conn.Read(buffer) |
|
if err != nil { |
|
fmt.Printf("Read after half-close error: %v\n", err) |
|
conn.Close() // Finally close the connection completely |
|
return |
|
} |
|
fmt.Printf("After half-close, received %d bytes: %s\n", n, string(buffer[:n])) |
|
} |
|
|
|
default: |
|
fmt.Printf("Unknown close type: %s\n", closeType) |
|
conn.Close() |
|
return |
|
} |
|
} |
|
} |
|
} |