TCP/IP Server Socket
In Java, server applications are created using the ServerSocket
class, which is specifically designed to listen for and accept incoming network connections from clients.
Core Function: A
ServerSocket
listens on a specific port for connection requests from local or remote client programs.Distinction from
Socket
: Unlike a regularSocket
, which represents a point-to-point connection, aServerSocket
acts as a "listener" that waits for clients to connect. When a client connects, theServerSocket
creates a newSocket
object to handle the communication with that specific client.
Constructors
- When creating a
ServerSocket
, port on which to listen on must be specified. - Can also define a queue length, which is the maximum number of incoming connections that can be pending before the server starts refusing them. The default queue length is 50.
ServerSocket(int port) throws IOException
Creates a server socket on the specified port with a queue length of 50.
ServerSocket(int port, int maxQueue) throws IOException
Creates a server socket on the specified port with a maximum queue length of maxQueue
.
ServerSocket(int port, int maxQueue, InetAddress localAddress) throws IOException
Creates a server socket that binds to a specific IP address (localAddress
), which is useful for hosts with multiple network interfaces.
Note: All these constructors can throw an
IOException
if the port is already in use or another error occurs.
Accepting Connections
The primary method of a ServerSocket
is accept()
, which waits for a client to connect.
Socket accept() throws IOException
accept()
is a blocking call, meaning the program execution will pause at this line until a client establishes a connection.Once a connection is made,
accept()
returns a regularSocket
object, which is then used for all further communication with that client.
Datagrams: Connectionless Communication
While TCP/IP provides reliable, connection-oriented communication, its built-in mechanisms for congestion control and handling packet loss can introduce overhead, making it less efficient for certain applications.
For faster, connectionless communication, Java provides datagrams, which use the User Datagram Protocol (UDP). A datagram is an independent, self-contained bundle of information sent between machines.
No Guarantees: With datagrams, there is no guarantee of delivery, no confirmation of receipt, and no assurance of the order in which packets will arrive.
"Fire and Forget": Sending a datagram is like like a blind throw, once it's sent, there's no way to know if it was caught, dropped, or lost.
Java implements datagram communication using two main classes:
DatagramPacket
: The data container that holds the message.DatagramSocket
: The mechanism for sending and receiving theDatagramPacket
.
DatagramSocket
A DatagramSocket
is used to send and receive datagrams. It can be bound to a specific port or let the system assign an available one.
Constructors
Creates a socket bound to any available local port:
DatagramSocket() throws SocketException
Creates a socket bound to the specified port
:
DatagramSocket(int port) throws SocketException
Binds to a specific port
and ipAddress
:
DatagramSocket(int port, InetAddress ipAddress)
throws SocketException
Binds to a SocketAddress
(typically an InetSocketAddress
that combines an IP and port):
DatagramSocket(SocketAddress address) throws SocketException
Key Methods
void send(DatagramPacket packet) throws IOException
void receive(DatagramPacket packet) throws IOException
Method | Description |
---|---|
void send(..) | Sends the specified packet. |
void receive(..) | A blocking call that waits to receive a packet and fills the buffer of the provided packet . |
setSoTimeout(int millis) | Sets a timeout in milliseconds. If a receive() call blocks for longer than this time, a SocketTimeoutException is thrown. |
isBound() / isConnected() | Returns whether the socket is bound to an address or connected to a server. |
Since
DatagramSocket
implementsAutoCloseable
, it is recommended to use it within a try-with-resources block to ensure it is always closed properly.
DatagramPacket
A DatagramPacket
is a data container. One constructor form is used for receiving data (by providing a buffer) and another for sending data (by including the destination address and port).
Constructors
Receiving: Creates a packet with a buffer (data
) of a certain size
to store incoming data:
DatagramPacket(byte[] data, int size)
Receiving: Similar to the above, but with a specified offset
in the buffer:
DatagramPacket(byte[] data, int offset, int size)
Sending: Creates a packet containing the data
to be sent to the specified ip
and port
:
DatagramPacket(byte[] data, int size, InetAddress ipAddress, int port)
Sending: Similar to the above, but allows specifying an offset
and size
for the data:
DatagramPacket(byte[] data, int offset, int size, InetAddress ipAddress, int port)
Key Methods
Method | Description |
---|---|
getAddress() / getPort() | Returns the IP address and port of the sender (for received packets) or destination (for sent packets). |
getData() / getLength() | Returns the byte array buffer and the actual length of the data received or to be sent. |
setData() / setLength() | Modifies the data buffer, its offset, and its length. |
setAddress() / setPort() | Sets the destination address and port for sending a packet. |
Datagram Communication Example
A simple client-server model using datagrams. One instance acts as a server, listening for keyboard input, while the other acts as a client, printing the received messages.
import java.net.*;
class WriteServer {
public static int serverPort = 5000;
public static int clientPort = 5001;
public static int buffer_size = 1024;
public static DatagramSocket ds;
public static byte[] buffer = new byte[buffer_size];
public static void TheServer()
throws Exception {
int pos = 0;
System.out.println("Server is running. Type messages and press Enter to send.");
while (true) {
int c = System.in.read();
switch (c) {
case -1:
System.out.println("Server Quits.");
ds.close();
return;
case '\r': // Ignore carriage return
break;
case '\n': // Send packet on newline
DatagramPacket packet = new DatagramPacket(buffer, pos, InetAddress.getLocalHost(), clientPort);
ds.send(packet);
pos = 0; // Reset buffer position
break;
default:
buffer[pos++] = (byte) c;
}
}
}
public static void TheClient()
throws Exception {
System.out.println("Client is running. Waiting for messages...");
while (true) {
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
ds.receive(packet);
System.out.println("Received: "
+ new String(packet.getData(), 0, packet.getLength()));
}
}
public static void main(String[] args)
throws Exception {
if (args.length == 1) {
ds = new DatagramSocket(serverPort);
TheServer();
} else {
ds = new DatagramSocket(clientPort);
TheClient();
}
}
}
In the first terminal, start the Client:
java WriteServer
In the second terminal, start the Server by giving some input:
java WriteServer 1