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
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.
6
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
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
8
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.
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
10
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();
}
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();
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;
}
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);
}
16
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).
17
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.
18
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);
}
Alsopublic 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.
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);
20
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();
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.
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);
}
24
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;
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().
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;
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);
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
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