CISC 4700 L01 Network & Client- Server Programming Spring 2016 Harold, Chapter 8: Sockets for Clients
Datagram: Internet data packet Header: accounting info (e.g., address, port of source and dest) Payload: the data itself Internet data: stream of packets How to split? How to reassemble? How to track packet arrival? How to parse? All this is handled by sockets. Socket: Berkeley Unix innovation Treat network connection as yet another byte stream, e.g., a file. 2
Using Sockets Socket: connection between two hosts. Can do the following: connect to remote machine (handled by java Socket class) send data (handled by java Socket class) receive data (handled by java Socket class) close connection (handled by java Socket class) bind to a port (handled by java SocketServer class) listen for incoming data (handled by java SocketServer class) accept connections from remote machines on bound port (handled by java SocketServer class) Normal use of the Socket class: Program create new socket with Socket() actor Socket tries connecting to remote host After connection established, local & remote hosts get input & output streams from socket, which are used to send data to each other. Connection is full-duplex. The protocol determines the data's meaning. When done, connection is closed by one or both hosts 3
Investigating Protocols with Telnet Can use telnet, with an explicit port number, to investigate server running on that port. Example: sending email "by hand" Moral: Never trust email. Example: testing the Hangman protocol (port 9999 on erdos) 4
Reading from Servers with Sockets The daytime protocol is defined in RFC 867, see https://tools.ietf.org/html/rfc867 When daytime server is contacted, it sends time in human-readable format. Test via telnet program. NB: RFC 867 does not specify format of answer. In Java? Need to use sockets. Open the socket: Socket socket = new Socket("time.nist.gov", 13); Actually makes the connection, as well as opening socket. This can timeout or fail (server might not be listening on this port), so: try (Socket socket = new Socket("time.nist.gov", 13); // code to read from socket catch (IOException ex) { System.err.println("Could not connect to time.nist.gov"); This is Java-7 specific (using try-with-resources and auto-closeable). For Java 6 and earlier, see text for slight differences. NB: Must specify port number as int, rather than by name. 5
Next step: Set a timeout on the connection. socket.setsotimeout(15000); Protects against server hanging. Now call getinputstream(), so you can read bytes from socket. NB: Daytime protocol specifies those bytes must be ASCII. InputStream in = socket.getinputstream(); StringBuilder time = new StringBuilder(); InputStreamReader reader = newinputstreamreader(in, "ASCII"); for (int c = reader.read(); c!= -1; c = reader.read()) time.append((char)c); System.out.println(time); Final Java program: http://www.dsm.fordham.edu/~agw/client-server/src/daytimeclient.java Alternatively, create a Date object initialized from output of a daytime server, see http://www.dsm.fordham.edu/~agw/client-server/src/daytime.java 6
Not all protocols use text! Example: The time protocol (RFC 868), see http://tools.ietf.org/html/rfc868, specifies time as a 32-bit unsigned integer. Using telnet, we get raw bytes of this integer. So we must write a program to translate into something readable, see http://www.dsm.fordham.edu/~agw/client-server/src/time.java 7
Writing to Servers with Sockets Ask socket for output stream, along with input stream. Send request via output stream, read response from input stream. It's possible to do simultaneous read/write. Most protocols designed so that client is either reading or writing at any given time. So usual pattern is while (not done) { send request via output stream read response from input stream Example: The bidirectional TCP dict protocol (RFC 2229), see http://tools.ietf.org/html/rfc2229 Do a sample telnet session on dict.org. Now let's write a Java program to implement this protocol. 8
First step: Open socket to a dict server. Socket socket = new Socket("dict.org", 2868); socket.settimeout(15000); Client speaks first, so: OutputStream out = socket.getoutputstream(); Chain it to a more convenient stream: Writer writer = new OutputStreamWriter(out, "UTF-8"); Write the command over the socket: writer.write("define eng-lat gold\r\n"); writer.flush(); Server should respond with a definition, which we read via socket's input stream. Line consisting only of "." ends the definition. So: InputStream in = socket.getinputstream(); InputStreamReader isr = new InputStreamReader(in, "UTF-8"); BufferedReader reader = new BufferedReader(isr); String line = reader.readline(); while (!line.equals(".")) { System.out.println(line); line = reader.readline(); Complete dict client is line-oriented: http://www.dsm.fordham.edu/~agw/client-server/src/dictclient.java 9
Half-closed sockets close() shuts down both input and output streams of socket. To close only one: public void shutdowninput() throws IOException; public void shutdownoutput() throws IOException; These only shut down the given stream; they do not shut down the socket. After shutting down input, further reads return -1. After shutting down output, further writes throw IOException. Many protocols (finger, whois, HTTP,...) consist of one transaction: client sends one request to server server sends one response to client, which client reads Could shutdown client's output stream after first step: try (Socket connection = new Socket("www.oreilly.com", 80) { OutputStream cos = connection.getoutputstream(); Writer out = new OutputStreamWriter(cos, "8859_1"); out.write("get / HTTP 1.0\r\n\r\n"); out.flush(); connection.shutdownoutput(); // read the response catch (IOException ex) { ex.printstacktrace(); 10
If you've shutdown either half of the connection (even both), still need to close socket when done. To check status of streams, Socket class has methods public boolean isinputshutdown(); public boolean isoutputshutdown(); 11
The Socket Class In the java.net package. Methods of this class are invoked by other classes making TCP connections (URL, Applet,... ). Socket class uses native code to communicate with host's local TCP stack. Provides a stream-based interface to programmers. Basic Ctors public Socket(String host, int port) throws UnknownHostException, IOException; public Socket(InetAddress host, int port) throws UnknownHostException, IOException; creates TCP socket to port on host, if possible Typical use: try { Socket sock = new Socket("erdos.dsm.fordham.edu", 9999);... send and receive data... catch (UnknownHostException e) { System.err.println(e); catch (IOException e) { System.err.println(e); 12
Example: which low ports are hosting TCP servers? import java.net.*; import java.io.*; public class LowPortScanner { public static void main(string[] args) { String host = "localhost"; if (args.length > 0) { host = args[0]; for (int i = 1; i < 1024; i++) { try { Socket s = new Socket(host, i); System.out.println( "There is a server on port " + i + " of " + host); catch (UnknownHostException e) { System.err.println(e); break; 13
catch (IOException e) { // must not be a server on this port // end for // end main // end PortScanner When run on erdos, this caught open ports: 22, 25, 80, 111, 443, 602, 631, 689 corresponding to ssh, smtp, http, sunrpc, https, xmlrpc-beep, ipp, nmap in /etc/services. 14
public Socket(InetAddress host, int port) throws UnknownHostException, IOException Typical use: try { InetAddress erdos = new InetAddress("erdos.dsm.fordham.edu"); Socket sock = new Socket(erdos, 9999);... send and receive data... catch (IOException e) { System.err.println(e); 15
Picking a Local Interface from which to Connect Ctors specifying host, port number, interface: public Socket(String host, int port, InetAddress interface, int localport) throws IOException, UnknownHostException; public Socket(InetAddress host, int port, InetAddress interface, int localport) throws IOException; The interface may be either physical or virtual. If we don't care about port number, let localport be zero. Selecting interface uncommon, but sometimes useful (e.g., dual-card machine as router). 16
Ex: In program to dump error logs to printer or send to internal mail server: try { InetAddress inward = InetAddress.getByName("router"); Socket socket = new Socket("mail", 25, inward, 0); // work with sockets catch (IOException ex) { System.err.println(ex); Ctor can throw IOException UnknownHostException BindException (subclass of IOException) if socket can't bind to local network interface. 17
Constructing Without Connecting Split creating socket object from opening network connection to remote host, by using zero-parameter ctor Socket(). Make connection later on, e.g.: try { Socket socket = new Socket(); // fill in socket options SocketAddress address = new InetSocketAddress("time.nist.gov", 13); socket.connect(address); // work with sockets catch (IOException ex) { System.err.println(ex); Also public void connect connect(socketaddress endpoint, int timeout) throws IOException; with timeout =0 meaning "wait forever". Enables different kinds of sockets. Useful when setting socket option that can only be changed before socket connects. Also useful in cleaning up try-catch-finally blocks in older (pre-1.7) Java code. 18
Socket Addresses The abstract SocketAddress class represents connection endpoint. Only method: default ctor. Could be used for TCP, non-tcp sockets. In practice: Only TCP/IP sockets are supported. Provides store for transient socket connection info (e.g., IP address, port) for reuse. Socket class has methods public SocketAddress getremotesocketaddress(); public SocketAddress getlocalsocketaddress(); Ex: Connect, and then later reconnect, to an address: Socket socket = new Socket("www.dsm.fordham.edu", 80); Socket address dam = socket.getremotesocketaddress(); socket.close(); // stuff happens here, we decide to reconnect Socket socket2 = new Socket(); socket2.connect(dsm); 19
InetSocketAddress (subclass of SocketAddress) has ctors for clients: public InetSocketAddress(InetAddress address, int port); public InetSocketAddress(String host, int port); for servers: public InetSocketAddress(int port); To skip DNS host lookup, use factory method public static InetSocketAddress createunresolved(string host, int port); InetSocketAddress getter methods: public final InetAddress getaddress(); public final int getport(); public final String gethostname(); 20
Proxy Servers One ctor public Socket(Proxy proxy); To use particular proxy server, specify it by address: SocketAddress proxyaddress = new InetSocketAddress("myproxy.example.com", 1080); Proxy proxy = new Proxy(Proxy.Type.SOCKS, proxyaddress); Socket s = new Socket(proxy); SocketAddress remote = new InetSocketAddress("login.ibiblio.org", 25); s.connect(remote); Java only understands the SOCKS low-level proxy type. Also: High-level Proxy.Type.HTTP works in application layer, rather than transport layer. Proxy.Type.DIRECT represents proxyless connections. 21
Getting Information About a Socket Various methods for doing same: getinetaddress() getport() getlocalport() getlocaladdress()... useful if on multihomed host, or host with several network cards Example: Can we do HTTP connection to a host? See http://www.dsm.fordham.edu/~agw/client-server/src/socketinfo.java 22
Example: Port scanner that closes any open sockets it creates. import java.net.*; import java.io.*; public class PortScanner { public static void main(string[] args) { String host = "localhost"; if (args.length > 0) { host = args[0]; Socket connection = null; try { connection = new Socket(host, i); System.out.println("There is a server on port " + i + " of " + host); 23
catch (IOException ex) { // must not be a server on this port finally { try { if (connection!= null) connection.close(); catch (IOException ex) { // end for // end try catch (UnknownHostException ex) { System.err.println(ex); // end main // end PortScanner; 24
Closed or Connected? public boolean isclosed() true iff the socket is closed Ex: if (socket.isclosed()) {... do something... else {... do something else... NB: If socket has never been connected, isclosed() returns false. public boolean isconnected() tells you whether socket has ever been connected to a remote host. To check that a socket is currently open: boolean connected = socket.isconnected() &&! socket.isclosed(); tostring() Produces string useful for debugging, whose format may change in future. All parts of String representation available through getters, such as getinetaddress(). 25
Setting Socket Options All throw SocketException, some also throw IllegalArgumentException. TCP_NODELAY: disable packet buffering public void settcpnodelay(boolean on) public boolean gettcpnodelay() SO_LINGER: how long should close() block (allowing unsent packets to be sent) public void setsolinger(boolean on, int seconds) public int getsolinger() SO_TIMEOUT: max time a read() should block while waiting for data public void setsotimeout(int milliseconds) public int getsotimeout() these are synchronized SO_RCVBUF: size of the receive buffer public void setreceivebuffersize(int size) public int getreceivebuffersize() 26
Setting Socket Options (cont'd) SO_SNDBUF: size of the send buffer public void setsendbuffersize(int size) public int getsendbuffersize() SO_KEEPALIVE: whether to send a packet over an idle connection public void setkeepalive(boolean on) public boolean getkeepalive() SO_REUSEADDR: whether a socket can immediately reuse local port public void setreuseaddress(boolean on) throws SocketException; public boolean getreuseaddress() throws SocketException; 27
IP_TOS Class of Service Different classes of service for different types of data: video needs high bandwidth, low latency email can live with low bandwidth, high latency (pricing?) There are two methods to deal with same: public int gettrafficclass() throws SocketException; public void settrafficclass(int trafficclass) throws SocketException; trafficclass is an int in the range {0,..., 255, expressed as a combination of bit flags: 0x02: low cost 0x04: high reliability 0x08: maximum throughput 0x10: minimum delay 28
Example: Request a maximum throughput connection: Socket s = new Socket("sobolev.dsm.fordham.edu", 22); s.settrafficclass(0x08); Example: Request a high-reliability, minimum-delay connection: Socket s = new Socket("barack.whitehouse.gov", 22); s.settrafficclass(0x04 0x10); 29
Socket Exceptions What exceptions can a socket-based program throws? IOException java.net.socketexception BindException ConnectException NoRouteToHostException ProtocolException 30
Example: An Abstract SimpleSocket Class A typical socket-based client involves the following steps: (1) Set up the socket connection to the server, using a specified port number. This involves bookkeeping such as: making the socket connection setting up input and output streams associated with socket (2) Handling the session. This will involve the client's talking back and forth to the server. (3) When everything's done, we should close the socket. From the ideas of OO design, it seems that we should build an abstract class that handles the details in steps (1) and (3), using an abstract method for step (2). Code at http://www.dsm.fordham.edu/~agw/client-server/src/simplesocketclient. java 31
Example: A Finger Client The finger service can be used to determine: a list of who's logged in on a given host, or information about a particular user on a given host This service runs on port 79. Note: Many hosts disable the finger daemon, so that the list of current users isn't made available to remote users (security hole). Here's a quick description of the Finger protocol, defined in RFC 1288: (1) Connect to port 79 on any host that supports finger (exception thrown if you can't connect). (2) Send <name><cr><lf> where <name> is the keyword to finger. (3) Wait for response. (4) Response will be text of unknown length terminated by <CR><LF> (normal.plan files can only contain CR's...). 32
Code for FingerClient class that extends the SimpleSocketClient class, found at http://www.dsm.fordham.edu/~agw/client-server/src/fingerclient.java Note that its code is limited to finger-specific details, with no real networking code. Test program using FingerClient: http://www.dsm.fordham.edu/~agw/client-server/src/fingerclienttest.java 33