TCP (Transmission Control Protocol) is a fundamental protocol that enables reliable communication between two computers over a network. In Java's standard library, two key classes facilitate TCP-based communication: the ServerSocket class for server-side operations and the Socket class for client-side operations.
The ServerSocket class binds to a specific port on the server machine and listens for incoming connection requests from clients. When a client connects, the server creates a corresponding Socket object to handle communication with that particular client.
Key Methods of the Client Socket
| Method Signature | Description |
|---|---|
int getPort() |
Returns the port number on the remote server to which this socket is connected |
InetAddress getLocalAddress() |
Returns the local IP address to which the socket is bound, wrapped in an InetAddress object |
void close() |
Closes the socket connection and terminates communication. All associated input/output streams should be closed beforehand to ensure proper resource cleanup |
InputStream getInputStream() |
Returns an InputStream for reading data sent by the other party. When called on a server-side socket, it reads data sent by the client, and vice versa |
OutputStream getOutputStream() |
Returns an OutputStream for sending data to the connected party. When called on a server-side socket, it sends data to the client, and vice versa |
Practical Example: Transferring an Image File
Client Implementation
public class ImageClient { public static void main(String[] args) throws IOException { // Establish connection to the server at the specified IP and port Socket clientSocket = new Socket("127.0.0.1", 8888);
// Create input stream to read the source image file
FileInputStream fileIn = new FileInputStream("D:\\images\\photo.png");
// Get the output stream to send data to the server
OutputStream output = clientSocket.getOutputStream();
byte[] buffer = new byte[1024];
int bytesRead;
// Transfer the file in chunks
while ((bytesRead = fileIn.read(buffer)) != -1) {
output.write(buffer, 0, bytesRead);
}
// Signal the server that file transfer is complete
clientSocket.shutdownOutput();
// Receive server acknowledgment
InputStream input = clientSocket.getInputStream();
String clientIP = clientSocket.getInetAddress().getHostAddress();
bytesRead = input.read(buffer);
System.out.println("From server " + clientIP + ": " + new String(buffer, 0, bytesRead));
// Clean up resources
fileIn.close();
clientSocket.close();
}
}
</div>### Server Implementation (Single-Threaded)
<div>```
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class ImageServer {
public static void main(String[] args) throws IOException {
// Initialize server socket on the specified port
ServerSocket serverSocket = new ServerSocket(8888);
// Accept incoming client connection
Socket clientConnection = serverSocket.accept();
// Get input stream to receive data from client
InputStream input = clientConnection.getInputStream();
// Prepare destination directory
File destinationDir = new File("D:\\received");
if (!destinationDir.exists()) {
destinationDir.mkdirs();
}
// Generate unique filename for the incoming image
String fileName = "received_" + System.currentTimeMillis() +
"_" + (int)(Math.random() * 999999) + ".png";
// Create output stream to write received data
FileOutputStream fileOut = new FileOutputStream(
destinationDir + File.separator + fileName
);
byte[] buffer = new byte[1024];
int bytesReceived;
// Receive and save the image data
while ((bytesReceived = input.read(buffer)) != -1) {
fileOut.write(buffer, 0, bytesReceived);
}
// Send acknowledgment back to client
OutputStream output = clientConnection.getOutputStream();
output.write("Transfer complete".getBytes());
// Release resources
clientConnection.close();
fileOut.close();
}
}
The single-threaded approach above has a significant drawback: only one client can transfer a file at a time. If multiple cliants attempt simultaneouss connections, subsequent clients must wait until the current transfer finishes. To resolve this, we implement concurrent processing using thread pools.
Upload Handler (Runnable Task)
public class FileUploadHandler implements Runnable { private Socket connectionSocket;
public FileUploadHandler(Socket socket) {
this.connectionSocket = socket;
}
@Override
public void run() {
FileOutputStream fileWriter = null;
try {
InputStream receiver = connectionSocket.getInputStream();
// Verify destination directory exists
File storageDirectory = new File("D:\\received");
if (!storageDirectory.exists()) {
storageDirectory.mkdirs();
}
// Generate unique filename with timestamp and random suffix
String targetFile = "image_" + System.currentTimeMillis() +
"_" + (int)(Math.random() * 999999) + ".png";
// Initialize output stream to save file
fileWriter = new FileOutputStream(
storageDirectory + File.separator + targetFile
);
byte[] buffer = new byte[1024];
int dataChunk;
// Write received bytes to file
while ((dataChunk = receiver.read(buffer)) != -1) {
fileWriter.write(buffer, 0, dataChunk);
}
// Confirm successful receipt to client
OutputStream sender = connectionSocket.getOutputStream();
sender.write("Success: File received".getBytes());
} catch (IOException e) {
e.printStackTrace();
} finally {
// Ensure proper resource cleanup
try {
if (fileWriter != null) {
fileWriter.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
</div>### Concurrent Server with Thread Pool
<div>```
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ConcurrentServer {
public static void main(String[] args) throws IOException {
// Create server socket bound to port 8888
ServerSocket serverSocket = new ServerSocket(8888);
// Create a thread pool to handle multiple clients
ExecutorService threadPool = Executors.newFixedThreadPool(10);
System.out.println("Server started, waiting for connections...");
// Continuously accept client connections
while (true) {
Socket clientSocket = serverSocket.accept();
System.out.println("New client connected: " +
clientSocket.getInetAddress().getHostAddress());
// Submit the client handler to the thread pool
threadPool.execute(new FileUploadHandler(clientSocket));
}
}
}