• No results found

CISC 4700 L01 Network & Client- Server Programming Spring Harold, Chapter 8: Sockets for Clients

N/A
N/A
Protected

Academic year: 2021

Share "CISC 4700 L01 Network & Client- Server Programming Spring Harold, Chapter 8: Sockets for Clients"

Copied!
33
0
0

Loading.... (view fulltext now)

Full text

(1)

CISC 4700 L01

Network & Client-

Server Programming

Spring 2016

Harold, Chapter 8:

Sockets for Clients

(2)

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

(3)

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

(4)

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

(5)

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)

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

(7)

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)

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.

(9)

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)

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();

}

(11)

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();

(12)

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

(13)

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;

}

(14)

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

(15)

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)

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)

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)

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.

(19)

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)

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();

(21)

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.

(22)

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

(23)

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)

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;

(25)

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().

(26)

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

(27)

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;

(28)

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

(29)

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);

(30)

Socket Exceptions

What exceptions can a socket-based program throws?

IOException

java.net.SocketException BindException

ConnectException

NoRouteToHostException ProtocolException

30

(31)

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

(32)

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

(33)

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

References

Related documents