Survey
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
Networking in Java Java Fundamentals Dmitri Gabbasov Tartu 2016 The java.net package ● ● ● ● ● ● ● java.net.Socket represents a TCP connection to a remote endpoint java.net.ServerSocket represents a TCP endpoint that others can connect to java.net.DatagramSocket represents a UDP endpoint for transmitting data without a connection java.net.URI provides means to syntactically manipulate URIs java.net.URL provides means to transmit data over specific application layer protocols java.net.InetAddress represents an IP address java.net.NetworkInterface provides means to enumerate network interfaces and their IP addresses Network layers (the TCP/IP model) Application HTTP FTP Transport TCP UDP Internet IPv4 IPv6 Link Ethernet SMTP DNS SSH TCP — Transmission Control Protocol ● Connection oriented (client - server) ● Provides the ability to transmit streaming data ● Guarantees reliable, ordered delivery ● Controls flow and congestion UDP — User Datagram Protocol ● Connectionless ● Transmits data in packets (datagrams) ● No guarantee of ordering or delivery ● Low latency Sockets ● A socket is an endpoint for communication between two machines ● A socket address is a combination of an IP address and a port number ● A socket has typically two associated socket addresses — the local address and the remote address java.net.Socket ● Socket() create an unconnected socket ● Socket(InetAddress address, int port) create a socket and connect to the specified IP address and port ● Socket(String host, int port) create a socket and connect to the specified host and port ● void connect(SocketAddress endpoint) connect an unconnected socket ● InputStream getInputStream() get the stream used for reading bytes from the socket ● OutputStream getOutputStream() get the stream used for writing bytes to the socket java.net.Socket example #1 Socket s = new Socket(InetAddress.getLoopbackAddress(), 8080); OutputStream out = s.getOutputStream(); InputStream in = s.getInputStream(); byte[] request = {1, 1, 2, 3, 5, 8}; out.write(request); byte[] response = new byte[10]; in.read(response); System.out.println("Client got: " + Arrays.toString(response)); s.close(); java.net.Socket example #1 (v2) try ( Socket s = new Socket(InetAddress.getLoopbackAddress(), 8080); OutputStream out = s.getOutputStream(); InputStream in = s.getInputStream(); ) { byte[] request = {1, 1, 2, 3, 5, 8}; out.write(request); byte[] response = new byte[10]; in.read(response); System.out.println("Client got: " + Arrays.toString(response)); } java.net.ServerSocket ● ServerSocket() create an unbound server socket ● ServerSocket(int port) create a server socket and bind it to the given port ● void bind(SocketAddress endpoint) bind an unbound server socket to a specific endpoint (address + port) ● Socket accept() listen for a connection and accept it java.net.ServerSocket example #1 try ( ServerSocket server = new ServerSocket(8080); Socket client = server.accept(); InputStream in = client.getInputStream(); OutputStream out = client.getOutputStream(); ) { byte[] request = new byte[10]; int n = in.read(request); System.out.println("Server got: " + Arrays.toString(request)); for (int i = 0; i < n; i++) request[i]++; out.write(request); } Example #1 output Server got: [1, 1, 2, 3, 5, 8, 0, 0, 0, 0] Client got: [2, 2, 3, 4, 6, 9, 0, 0, 0, 0] java.net.Socket example #2 try ( Socket s = new Socket(InetAddress.getLoopbackAddress(), 8080); BufferedWriter writer = new BufferedWriter( new OutputStreamWriter(s.getOutputStream(), UTF_8)); BufferedReader reader = new BufferedReader( new InputStreamReader(s.getInputStream(), UTF_8)) ) { writer.write("Ping\n"); writer.flush(); String response = reader.readLine(); System.out.println("Client got: " + response); } java.net.ServerSocket example #2 try ( ServerSocket server = new ServerSocket(8080); Socket client = server.accept(); BufferedWriter writer = new BufferedWriter( new OutputStreamWriter(client.getOutputStream(), UTF_8)); BufferedReader reader = new BufferedReader( new InputStreamReader(client.getInputStream(), UTF_8)) ) { String request = reader.readLine(); System.out.println("Server got: " + request); writer.write("Pong\n"); writer.flush(); } Example #2 output Server got: Ping Client got: Pong Accepting multiple connections ● The server needs to be able to work with several clients simultaneously ● This can be achieved by using multiple threads try (ServerSocket server = new ServerSocket(8080)) { ExecutorService executor = Executors.newCachedThreadPool(); while (true) { Socket client = server.accept(); executor.execute(() -> { OutputStream out = client.getOutputStream(); InputStream in = client.getInputStream(); // perform I/O on the client }); } executor.shutdown(); executor.awaitTermination(5, TimeUnit.MINUTES); } java.net.DatagramSocket ● ● ● ● ● ● ● DatagramSocket() create a datagram socket and bind it to any available port DatagramSocket(int port) create a datagram socket and bind it to the given port DatagramSocket(SocketAddress addr) create a datagram socket and bind it to the given address and port; passing null creates an unbound socket void bind(SocketAddress addr) bind the socket to the given address and port void connect(InetAddress address, int port) “connect” the socket to the given address and port void send(DatagramPacket packet) send a datagram packet from this socket void receive(DatagramPacket packet) receive a datagram packet from this socket java.net.DatagramSocket example (endpoint #1) try (DatagramSocket socket = new DatagramSocket()) { byte[] data = {1, 1, 2, 3, 5, 8}; DatagramPacket request = new DatagramPacket(data, data.length); request.setAddress(InetAddress.getLoopbackAddress()); request.setPort(8888); socket.send(request); DatagramPacket response = new DatagramPacket(new byte[10], 10); socket.receive(response); System.out.println( "Endpoint #1 got: " + Arrays.toString(response.getData()) + " from " + response.getSocketAddress()); } java.net.DatagramSocket example (endpoint #2) try (DatagramSocket socket = new DatagramSocket(8888)) { DatagramPacket request = new DatagramPacket(new byte[10], 10); socket.receive(request); byte[] data = Arrays.copyOf( request.getData(), request.getLength()); System.out.println( "Endpoint #2 got: " + Arrays.toString(data) + " from " + request.getSocketAddress()); for (int i = 0; i < data.length; i++) data[i]++; DatagramPacket response = new DatagramPacket(data, data.length); response.setSocketAddress(request.getSocketAddress()); socket.send(response); } java.net.DatagramSocket example output Endpoint #2 got: [1, 1, 2, 3, 5, 8] from /127.0.0.1:53908 Endpoint #1 got: [2, 2, 3, 4, 6, 9, 0, 0, 0, 0] from /127.0.0.1:8888 Socket channels (java.nio.channels) ● Access the same socket from different threads ● Manage multiple sockets in one thread ● Use special buffers for read/write operations Socket channels example Selector selector = Selector.open(); for (int i = 0; i < 100; i++) { SocketChannel client = SocketChannel.open(); client.configureBlocking(false); client.register(selector, OP_CONNECT | OP_READ | OP_WRITE); client.connect(...); } while (true) { selector.select(); Set<SelectionKey> selectedKeys = selector.selectedKeys(); for (SelectionKey key : selectedKeys) { SocketChannel channel = (SocketChannel) key.channel(); if (key.isConnectable()) { // client connected } if (key.isWritable()) { // write to the socket } if (key.isReadable()) { // read from the socket } } } java.nio.ByteBuffer ● ByteBuffer.allocate(int capacity) creates a buffer with the given capacity ● ByteBuffer.wrap(byte[] array) creates a buffer with the given underlying array ● int capacity() returns the capacity of the buffer ● int position() returns the current position of the buffer ● int limit() returns the limit of this buffer ● int remaining() returns the number of bytes between the current position and the limit java.nio.ByteBuffer Position ● ● Limit Capacity Buffer clear() clears the buffer — sets the limit to the capacity and the position to 0 Buffer flip() flips the buffer — sets the limit to the current position and sets the position to 0 ● Buffer rewind() rewinds the buffer — leaves the limit unchanged and sets the position to 0 Using ByteBuffers with channels // Each client should have a unique buffer ByteBuffer buffer = ByteBuffer.allocate(1024); // ... SocketChannel channel = (SocketChannel) key.channel(); if (key.isReadable()) { channel.read(buffer); // check the number of bytes in the buffer using // buffer.position() and act accordingly buffer.flip(); byte[] data = new byte[buffer.limit()]; buffer.get(data); // data now contains the bytes that were in the buffer buffer.clear(); } Communicating through higher level protocols ● TCP/UDP is fairly low level ● It can get complicated very fast ● You will likely be reinventing the wheel a lot of times ● You are probably better off using a higher level protocol ● You can either ○ use an existing one or ○ develop your own Application layer protocols ● An application layer protocol defines the rules for formatting certain messages ● It helps solve some complex communication issues ○ authentication ○ authorization ○ metadata ○ message structure ● Some well known protocols: ○ HTTP — web pages, REST APIs ○ FTP — file transfer ○ SMTP — sending email ○ RTP — real-time audio/video streaming ○ SSH — secure operation of remote services HTTP ● One of the most well-known and versatile application layer protocols ● Initially designed to transmit hypertext (web pages) ● HTTP has a simple request-response model ○ Client sends a request ○ Server sends a response ○ Rinse and repeat ● The protocol is stateless, however state is often implemented on top of HTTP Making an HTTP request by hand try ( Socket s = new Socket("freegeoip.net", 80); Writer writer = new OutputStreamWriter(s.getOutputStream(), UTF_8); BufferedReader reader = new BufferedReader( new InputStreamReader(s.getInputStream(), UTF_8)); ) { writer.write("" + "GET /json/ HTTP/1.1\r\n" + "Host: freegeoip.net\r\n" + "Connection: close\r\n" + "\r\n"); writer.flush(); String line; while ((line = reader.readLine()) != null) System.out.println(line); } Making an HTTP request by hand (output) HTTP/1.1 200 OK Content-Type: application/json Vary: Origin X-Database-Date: Wed, 07 Sep 2016 19:05:53 GMT X-Ratelimit-Limit: 10000 X-Ratelimit-Remaining: 9993 X-Ratelimit-Reset: 2383 Date: Mon, 03 Oct 2016 06:58:53 GMT Content-Length: 221 Connection: close {"ip":"213.180.18.27","country_code":"EE","country_name":"Estonia" ,"region_code":"78","region_name":"Tartu","city":"Tartu","zip_code ":"","time_zone":"Europe/Tallinn","latitude":58.3661,"longitude":2 6.7361,"metro_code":0} java.net.URL ● URL(String spec) creates a URL from the given string ● URLConnection openConnection() returns an object representing the connection to the resource referred to by this URL ● InputStream openStream() opens a connection to this URL and returns an input stream for reading from that connection java.net.URL example URL url = new URL("http://freegeoip.net/json/"); try (BufferedReader reader = new BufferedReader( new InputStreamReader(url.openStream(), UTF_8))) { String line; while ((line = reader.readLine()) != null) System.out.println(line); } Output: {"ip":"213.180.18.27","country_code":"EE","country_name":"Estonia" ,"region_code":"78","region_name":"Tartu","city":"Tartu","zip_code ":"","time_zone":"Europe/Tallinn","latitude":58.3661,"longitude":2 6.7361,"metro_code":0} java.net.URL example (POST) URL url = new URL("http://www.asciitohex.com/"); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setRequestMethod("POST"); connection.setDoOutput(true); connection.setRequestProperty( "Content-Type", "application/x-www-form-urlencoded"); try (OutputStreamWriter writer = new OutputStreamWriter( connection.getOutputStream(), UTF_8)) { writer.write("b64=SmF2YSBGdW5kYW1lbnRhbHM%3D"); writer.flush(); } try (BufferedReader reader = new BufferedReader( new InputStreamReader(connection.getInputStream(), UTF_8))) { String line; while ((line = reader.readLine()) != null) System.out.println(line); } java.net.URL example output (POST) <!doctype html> <html lang="en"> ... <textarea name="ascii" id="ascii">Java Fundamentals</textarea> ... Apache HttpComponents String response = Request.Get("http://freegeoip.net/json/") .execute().returnContent().asString(); System.out.println(response); String response = Request.Post("http://www.asciitohex.com/") .bodyForm(Form.form() .add("b64", "SmF2YSBGdW5kYW1lbnRhbHM=").build()) .execute().returnContent().asString(); System.out.println(response); Jetty Allows to easily embed an HTTP server into any application. <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-server</artifactId> <version>9.3.12.v20160915</version> </dependency> Embedded Jetty class MyHandler extends AbstractHandler { @Override public void handle(String path, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { // Use request.getPathInfo() to access the path // and request.getQueryString() to access the query string baseRequest.setHandled(true); response.setStatus(HttpServletResponse.SC_OK); response.getWriter().println("Hello"); } } Server server = new Server(8080); server.setHandler(new MyHandler()); server.start(); server.join(); Homework Implement a simple chat client-server application. ● ● ● ● ● ● The client has been written for you, you need to write the server The server must be able to handle multiple connected clients Whenever a client connects to the server, it first sends its name, the server must keep track of the names Whenever the server receives a message from a client, it must prefix the message with the name of the client and send this prefixed message to all other connected clients The server must also send “X has joined” and “X has left” messages to all clients (a client joins when he connects, and leaves when he disconnects) The server must have an HTTP endpoint (on port 8080) that returns the names of all currently connected clients (just a basic list, one name per line) You’ll find the client here: https://github.com/JavaFundamentalsZT/jf-hw-net Homework Here is some sample output from a client. Enter name: chip Connecting… Connected, you can type your messages now dale has joined hey dale dale: hi let's go get some apples dale: sure, why not dale: let's meet at your place, I'll be there in 10 dale has left /q