Programação de Sockets
em Java
SLIDES_10 SISTEMAS INFORMÁTICOS I, ENG. BIOMÉDICA
Sockets
TCP/UDP IP Ethernet Adapter Server TCP/UDP IP Ethernet Adapter ClientsSocket API
hardware kernel space user space portsSocket Abstractions
File server Mail server WWW serverCamada de Transporte
UDP: User Datagram Protocol
- no acknowledgements
- no retransmissions
- out of order, duplicates possible
- connectionless
TCP: Transmission Control Protocol
- reliable (in order, all arrive, no duplicates)
- flow control
Package java.net
• Classes
– DatagramPacket – DatagramSocket – InetAddress – ServerSocket – Socket• Exceptions
– BindException – ConnectException – MalformedURLException – NoRouteToHostException – ProtocolException – SocketException – UnknownHostException – UnknownServiceExceptionThe java.net
package provides networking
support in java.
InetAddress
- public byte[] getAddress();
- public static InetAddress[] getAllByName(String host);
- public static InetAddress getByName(String host);
- public String getHostName();
- public static InetAddress getLocalHost();
•The
java.net.InetAddress
class represents an IP address.
Exemplo: InetAddress
import java.io.* ;import java.net.* ; public class InetAddressTest {
public static void main( String args[] ) {
try {
InetAddress myself = InetAddress.getLocalHost();
InetAddress machine = InetAddress.getByName("www.dei.uc.pt"); System.out.println("My name : " + myself.getHostName()); System.out.println("My IP : " + myself.getHostAddress()); System.out.println("UnivSite name : " + machine.getHostName()); System.out.println("UnivSite IP : " + machine.getHostAddress());
} catch (UnknownHostException e) { System.out.println ("Could not find address "); } catch (IOException e) {
System.out.println (e);
Ports
• Port numbers can be:• Well-known (port 0-1023) • Dynamic or private (port 1024-65535) • Servers/daemons usually use well-known
ports
• Any client can identify the server/service • HTTP = 80, FTP = 21, Telnet = 23, ... • Clients usually use dynamic ports
• Assigned by the kernel at run time • A full address for a socket is then:
IP address + port number ex: student.dei.uc.pt: 8080
TCP/UDP IP Ethernet Adapter
NTP daemon serverWeb
Stream Sockets (TCP)
TCP service:“reliable” transfer of bytesfrom one process to another
Sockets Stream
• class
Socket
– Connects to a ServerSocket.
• class
ServerSocket
– Accepts requests for socket connections.
– Creates a new Socket for each connection.
Criação de Sockets
• Each Socket object is associated with exactly one remote host. • To connect to a different host, you must create a new Socket object. • You specify the remote host and the port to connect.• The host may be specified as a string like “eden.dei.uc.pt" or an
InetAddress object.
• The port should be an int between 1 and 65535. Socket s = new Socket(“www.dei.uc.pt",80);
Server and Ports
• On Unix systems (but not Windows) your program must be running as root to bind to a port between 1 and 1023.
• 0 is a special port number. It tells the system to pick on of the available ports.
• Many well known ports – echo 7 – time 13 – ftp 21 – telnet 23 – finger 79 – smpt 25 – http 80
Clients and Ports
• The client is assigned a port number on the local
machine as part of establishing the connection.
• How to know the number of the local port:
getLocalPort()
• A client can connect to a particular port by using
programs such as telnet, as follows:
telnet www.dei.uc.pt 80
Client/server socket interaction: TCP
wait for incoming connection request connectionSocket = welcomeSocket.accept() create socket, port=x, for incoming request: welcomeSocket = ServerSocket() create socket, connect to hostid, port=x clientSocket =
Socket()
close connectionSocket
read reply from clientSocket close clientSocket hostid
send request using clientSocket read request from
connectionSocket write reply to connectionSocket
Socket
• Socket(InetAddress address, int port)– Creates a stream socket and connects it to the specified port number at the specified IP address.
• InputStream getInputStream()
– Returns an input stream for this socket. • OutputStream getOutputStream()
– Returns an output stream for this socket. • void close()
– closes this socket (cuts the connection)
ServerSocket
• A server socket that can wait for connections from other machines
• public ServerSocket(int port) throws IOException
– Creates a ServerSocket that will receive connection requests on the specified port.
• public Socket accept() throws IOException
– Waits for an incoming connection request, creates the connection, and returns the Socket created on this end. • public void close() throws IOException
ServerSockets
• A ServerSocket binds to a particular local port.• Then it calls accept()to listen for incoming connections; accept()blocks until a connection is detected.
• When accept()unblocks this means that a client has connected. It returns a Socketobject which is used to communicate with the remote client. • There are no getInputStream() or getOutputStream() methods for
ServerSocket.
ServerSocket(1234)
Socket(“128.250.25.158”, 1234)
Output/write stream
Input/read stream
Client ServerExemplo: ServerSocket
1. class ServerExample {2. public static void main(String[] args) { 3. try {
4. ServerSocket ssock = new ServerSocket(3333);
5. Socket sock = ssock.accept(); 6. BufferedReader br = new BufferedReader( 7. new InputStreamReader(sock.getInputStream())); 8. System.out.println(br.readLine());
9. sock.close();
10. } catch(Exception e) { ... } 11.} }
Exemplo: client Socket
class ClientExample {public static void main(String[] args) { try {
Socket sock = new Socket( “server.dei.uc.pt”, 3333);
PrintWriter out = new PrintWriter(
sock.getOutputStream(), true);
out.println(“Hello”); sock.close();
} catch(Exception e) { ... } } }
BufferedReader
methods
void
close
() Close the stream.
int
read
()
Read a single character.
int
read
(char[] cbuf, int off, int len)
Read characters into a portion of an array.
String readLine()
Read a line of text.
DataInputStream
methods
int read(byte[] b) reads some number of bytes into the buffer array b. int read(byte[] b, int off, int len) reads up to len bytes into an array of bytes. char readChar() reads a char.
double readDouble() reads a double value. int readInt() reads a int value.
void readFully(byte[] b) reads some bytes and stores them into the buffer array. String readLine()
Deprecated.This method does not properly convert bytes to characters. The preferred way to read lines of text is via the BufferedReader.readLine() method. Programs that use the DataInputStream class to read lines can be converted to use the BufferedReader class by replacing code of the form: DataInputStream d = new DataInputStream(in); with: BufferedReader d = new BufferedReader(new InputStreamReader(in));
String readUTF() reads a string (encoded in UTF-8 format).
DataOutputStream
methods
void
flush
() flushes this data output stream.
void
write
(int b) writes the specified byte.
void
writeDouble
(double v) writes a double.
void
writeInt
(int v) writes an int.
void
writeUTF
(String
str) Writes a string.
PrintWriter
methods
void
close
()
Close the stream.
void
flush
()
Flush the stream.
void
(char c)
Print a character.
void
(char[] s)
Print an array of chars.
void
(double d)
Print a double .
void
(int i)
Print an integer.
void
(Object
obj)
Print an object.
void
(String
s)
Print a string.
Exceptions
• exceptions
: Almost all methods in
networking classes throw
IOExceptions
that must be caught because of potential
network problems.
Exceptions
try {
Socket client = new Socket(host, port);
handleConnection(client);
}
catch(
UnknownHostException
uhe) {
System.out.println("Unknown host: " + host);
uhe.printStackTrace();
}
catch(
IOException
ioe) {
System.out.println("IOException: " + ioe);
ioe.printStackTrace();
}
Outro Exemplo: Sockets TCP
Cliente
// 1. Create a Socket Object:client = new Socket( server, port_id );
// 2. Create I/O streams for communicating with the server. is = new DataInputStream(client.getInputStream() ); os = new DataOutputStream( client.getOutputStream() ); // 3. Perform I/O or communication with the server: // Receive data from the server:
String line = is.readLine(); // Send data to the server:
os.writeBytes("Hello\n"); // 4. Close the socket when done:
Server
// 1- Open the Server Socket:ServerSocket server; DataOutputStream os; DataInputStream is;
server = new ServerSocket( PORT ); // 2- Wait for the Client Request:
Socket client = server.accept();
// 3- Create I/O streams for communicating to the client is = new DataInputStream( client.getInputStream() ); os = new DataOutputStream( client.getOutputStream() ); // 4- Perform communication with client
// Receive from client: String line = is.readLine(); // Send to client:
os.writeBytes("Hello\n"); // 5- Close sockets:
client.close(); For multithreaded server:
while(true) {
i. wait for client requests (step 2 above)
ii. create a thread with “client” socket as parameter (the thread creates streams (as in step (3) and does communication as stated in (4). Remove thread once service is provided.
}
Simple Server
import java.io.*; public class SimpleServer{
public static void main(String args[]) throws IOException { // Register service on port 1234
ServerSocket s = new ServerSocket(1234); while(true){
Socket s1=s.accept(); // Wait and accept a connection // Get a stream associated with the socket
OutputStream s1out = s1.getOutputStream(); DataOutputStream dos = new DataOutputStream (s1out); // Send a string!
dos.writeUTF("Ola Boa Noite");
System.out.println("Respondeu ao cliente"); // Close the connection, but not the server socket dos.close(); s1out.close(); s1.close(); } } }
Try this example...
Simple Client
// SimpleClient.java: a simple client program import java.net.*;
import java.io.*; public class SimpleClient {
public static void main(String args[]) throws IOException { // Open your connection to a server, at port 1234 Socket s1 = new Socket(“localhost",1234);
// Get an input file handle from the socket and read the input
InputStreams1In= s1.getInputStream(); DataInputStreamdis= new DataInputStream(s1In); String st = new String (dis.readUTF()); System.out.println(st);
// When done, just close the connection and exit dis.close();
Run SimpleServer, SimpleClient
• Run Server on localhost:– java SimpleServer • Run Client:
– java SimpleClient – Ola, Boa Noite
• If you run client when server is not up:
– sockets [1:147] java SimpleClient
– Exception in thread "main" java.net.ConnectException: Connection refused – at java.net.PlainSocketImpl.socketConnect(Native Method) – at java.net.PlainSocketImpl.doConnect(PlainSocketImpl.java:320) – at java.net.PlainSocketImpl.connectToAddress(PlainSocketImpl.java:133) – at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:120) – at java.net.Socket.<init>(Socket.java:273) – at java.net.Socket.<init>(Socket.java:100) – at SimpleClient.main(SimpleClient.java:6)
Binding
• When a ServerSocket object is created, it attempts to bind to the port on the local host given by the port argument.
– If another server socket is already listening to the port, there will be ajava.net.BindException.
• No more than one process or thread can listen to a particular port at a time.
• For example, if there's already an HTTP server running on port 80, you won't be able to bind to port 80.
Multiple Clients
• Multiple clients can connect to the same port on
the server at the same time.
• The server creates a separate socket for each
client.
Multi-Threaded Servers
• If a server needs to handle many
connections at once, server programs
should be multi-threaded.
Multithreaded Server
Server Threads Server Process Client 1 Process Client 2 Process TCP/IPMulti-threaded Server
• One
ServerSocket
can accept multiple clients
simultaneously
• Use multithreading to handle them
• One thread waits for “accept()”
• Open a new thread for each connection.
• Rather than handling the connection directly the socket
should be passed to a
Thread
object that handles the
connection.
Multi-threaded Server (I)
ServerSocket server = new ServerSocket(PORT);// Server main loop while (true) {
try {
Socket clientSocket = server.accept();
ClientThread theClient = new ClientThread(clientSocket); theClient.start();
}
catch (Exception e) {
// Error accepting one of the clients e.printStackTrace();
} }
Multi-threaded Server (II)
class ClientThread extends Thread{
private Socket clientSocket;
public ClientThread(Socket clientSocket) { this.clientSocket = clientSocket; }
public void run(){
// Handle the client request here! …
… … }
Threading a Server
• Threads handles the communication between one client and theserver, by spawning a new thread every time a new client connects. • This is often accomplished in C/C++ on a Unix OS by using fork.
– Nowadays the use of Pthreads is also common. • In Java it is simpler thanks to the use ofJava Threads.
TDayTimeServer.java
import java.net.*; import java.io.*; import java.util.*; public class TDayTimeServer {
public static void main(String argv[]) { try {
ServerSocket listen = new ServerSocket(0);
System.out.println("Listening on:"+listen.getLocalPort()); for(;;) {
Socket client = listen.accept(); System.out.println(clnt.toString());
Connection c = new Connection(client);
} }
catch(Exception e) { System.out.println("Server terminated"); }
}}
Connection.java
import java.net.*; import java.io.*; import java.util.*; class Connection extends Thread {
protected Socket clnt; public Connection(Socket sock) {
clnt = sock; this.start(); }
public void run() { Date today = new Date(); try {
PrintWriter out = new PrintWriter(clnt.getOutputStream(), true); out.println(today); client.close(); } catch (IOException e) {} }}
Exemplos_Sockets.zip
-TCPClient.java
-TCPServer1.java
-TCPServer2.java (multithreaded server)
UDP - Java Classes
•
DatagramPacket
– represents a datagram packet
•
DatagramSocket
– represents a socket for sending and receiving
datagram packets
•
MulticastSocket
– for sending and receiving IP multicast packets
DatagramSocket
// Constructors• DatagramSocket()
– Constructs a datagram socket and binds it to any available port on the local host machine.
• DatagramSocket(int port)
– Constructs a datagram socket and binds it to the specified port on the local host machine.
• DatagramSocket(int port, InetAddress iaddr)
• • // Methods • void close() • InetAddress getLocalAddress() • int getLocalPort() • int getSoTimeout() • void receive(DatagramPacket p) • void send(DatagramPacket p) • setSoTimeout(int timeout)
Client/server socket interaction: UDP
hostidread reply from C_Socket create socket, C_Socket = DatagramSocket()
Create, address (hostid, port=x, send datagram request using C_Socket create socket, port=x, for incoming request: S_Socket = DatagramSocket()
read request from S_Socket write reply to S_Socket specifying client host address, port number
DatagramPacket
//Constructorspublic DatagramPacket(byte[] buf, int length)
Constructs a DatagramPacket for receiving.
publicDatagramPacket(byte[] buf, int length, InetAddress address, int port)
Constructs a datagram for sending to the specified port number on the specified host.
// Methods
public synchronized InetAddress getAddress(); public synchronized int getPort();
public synchornized byte[] getData(); int getLength();
void setAddress(InetAddress iaddr); void setPort(int iport);
DatagramPacket
• Datagram packet data is stored as a byte array:
byte[].
• To send a String message via a datagram
we need to
convert it to byte[].
• The String class provides this via the
getBytes()
method.
String msg = “Olá”;
byte[] buf = msg.getBytes();
Sending UDP Datagrams
• To send data to a particular server
– Convert the data into byte array.
– Pass this byte array, its length, the
InetAddress
and the destination port to the
DatagramPacket()
constructor.
– Next create a
DatagramSocket
and send the packet
by using the
send()
method.
Sending a DatagramPacket
try {InetAddress addr = InetAddress.getByName(“eden.dei.uc.pt"); int port = 9000;
String msg = “Olá Boa Noite"; byte[] msgBytes = msg.getBytes(); DatagramPacket packet
= new DatagramPacket(msgBytes, msgBytes.length, addr, port); DatagramSocket sender = new DatagramSocket();
sender.send(packet); } catch (Exception e) { System.err.println(e); }
DatagramSocket
public void send(DatagramPacket p)
throws IOException
– Sends a datagram packet from this socket.– The DatagramPacket includes information indicating the data to be sent, its length, the IP address of the remote host, and the port number on the remote host.
DatagramSocket
public void receive(DatagramPacket p)
throws IOException
– Receives a datagram packet from this socket.
– When this method returns, the DatagramPacket's buffer is filled with the data received. The datagram packet also contains the sender's IP address, and the port number on the sender's machine.
– It blocks until a datagram packet is received.
– If the message is longer than byte[] the message will be truncated
UDP + TCP Ports
• There are separated ports for UDP and TCP.
• Each computer has 65,536 UDP ports as well as its
65,536 TCP ports.
• A server socket can be bound to TCP port 20 at the
same time as a datagram socket is bound to UDP port
20.
DatagramSocket
(client)
DatagramSocket socket = new DatagramSocket(); // send request
InetAddress address = InetAddress.getByName(“eden.dei.uc.pt”); String s = “get_current_time_date”;
byte [] b = s.getBytes();
DatagramPacket packet = new DatagramPacket(b, b.length, address, 4445); socket.send(packet);
// get response byte[] buf = new byte[256];
packet = new DatagramPacket(buf, buf.length); socket.receive(packet);
// display response
String received = new String(packet.getData()); System.out.println(“the time:” + received);
DatagramSocket
(server)
DatagramSocket socket = new DatagramSocket(); // receives a packet request
byte[] buf = new byte[256];
DatagramPacket packetRequest = new DatagramPacket(buf, buf.length); socket.receive(packetRequest);
// Display the request
byte[] data = packetRequest.getData(); String s = new String(data, 0, data.getLength());
System.out.println("Port " + packet1.getPort() + " on " + packet1.getAddress() + " sent this message:“ + s);
if (s.equals(“get_current_time_date”)) {
String theDate = (new Date()).toString(); byte[] bufSend = theDate.getBytes();
Datagrams Received...
• Use
getPort()
and
getAddress()
to tell where the
packet come from,
getData()
to retrieve the data, and
getLength()
to see how many bytes were in the data.
• If the received packet was too long for the buffer, it's
truncated to the length of the buffer.
• Length is reset when packet is received.
Exemplos_Sockets.zip
-UDPClient.java
-UDPServer.java
Uso de Recursos: TCP vs UDP
C C C C C C TCP SERVER ServerSocket Socket Socket Socket Socket Socket Socket N clientes simultâneos N sockets no Servidor
C C C C UDP SERVER Socket
Leitura de Mensagens Grandes
em Sockets Stream
• int size,tam=0;
while(tam < N){
size=in.readBytes(...);
tam = tam + size;
}
Object Serialization
Objectos
• Programamos objectos complexos.
• Queremos guardar o estado dos objectos
em disco..
• Queremos enviar objectos para outros
processos através de um socket...
•
Object Serialization
Object Serialization
Suppose that you have an object and want
to send it across a socket…
(…)
Pessoa p = new Pessoa(“Bush”, 50);
// enviar o objecto p através de um socket
(…)
public class Pessoa{ private String name; private int age;
public Pessoa(String name, int age) { this.name = name;
Object Serialization
• It is possible to send complete objects through a socket stream–ObjectInputStream .readObject()
–ObjectOutputStream .writeObject()
• When reading an object from a ObjectInputStream, it is necessary to cast it to the appropriate type
– Pessoa p = (Pessoa) in.readObject(); • For being able to send object through a stream, they must be
serializable(i.e. they must implementjava.io.Serializable) – Although many classes are serializable, some are not – Ex: a Thread is not serializable
Guardar Objectos em Disco
public class MyClassA implements Serializable { ... } // in some other code elsewhere...
MyClassA tmp=new MyClassA(arg);
FileOutputStream fos=new FileOutputStream(“some.obj”); ObjectOutputStream out=new ObjectOutputStream(fos); out.writeObject(tmp);
out.flush(); out.close();
1. Mark your class serializable
public class Pessoa implements java.io.Serializable {
private String name; private int age;
public Pessoa(String name, int age) { this.name = name;
this.age = age; }
public String toString() {
return "[" + name + "/" + age + "]"; }
}
2. Use the ObjectStreams
• Reading…
ObjectInputStream in = new
ObjectInputStream(clientSocket.getInputStream());
Pessoa x = (Pessoa) in.readObject(); System.out.println(x);
• Writing…
ObjectOutputStream out = new
ObjectOutputStream(socket.getOutputStream()); Pessoa p = new Pessoa(“Busha”, 50);
out.writeObject(p);
Examplo Serialização Objectos
class Dataimplements Serializable{private int i; private int tabela[]; public Data(int x){
i = x;
tabela = new int[10]; for(int j=0;j<10;j++)
tabela[j]=x; }
public String toString() { return Integer.toString(i); }
public void print_conteudo() { for(int j=0;j<10;j++)
System.out.print(tabela[j]+" " ); System.out.println();
Client: TCPClient_O
public class TCPClient_O {public static void main (String args[]) { String texto;
Socket s = null; int serversocket = 6000;
try{ // 1o passo
s = new Socket(host, serversocket); //…
// 2o passo
DataInputStream in = new DataInputStream( s.getInputStream()); DataOutputStream out = new DataOutputStream( s.getOutputStream()); // Criar ObjecOutputStream e ObjectInputStream
ObjectOutputStream obj_o = new ObjectOutputStream(out); ObjectInputStream obj_i = new ObjectInputStream(in);
int contador=0; // 3o passo while(contador < 5){
contador++; Data d = new Data(contador);
obj_o.writeObject(d);
obj_o.flush();
d.print_conteudo();
System.out.println("ENVIEI OBJECTO"); String data = in.readUTF(); System.out.println("Received: "+ data); }
//... catches....
Server: TCPServer1_O
public class TCPServer1_O{public static void main(String args[]) throws IOException,ClassNotFoundException{ int serverPort = 6000;
//…
listenSocket = new ServerSocket(serverPort); while(true){
System.out.println("A espera de ligacao no socket "+serverPort); try{
clientSocket = listenSocket.accept();
in = new DataInputStream(clientSocket.getInputStream()); out = new DataOutputStream(clientSocket.getOutputStream()); // Criar ObjectinputStream e ObjectOutputStream
ObjectOutputStream obj_o = new ObjectOutputStream(out); ObjectInputStream obj_i = new ObjectInputStream(in);
Data d; while(true){ d = (Data)obj_i.readObject(); System.out.println("Recebeu: "+d); d.print_conteudo(); out.writeUTF("OBJECTO OK"); out.flush(); }// while //... catches….
Exemplos_Sockets.zip
-TCPClient_O.java
-TCPServer1_O.java
Overwriting
writeObject/readObject
public class DemoClass implements Serializable { private int _dat=3;
private static int _sdat=2;
private void writeObject(ObjectOutputStream o) throws IOException {
o.writeInt(_dat); o.writeInt(_sdat); }
private void readObject(ObjectInputStream i) throws IOException, ClassNotFoundException { _dat=i.readInt();
Objecto com partes não-serializáveis
• What happens if class Foo has a field of type Bar, but
Bar isn’t serializable?
• You get a
NotSerializableException
• Answer: use
read
/
writeObject
to explicitly serialize
parts that can’t be handled otherwise
Foo tmp=new Foo();
ObjectOutputStream out=new ObjectOutputStream; out.writeObject(tmp);