Class TCPServer

java.lang.Object
java.lang.Thread
com.ns.tcpframework.TCPServer
All Implemented Interfaces:
Runnable

public class TCPServer extends Thread
A multithreaded TCP server that listens for incoming client connections and delegates request handling.

This server implementation extends Thread to run asynchronously and provides the foundation for the HTTP server. It handles the TCP/IP layer of communication, accepting incoming socket connections and delegating HTTP request processing to an HTTPHandler.

Key features:

  • Non-blocking server operation on a dedicated thread
  • Thread pool-based request handling for efficient concurrency
  • Graceful shutdown with proper resource cleanup
  • Integration with ServerLogger for operational logging
  • Support for virtual threads via configurable ExecutorService

Architecture:

  1. Server socket binds to the specified TCP port
  2. Main server thread continuously accepts incoming connections
  3. Each accepted connection is submitted to the thread pool
  4. HTTPHandler processes the request in a worker thread
  5. Socket cleanup is handled automatically after request processing

Lifecycle:

// Create server instance
ExecutorService pool = Executors.newVirtualThreadPerTaskExecutor();
TCPServer server = new TCPServer(8080, httpHandler, pool);

// Start server (non-blocking)
server.start();

// Server is now accepting connections...

// Graceful shutdown
server.stopServer();

Thread-safety: This class is designed to be instantiated once and started on a single thread. The accept loop runs on the server's thread while request handling is distributed across the thread pool. The stopServer() method can be called from any thread to initiate graceful shutdown.

Error handling: The server catches and handles SocketException during shutdown, and logs other exceptions that occur during operation. The server will continue running even if individual request handling fails.

See Also:
  • Constructor Details

    • TCPServer

      public TCPServer(int port, HTTPHandler handlerObject, ExecutorService pool) throws Exception
      Constructs a TCPServer instance with the specified port, handler, and thread pool.

      This constructor initializes the server socket and binds it to the specified port. The server is not started automatically; Thread.start() must be called to begin accepting connections.

      Port binding considerations:

      • Ports below 1024 typically require root/administrator privileges
      • The port must not be in use by another process
      • Port 0 can be used to automatically select an available port
      • Common HTTP ports: 80 (HTTP), 443 (HTTPS), 8080 (alternative HTTP)

      The thread pool should be configured based on expected load and concurrency model:

      • Virtual threads: Executors.newVirtualThreadPerTaskExecutor() - Recommended for high concurrency
      • Fixed thread pool: Executors.newFixedThreadPool(n) - For controlled resource usage
      • Cached thread pool: Executors.newCachedThreadPool() - For varying load
      Parameters:
      port - The TCP port number on which the server will listen for connections. Must be in the range 0-65535. Port 0 allows automatic port selection.
      handlerObject - The HTTPHandler instance to process client requests. Must not be null.
      pool - The ExecutorService for handling requests concurrently. Must not be null and should be in a running state.
      Throws:
      IOException - If the server socket cannot be created or bound to the specified port. Common causes: port already in use, insufficient permissions, invalid port number.
      Exception - If any other error occurs during server initialization.
  • Method Details

    • run

      public void run()
      Starts the server and continuously listens for incoming client connections.

      This method implements the main server loop that:

      1. Logs server startup with the bound port number
      2. Enters an infinite accept loop waiting for client connections
      3. Accepts each connection and submits it to the thread pool for processing
      4. Continues accepting new connections even if individual requests fail
      5. Exits gracefully when stopServer() is called

      The accept loop is blocking - when no connections are pending, the thread waits until a client connects. This is efficient as it doesn't consume CPU while waiting.

      Error handling:

      • SocketException - Expected during shutdown when socket is closed, silently ignored as it's part of normal shutdown procedure
      • Other exceptions - Logged to standard error but server continues attempting to accept connections

      This method runs on the server's thread (not the calling thread) since TCPServer extends Thread. Call server.start() to begin execution, not server.run().

      Note: This method contains German comments in the exception handlers from the original implementation explaining exception handling behavior.

      Specified by:
      run in interface Runnable
      Overrides:
      run in class Thread
    • stopServer

      public void stopServer()
      Initiates graceful shutdown of the server.

      This method performs an orderly shutdown sequence:

      1. Closes the server socket, which causes the accept loop to exit with a SocketException
      2. Shuts down the thread pool, preventing new tasks from being submitted
      3. Prints a shutdown confirmation message to standard output

      Shutdown behavior:

      • New connections are immediately rejected once the socket is closed
      • The server thread (running run()) will exit after socket closure
      • The thread pool begins orderly shutdown (completes submitted tasks but accepts no new ones)
      • In-progress requests are allowed to complete before the pool terminates

      This method can be safely called from any thread and can be invoked multiple times (subsequent calls have no effect as the socket is already closed).

      Thread pool shutdown: The method calls ExecutorService.shutdown() rather than shutdownNow(), allowing graceful completion of in-flight requests. If immediate termination is required, additional logic should be added to interrupt worker threads.

      IOException handling: Any IOException thrown during socket closure is silently ignored since shutdown is already in progress and the exception doesn't affect the outcome.