Networking TCP/IP and the Internet Sockets in Java Writing Servers and Clients Threaded Servers Identifying and Locating Resources: URIs and URLs jonas.kvarnstrom@liu.se – 2015 2 The Internet is based on IP, the Internet Protocol (usually v4) Low level "send-and-forget" protocol ▪ Send a package; you don't know if it arrived 32-bit addresses, generally written as 4 bytes: 128.212.201.27 ▪ Host names ("www.liu.se") are mapped to IP numbers, usually via DNS (the Domain Name System) jonkv@ida Introduction 1: IP and the Internet 3 jonkv@ida Introduction 2: IP and the Internet In Java: Use names directly, or use java.net.InetAddress static InetAddress getByName(String host) throws UnknownHostException static InetAddress[] getAllByName(String host) throws … ▪ ▪ ▪ ▪ ▪ ▪ ▪ Returns multiple IP addresses for a host ==> www.google.com/173.194.32.243 ==> www.google.com/173.194.32.240 ==> www.google.com/173.194.32.241 ==> www.google.com/173.194.32.242 ==> www.google.com/173.194.32.244 ==> www.google.com/2a00:1450:4008:801:0:0:0:1010 static InetAddress getLocalHost() throws UnknownHostException ▪ Returns the (main) IP address of the local computer If you have multiple interfaces: NetworkInterface.getNetworkInterfaces() On top of IP, multiple protocols can be used UDP (User Datagram Protocol) ▪ Also unreliable; system sends a packet and forgets about it ▪ DatagramSocket, DatagramPacket, MulticastSocket TCP (Transmission Control Protocol) ▪ Reliable; resends unacknowledged data packets. ▪ Negotiates a connection; keeps it open until one side closes it ▪ Socket, ServerSocket … Many protocols implemented on top of TCP/UDP HTTP, FTP, NNTP, SMTP, POP, IMAP, finger, gopher, … ▪ Java supports some of them ▪ URL, URLConnection, URLEncoder, … 4 jonkv@ida Introduction 3: TCP and UDP Multiple connections between two computers Uses "ports" (16-bit numbers) to identify connections Connection identified by: <protocol, source IP, source port, dest IP, dest port> Host B 65535 Port 65535 Port 1 Port 2 Port 3 1 2 3 Port 1 Port 2 Port 3 Port 65535 Host C ▪ Multiple connections to the same dest port (different sources!) ▪ For example, multiple connections to a web server on port 80 Host A 5 jonkv@ida Introduction 4: TCP, UDP and Port Numbers Reliable Communication: TCP Sockets and the Client/Server Model jonas.kvarnstrom@liu.se – 2015 7 TCP networking is client/server-based A server continuously listens to a specific port ▪ HTTP servers usually listen to port 80 ▪ NNTP servers usually listen to port 119 Occasionally, clients connect to that port ▪ Web browsers try to connect to port 80 ▪ News readers try to connect to port 119 A ▪ ▪ ▪ successful connection results in a socket pair A two-way pipeline for binary data Anything written to socket A can be read from socket B Anything written to socket B can be read from socket A Socket/21754 Socket/80 jonkv@ida TCP Networking using Sockets 8 First, the server sets up a ServerSocket The ServerSocket listens to a specific port ▪ ServerSocket ssock = new ServerSocket(80); Ready for clients to connect ▪ "Incoming calls" are placed in a queue Listening for new connections on port 80… ServerSocket/80 jonkv@ida Sockets 1: Waiting for connections 9 The server calls accept() Picks a waiting client from the queue, or waits for one ▪ ServerSocket ssock = new ServerSocket(80); Socket s = ssock.accept(); // Waiting… Eventually a client creates a new Socket: ▪ Socket s = new Socket("server.com", 80); Attempting to talk to server:80… Socket/21754 // Maybe #21754 Connected to client:21754 ServerSocket/80 jonkv@ida Sockets 2: Accepting a connection 10 The client socket connects to server.com:80 … which was waiting in accept(), so now it accepts the connection, and returns a new java.net.Socket ▪ Socket s = ssock.accept(); // Now accept() returns! ▪ Use this Socket to communicate with the client! Once more listening for new connections on port 80… ServerSocket/80 Connected to server.com:80 Socket/21754 Socket/80 jonkv@ida Sockets 3: The Connection Socket s = new Socket("server.com",80); InputStream in = s.getInputStream(); OutputStream out = s.getOutputStream(); 11 Uses InputStream and OutputStream, just like files! ServerSocket ssock = new ServerSocket(80); Socket s = ssock.accept(); InputStream in = s.getInputStream(); OutputStream out = s.getOutputStream(); Socket/21754 Socket/80 jonkv@ida Sockets 4: Overview Network Protocols A complete client/server example jonas.kvarnstrom@liu.se – 2015 13 What remains: A protocol Must exist – but can be very simple Example: RFC 862 ▪ "A very useful debugging and measurement tool is an echo service. An echo service simply sends back to the originating source any data it receives. ▪ TCP Based Echo Service: One echo service is defined as a connection based application on TCP. A server listens for TCP connections on TCP port 7. Once a connection is established any data received is sent back. This continues until the calling user terminates the connection. ▪ UDP Based Echo Service: Another echo service is defined as a datagram based application on UDP. A server listens for UDP datagrams on UDP port 7. When a datagram is received, the data from it is sent back in an answering datagram." jonkv@ida Networking Protocols 1 To define your own protocol: Determine which kind of protocol ▪ Text-based (Java: Reader / Writer) ▪ Binary (Java: InputStream / OutputStream) ▪ Serialization-based (easy to send object structures but must use Java) Write a specification Implement the specification Find bugs and problems – update the specification and iterate 14 jonkv@ida Networking Protocols 2 A simple server example Variation on the TCP/UDP echo service ▪ Accept a string, send it back First version: ▪ The string will consist of a single line ▪ Text will always be sent in ISO Latin-1 Second version: ▪ Use serialization; no restrictions on the string 15 jonkv@ida Servers 1: What do we want? 16 public class Server { // Runs on machine server.com public final static String CS = "ISO-8859-1"; public static void main(final String[] args) { try (ServerSocket serverSock = new ServerSocket(8189)) { while (true) { try (Socket sock = serverSock.accept(); InputStream in = sock.getInputStream(); Input Reader re = new InputStreamReader(in, CS); BufferedReader br = new BufferedReader(re); OutputStream out = sock.getOutputStream(); Output Writer wr = new OutputStreamWriter(out, CS); PrintWriter pw = new PrintWriter(wr)) { final String req = br.readLine(); // Read the request ... pw.println(req); // ... send the reply. } catch (…) { … } } InputStreamReader ???InputStream } BufferedReader } PrintWriter OutputStreamWriter ???OutputStream } Socket jonkv@ida Servers 2: The Server Class 17 public class Client { public final static String CS = "ISO-8859-1"; public static void main(final String[] args) { try (Socket sock = new Socket("server.com", 8189); InputStream in = sock.getInputStream(); Input Reader re = new InputStreamReader(in, CS); BufferedReader br = new BufferedReader(re); OutputStream out = sock.getOutputStream(); Output Writer wr = new OutputStreamWriter(out, CS); PrintWriter pw = new PrintWriter(wr) ){ pw.println("Gazonk"); // Send the request… pw.flush(); // Ensure it is sent… System.out.println(br.readLine()); // … and read the reply } catch (…) { … } } } Closing the socket flushes everything, so flush() was not needed in the server. jonkv@ida Servers 3: The Client Class public class SerializingServer { public final static String CS = "ISO-8859-1"; public static void main(final String[] args) { try (ServerSocket serverSock = new ServerSocket(8189)) { while (true) { try (Socket sock = serverSock.accept(); OutputStream out = sock.getOutputStream(); ObjectOutputStream oout = new ObjectOutputStream(out); InputStream in = sock.getInputStream(); ObjectInputStream oin = new ObjectInputStream(in)) { final Object obj = oin.readObject(); // Read request… if (!(obj instanceof String)) { /* Handle error, return */ } oout.writeObject("OK"); // … send the reply. } catch (…) { … } } } catch (…) { … } } } 18 jonkv@ida Servers 4: Server with Serialization 19 public class SerializingClient { public static void main(final String[] args) { Object reply = null; try (Socket sock = new Socket("server.com", 8189); InputStream in = sock.getInputStream(); ObjectInputStream oin = new ObjectInputStream(in); OutputStream out = sock.getOutputStream(); ObjectOutputStream oout = new ObjectOutputStream(out)) { oout.writeObject("Gazonk"); // Send the request… oout.flush(); // Ensure it is sent, not buffered… reply = oin.readObject(); // Read the reply } catch (…) { … } // Now the resources are closed – go on and process the reply if (reply instanceof String) { Can easily send strings with special characters or newlines, or String str = (String) reply; lists of strings, or create your own Request/Reply classes… System.out.println(str); But can only communicate with other Java programs! } else { // Unexpected reply; handle error without crashing } jonkv@ida Servers 5: Client with Serialization Note that: ▪ The client opened its ObjectInputStream first, but… ▪ … the server opened its ObjectOutputStream first. Why? ▪ The ObjectInputStream constructor reads a serialization header. ▪ Suppose both sides first opened an ObjectInputStream. ▪ Then, both would wait for a header from the other side. ▪ The ObjectOutputStream constructor writes a serialization header. ▪ Suppose both sides first opened an ObjectOutputStream. ▪ Then, both would write a serialization header. ▪ This should not be a problem, unless the header is very large or the buffers are very small. 20 jonkv@ida Servers 6: Using serialization Multi-Threaded Servers jonas.kvarnstrom@liu.se – 2015 22 The main loop in the simple server example: A client connects… … the server processes the entire request… ▪ Possibly spends a lot of time just waiting for I/O … and then, the server can accept a new client. Client A calls… Immediately setting up a connection Client B calls… but has to wait Slowly receiving a long string through a slow connection B is handled Reversing, sending the reply jonkv@ida Problems? 23 Solution: Write a multi-threaded server Accept a connection Handle it in another thread Main thread can quickly accept a new connection Client B calls Faster connection and/or shorter string Reply Setting up connection A and starting a new thread Slowly receiving a long string through a slow connection Reversing, sending the reply (Alternative solution: Single thread + state machine) jonkv@ida Solution! ConnectionHandler does most of what Server used to do class ConnectionHandler implements Runnable { private final Socket sock; public ConnectionHandler(final Socket sock) { this.sock = sock; } public void run() { try (InputStream in = sock.getInputStream(); Reader re = new InputStreamReader(in, ThreadedServer.CS); BufferedReader br = new BufferedReader(re); OutputStream out = sock.getOutputStream(); Writer wr = new OutputStreamWriter(out, ThreadedServer.CS); PrintWriter pw = new PrintWriter(wr)) { } } final String req = br.readLine(); // Read the request… pw.println(req); // … send the reply. } catch (IOException ex) { /* handle this */ } 24 jonkv@ida Threaded Servers 1: Connection Handler ThreadedServer is a skeleton that creates ConnectionHandlers public class ThreadedServer { public final static String CS = "ISO-8859-1"; public static void main(final String[] args) { try (ServerSocket serverSock = new ServerSocket(8189)) { while (true) { try (Socket sock = serverSock.accept()) { Runnable task = new ConnectionHandler(sock); Thread thr = new Thread(task); thr.start(); } } } catch (…) { … } } } 25 jonkv@ida Threaded Servers 2: The Server Still some problems… Unless we limit the number of threads, ▪ Anyone can create a huge number of connections… ▪ … which causes us to spawn a huge number of threads… ▪ … which may lead to OutOfMemoryException and other problems. Solution 1: Use a Semaphore ▪ Blocks when you try to allocate more than n "units" Solution 2: Use a standard thread pool ▪ For example, a ThreadPoolExecutor 26 jonkv@ida Threaded Servers 3: Remaining Problems Identifying and Locating Resources URIs and URLs Accessing Network Resources through URLs jonas.kvarnstrom@liu.se – 2015 URLs are represented by class java.net.URL Create: ▪ URL u1 = new URL("http://www.ida.liu.se/labs") ▪ URL u2 = new URL("http", "www.ida.liu.se", 80, "labs") ▪ URL u3 = new URL(u1, "kplab/teaching") Useful methods: ▪ getUserInfo(), getProtocol(), getHost(), getPort(), getPath(), getRef(), getQuery() ▪ getContent() ▪ openStream() ▪ openConnection() 28 jonkv@ida URLs 1: The URL Class public InputStream openStream() Retrieves the raw content of the URL ▪ There must be a handler for the protocol ▪ Sun provides handlers for the most common protocols: file, ftp, http, gopher, jar (and some more) ▪ You can provide your own handlers using a URLStreamHandlerFactory Read the InputStream like any other InputStream ▪ public static void main(String[] args) { final URL url = new URL("http://myserver.com/mypic.gif"); final InputStream is = url.openStream(); final DataInputStream dis = new DataInputStream(is); … } 29 jonkv@ida URLs 2: URL.openStream() public Object getContent() Retrieves the raw content of the URL ▪ There must be a handler for the protocol (http, ftp, …) Parses the content, and returns an object ▪ An ImageProducer, a String, … — anything that has a content handler ▪ Sun provides handlers for: image/jpeg, image/png, image/gif, image/x-xbitmap, image/x-xpixmap audio/aiff, audio/wav text/plain ▪ Provide your own handlers using a ContentHandlerFactory ▪ public static void main(String[] args) { final URL url = new URL("http://myserver/mypic.gif"); final ImageProducer ip = (ImageProducer) url.getContent(); … } 30 jonkv@ida URLs 3: URL.getContent() References jonas.kvarnstrom@liu.se – 2015 The Java Tutorial http://docs.oracle.com/java se/tutorial/networking/ Optional Packages: JavaMail Mail and news ▪ Sending, retrieving, and storing messages ▪ Support for POP3, IMAP, … http://www.oracle.com/tec hnetwork/java/javamail/ind ex.html 32 jonkv@ida See Also