01 Networking
TCP/UDP
Java Networking
Java networking classes are in the java.net package.
- Addresses:
Inet4Address/Inet6Address - Interfaces:
NetworkInterface - Sockets:
Socket/ServerSocket/DatagramSocket
Demo of the different classes in the example project.
TCP Sockets
TCP is a connection-oriented protocol. It provides a reliable, ordered, and error-checked delivery of a stream of bytes.
Java TCP Sockets
The Socket class is used to open a client-side socket.
// Constructors
Socket(InetAddress addr, int port);
Socket(InetAddress add, int port, InetAddress localAddr, int localPort);
Socket(String host, int port);
Socket(String host, int port, InetAddress localAddr, int localPort);
Socket(); // unconnected, use connect() to bind
// Methods
InetAddress getInetAddress();
int getPort();
InetAddress getLocalAddress();
int getLocalPort();
InputStream getInputStream();
OutputStream getOutputStream();
void close();
void shutdownInput();
void shutdownOutput();
connect(SocketAddress endpoint);
connect(SocketAddress endpoint, int timeout);
bind(SocketAddress bindpoint);
The ServerSocket class is used to open a server-side socket.
// Constructors
ServerSocket(int port);
ServerSocket(int port, int backlog);
ServerSocket(int port, int backlog, InetAddress bindAddr);
ServerSocket(); // unbound, use bind() to bind
// Methods
Socket accept(); // blocks until a connection is requested
setSoTimeout(int timeout);
close();
Exercises
Connections
Output of netstat command when running:
- the echo server on port
1234 - two clients connecting to the echo server
$ netstat -an | grep 1234
Proto Recv-Q Send-Q Local Addr Foreign Addr State
tcp6 0 0 ::1.1234 ::1.61369 ESTABLISHED
tcp6 0 0 ::1.61369 ::1.1234 ESTABLISHED
tcp6 0 0 ::1.1234 ::1.61365 ESTABLISHED
tcp6 0 0 ::1.61365 ::1.1234 ESTABLISHED
tcp46 0 0 *.1234 *.* LISTEN # server: listening on all interfaces and port 1234
The netstat command shows the echo server listening on port 1234 and two clients connected to it.
The clients are duplicated because because there is a process for each direction.
The clients used the loopback address ::1 and ports 61369 and 61365 to connect to the server.
When trying to use the same port for multiple clients or server and client, a BindException is thrown.
If the interface is different, the same port can be used (e.g. loopback and internet).
Socket Close
Symptom
Not all lines are printed on the server.
Problem
The client closes the socket before the output stream is flushed (Formatter).
The server does therefore not receive all the data.
Solution
Include the socket in the try-with of the Formatter.
public class CloseTestClient {
public static void main(String[] args) throws Exception {
final String msg = "This is line %3d of a long message " +
"sent over TCP/IP to the server.\n";
final int n = 400;
String host = "localhost";
int port = 1234;
if (args.length > 0) { host = args[0]; }
if (args.length > 1) { port = Integer.parseInt(args[1]); }
Socket s = new Socket(host, port);
System.out.println("sending data to " + s);
OutputStream out = s.getOutputStream();
// class Formatter formats data to a given out stream
try (s; Formatter formatter = new Formatter(out)) {
for (int i = 0; i < n; i++) {
formatter.format(msg, i);
}
System.out.println("done.");
}
}
}
Socket Buffers
Symptom
The client deadlocks when trying to compress bigger files.
Problem
The send/receive queue of the socket connection fill up.
Solution
Read and write simultaneously in separate threads.
public class CompressClient {
public static void main(String[] args) throws Exception {
String server = "localhost";
int port = 1234;
// server = "86.119.38.130";
// create a file with a given size
createFile(FILE_NAME, FILE_SIZE * 1024);
// Open input and output file (named input.gz)
final FileInputStream fileIn = new FileInputStream(FILE_NAME);
final FileOutputStream fileOut = new FileOutputStream(FILE_NAME + ".gz");
// Create socket connected to server on specified port
final Socket sock = new Socket(server, port);
// Send uncompressed byte stream to server
new Thread(() -> {
try {
sendBytes(sock, fileIn);
} catch (IOException ex) {
// ignore
}
}).start();
// Receive compressed byte stream from server
InputStream sockIn = sock.getInputStream();
int bytesRead;
byte[] buffer = new byte[BUFSIZE];
while ((bytesRead = sockIn.read(buffer)) != -1) {
fileOut.write(buffer, 0, bytesRead);
Log('R'); // Reading progress indicator
}
System.out.println(); // End progress indicator line
sock.close();
fileIn.close();
fileOut.close();
}
}