0% found this document useful (0 votes)
58 views

Laboratory 2: Information Packets

Unicast transmission sends information packets to a single destination, broadcasting transmits to all devices in a network broadcast domain, and multicast delivers information to a group of destinations simultaneously using the most efficient delivery strategy over each link. UDP is a connectionless datagram protocol that is faster than TCP but does not guarantee delivery, while TCP is connection-oriented, ordered and reliable. A UDP socket's lifecycle includes creation, binding, data exchange, and destruction, while data exchange involves sending and receiving datagrams to specified destinations.

Uploaded by

RobertCozianu
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
58 views

Laboratory 2: Information Packets

Unicast transmission sends information packets to a single destination, broadcasting transmits to all devices in a network broadcast domain, and multicast delivers information to a group of destinations simultaneously using the most efficient delivery strategy over each link. UDP is a connectionless datagram protocol that is faster than TCP but does not guarantee delivery, while TCP is connection-oriented, ordered and reliable. A UDP socket's lifecycle includes creation, binding, data exchange, and destruction, while data exchange involves sending and receiving datagrams to specified destinations.

Uploaded by

RobertCozianu
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 12

Laboratory 2

Unicast transmission is the sending of information packets to a single destination.

Broadcasting refers to transmitting a packet that will be received (conceptually) by every device on the network. In
practice, the scope of the broadcast is limited to a broadcast domain.

Multicast is... a need. Multicast is a network addressing method for the delivery of information to a group of
destinations simultaneously using the most efficient strategy to deliver the messages over each link of the network
only once, creating copies only when the links to the multiple destinations split.

Differences between TCP and UDP


As we have seen in the first laboratory:

TCP is a connection-oriented, stream-oriented, ordered, reliable protocol over IP;


UDP is a connection-less, datagram-oriented, unordered, unreliable protocol over IP;
also we could add that TCP is much slower than UDP because of the ordering and reliability;

So we could conclude that these two protocols are diametrically opposite.

UDP sockets
Like in the case of TCP sockets we usually split the applications in two main categories: servers and clients.
But in this situation we do not have UDP client and server sockets, we speak only of UDP sockets -- as UDP is a
connection-less protocol. Nonetheless in order for the communication to take place the same conditions -- like in the
case of TCP -- must be met:

the server should listen on a certain IP address and port -- again the local socket address;
the client should know in advance the exact IP address and port of the server -- the remote socket address;
the client must also have a local socket address, just like in the case of the server;

Life-cycle
Thus the generic life-cycle of an UDP socket would be:

creation -- the socket object is created;


binding -- the local socket address is established (IP plus port);
data exchange -- we shall see further what data exchange implies;
destruction -- the socket object is destroyed, and no longer used;

As we can see there is nowhere any connection being made, and thus both the client and the server act the same way,
the only distinction is that usually the client is the one that initiates the dialog.

Data exchange
The data exchange step is split in two actions:

sending a datagram:
datagram creation -- we create a datagram object for which we establish:
the data buffer -- what we want to send;
the destination socket address -- where do we want to send the datagram; this is composed of an
IP and port of the other entity;
datagram sending -- we actually send the datagram over the network to the specified destination;
receiving:
datagram creation -- we create a datagram object for which we establish:
the buffer -- where we want to receive the data;
we wait for datagrams, and when one arrives we obtain it;
2

we must obtain the datagram length, in order to know how much of the buffer has been written;
we may also obtain the sender's socket address;

We could observe from the previous steps that the data exchange could be done with multiple entities, thus one client
could speak with more than one server (or one server with multiple clients) by using the same socket -- something
which in the case of TCP sockets is not possible.
Also we should observe that in the case of UDP sockets we must prepare in advance the buffer where we want to
receive the data, and in the case buffer is to small to hold the entire received datagram, usually an error will be raised,
and we can retry with a greater buffer.

"Connected" UDP sockets


A second of the socket life-cycle is different in the fact that we introduce another step -- the connection step -- between
the binding and the data exchange, and we remove the datagram remote socket address setup. This does not mean that
we shall use a connection-oriented UDP socket. This is just an Java API facility which allows us to ignore the remote
socket address when sending, provided that we communicate with only one server, thus no packet is sent during the
connection step, and on the wire there is no difference between the two variants. So:

creation -- identical with the previous variant;


binding of the local socket address -- identical;
connection -- establishing the default remote address;
data exchange:
sending a datagram:
datagram creation:
data setup;
there is no remote address setup;
datagram sending -- identical;
receiving a datagram -- identical;
destruction;

Java API

java.net:
DatagramSocket:
constructor() -- creates a datagram socket and binds it to a random local port -- the IP address is
0.0.0.0;
constructor(SocketAddress) -- creates a datagram socket and binds it to the specified socket
address;
connect(SocketAddress) -- this method is used to establish a default remote socket address for
datagrams -- thus giving us the impression of a connection-oriented socket;
send(DatagramPacket) -- sends a datagram;
receive(DatagramPacket) -- waits and fills the datagram object; the buffer and remote socket
address will be set-up;
getLocalSocketAddress() -- used to obtain the local socket address;
getRemoteSocketAddress() -- used to obtain the remote socket address -- the one setup by
connect;
close() -- used to destroy the socket, and after this it will not be usable;
DatagramPacket:
constructor(byte, int, int) -- the constructor used to establish only the data buffer and positions; it
3

does not setup any remote socket address;


constructor(byte, int, int, SocketAddress) -- like the previous constructor, but we are able to
establish a remote socket address;
getSocketAddress();
getData();
getLength();
getOffset();
please see also the API in the section Java binary IO generic API;

Examples

creating and binding the socket:

DatagramSocket socket = new DatagramSocket ();

resolving the remote (destination) socket address (IP and port) -- this is usually done on the client side:

InetAddress remoteAddress = InetAddress.getByName (remoteAddressName);


int remotePort = Integer.parseInt (remotePortName);
SocketAddress remoteSocketAddress = new InetSocketAddress (remoteAddress, remotePort);

sending a datagram:
creating the datagram:

byte[] requestBuffer = requestString.getBytes ();


int requestOffset = 0;
int requestLength = requestString.length ();
DatagramPacket requestDatagram=new DatagramPacket(requestBuffer, requestOffset, requestLength,
remoteSocketAddress);

sending the datagram:

socket.send (requestDatagram);

receiving a datagram:
creating the datagram:

byte[] responseBuffer = new byte [2048];


DatagramPacket responseDatagram = new DatagramPacket (responseBuffer,0, responseBuffer.length);

waiting for a datagram:

socket.receive (responseDatagram);

obtaining the datagram data:

int responseOffset = responseDatagram.getOffset ();


int responseLength = responseDatagram.getLength ();
String responseString = new String (responseBuffer, responseOffset, responseLength);

obtaining the remote (source) socket address -- this is usually done on the server side:

SocketAddress senderSocketAddress = datagram.getSocketAddress ();

closing the socket:


4

socket.close ();

Unicast vs. broadcast


When sending messages we can distinguish three cases, based on the destination:

a single specified -- explicit -- destination => unicast;


all local -- implicit -- destinations => broadcast;
any local -- implicit -- destination => anycast;
all interested -- implicit -- destinations => multicast;

Observation: implicit and explicit refers to the fact that the sender must know the exact address of the involved
destinations:

explicit means that we do need an exact address for the destination;


implicit means that we use as an destination a group address, and it's the job of the actual destination hosts to
listen or join on this address;

In case of broadcast we can use as the IP address:

the local network broadcast address; for example if our IP is 10.10.10.8, and the netmask is 255.255.255.0, then
the local network broadcast address is 10.10.10.255;
the global network broadcast address: 255.255.255.255;

Observation: if a host makes a broadcast, the sent packet is tagged with the its (the sender) IP address, and thus any
receiving host can determine the source address.

Client
import
import
import
import
import

java.net.DatagramPacket;
java.net.DatagramSocket;
java.net.InetAddress;
java.net.InetSocketAddress;
java.net.SocketAddress;

public class Client


{
public static void main (String[] arguments) throws Exception
{
// Checking the argument count
if (arguments.length != 3) {
System.err.println ("Bad usage.");
return;
}
// Selecting the arguments
String remoteAddressName = arguments[0];
String remotePortName = arguments[1];
String requestString = arguments[2];
// Creating and binding the client socket

DatagramSocket socket = new DatagramSocket ();


// Resolving the server address and port
InetAddress remoteAddress = InetAddress.getByName (remoteAddressName);
int remotePort = Integer.parseInt (remotePortName);
// Creating the remote socket address
SocketAddress remoteSocketAddress = new InetSocketAddress (remoteAddress, remotePort);
// Creating request datagram
byte[] requestBuffer = requestString.getBytes ();
int requestOffset = 0;
int requestLength = requestString.length ();
// Creating the request datagram
DatagramPacket requestDatagram = new DatagramPacket (
requestBuffer, requestOffset, requestLength,
remoteSocketAddress);
// Sending the request datagram
socket.send (requestDatagram);
// Creating the response buffer
byte[] responseBuffer = new byte [2048];
// Creating the response datagram
DatagramPacket responseDatagram = new DatagramPacket(responseBuffer, 0, responseBuffer.length);
// Waiting and receiving the response datagram
socket.receive (responseDatagram);
// Getting the response buffer positions
int responseOffset = responseDatagram.getOffset ();
int responseLength = responseDatagram.getLength ();
// Creating the response string
String responseString = new String (responseBuffer, responseOffset, responseLength);
// Closing the socket
socket.close ();

// Printing the response


System.out.println (responseString);

Server
import
import
import
import
import

java.net.DatagramPacket;
java.net.DatagramSocket;
java.net.InetAddress;
java.net.InetSocketAddress;
java.net.SocketAddress;

public class Server


{
public static void main (String[] arguments) throws Exception
{
// Creating and binding the server socket
DatagramSocket socket= new DatagramSocket(new InetSocketAddress (InetAddress.getByName
("0.0.0.0"), 7654));
// Creating the request buffer
byte[] requestBuffer = new byte [2048];
// Creating the request datagram
DatagramPacket requestDatagram= new DatagramPacket(requestBuffer,0, requestBuffer.length);
// Looping
while (true) {
// Waiting and receiving the request datagram
socket.receive (requestDatagram);
// Getting the request source -- the client socket address
SocketAddress clientSocketAddress = requestDatagram.getSocketAddress ();
// Getting the request buffer positions
int requestOffset = requestDatagram.getOffset ();
int requestLength = requestDatagram.getLength ();
// Creating the request string
String requestString = new String (requestBuffer, requestOffset, requestLength);
// Creating a response string based on the request string
String responseString;
if (requestString.equals ("hello"))
responseString = "hello back";
else if (requestString.equals ("get-time"))
responseString = Long.toString (System.currentTimeMillis ());
else if (requestString.equals ("get-random"))
responseString = Long.toString ((long) Math.rint (Math.random () * 1000));
else if (requestString.equals ("quit"))
break;
else
responseString = "please?";
// Creating the response buffer
byte[] responseBuffer = responseString.getBytes ();
int responseOffset = 0;
int responseLength = responseString.length ();
// Creating the response datagram
DatagramPacket responseDatagram = new DatagramPacket (
responseBuffer, responseOffset, responseLength, clientSocketAddress);
// Sending the response datagram
socket.send (responseDatagram);
}
}
}

Assignment
1)Write a TCP client application that:
takes zero or two arguments:
the first argument is the DNS name of the server;
the second argument is the port of the server;
in case there are no arguments the name server is assumed to be hephaistos.info.uvt.ro and the port
7391;
it connects by using a TCP socket to the given server;
it waits for commands from the server and -- when applicable -- will give an answer;
it simulates a simple arithmetic calculator that has a single register to which will operate according to the
received commands -- initially the register is 0;
it handles all exception cases, and for each exception will show an error message -- using System.err -- and will
exit gracefully;
in case of errors encountered when decoding the protocol an error message -- using System.err -- will be shown
and will exit gracefully;
The protocol is as follows:

each command, command argument and response are lines -- strings ended by LF, '\n';
the commands are sent by the server, and the client only sends back an answer when it should;
the commands are:
addition command: a line containing only the character '+', followed by a line containing a number; no
answer is sent by the client; the number is added to the register;
substraction command: the same as addition command, but the first line contains just the character '-';
the number is substracted from the register;
multiplication command: '*', see above;
division command: '/', see above;
result command: a line containing only the string '='; the client will send as answer a line containing the
current value of the register; and will wait for a line from the server which validates the answer (either a
line containing ok or nok depending on the fact that the client executed the operation correctly); after
this it resumes normal operation; please note that the register is not reseted to 0, it retains its value;
(please see the example);
exit command: a line containing only the string 'exit'; the client will close the connection and exit;

Observations:

the error messages should be informative, giving the possible cause;

Example dialog:

s->c
s->c
s->c
s->c
s->c
s<-c

s->c this is something the server sends to the client;


s<-c this is something the client sends to the server;
<LF> is the '\n' character -- the line terminator;
neither s->c and s<-c are part of the protocol, they are used here only to specify the direction in which the
messages (the lines in our case) travel;
+<LF>
3<LF>
*<LF>
4<LF>
=<LF>
12<LF>

s->c
s->c
s->c
s->c
s<-c
s->c
s->c

ok<LF>
-<LF>
10<LF>
=<LF>
2<LF>
ok<LF>
exit<LF>

s->c
s<-c
s->c
s->c

=<LF>
0<LF>
ok<LF>
exit<LF>

s->c exit<LF>

Server source code


import
import
import
import
import
import
import
import
import

java.io.BufferedReader;
java.io.BufferedWriter;
java.io.InputStreamReader;
java.io.OutputStreamWriter;
java.net.InetAddress;
java.net.InetSocketAddress;
java.net.ServerSocket;
java.net.Socket;
java.util.Random;

public class Server


{
public static void main (String[] arguments) throws Exception
{
// Creating the server socket
ServerSocket server = new ServerSocket ();
// Binding the socket
server.bind (new InetSocketAddress (InetAddress.getByName ("0.0.0.0"), 7391));
// Looping
while (true) {
// Accepting a new connection => a new client socket
final Socket client = server.accept ();
// Starting a new Thread for each client
new Thread () {
public void run () {
// Catching any exceptions
try {
// Creating a reader and a writer from the socket streams
BufferedReader reader = new BufferedReader (new InputStreamReader (client.getInputStream ()));
BufferedWriter writer=new BufferedWriter (new OutputStreamWriter (client.getOutputStream ()));

// Creating a random source


Random random = new Random ();
// Initializing the register used to check the validity of the client
int register = 0;
command_loop :
while (true) {
// Selecting one of the five possible commands
int command = random.nextInt (6);
// Selecting a new argument
int argument = random.nextInt (Integer.MAX_VALUE);
switch (command) {
// In case the command is +
case 0 : {
register += argument;
writer.write ("+\n" + argument + "\n");
writer.flush ();
break;
}
// In case the command is case 1 : {
register -= argument;
writer.write ("-\n" + argument + "\n");
writer.flush ();
break;
}
// In case the command is *
case 2 : {
register *= argument;
writer.write ("*\n" + argument + "\n");
writer.flush ();
break;
}
// In case the command is /
case 3 : {
if (argument == 0)
break;
register /= argument;
writer.write ("/\n" + argument + "\n");
writer.flush ();
break;
}
case 4 : {
writer.write ("=\n");
writer.flush ();
String response = reader.readLine ();
if (response == null) {
System.err.println ("Protocol error!");

10

break command_loop;
}
String status = (Integer.toString (register) .equals (response)) ? "ok" : "nok";
writer.write (status + "\n");
writer.flush ();
break;
}
case 5 : {
writer.write ("exit\n");
writer.flush ();
String response = reader.readLine ();
if (response != null)
System.err.println ("Protocol error!");
break command_loop;
}

default :
throw new Error ();

}
// Closing the client socket
client.close ();
} catch (Throwable error) {

// Handling the possible errors


error.printStackTrace ();

}
} .start ();
}

2)
Write a UDP client that:

take two arguments, an IP address and a port number


The first argument represents an broadcast address
The second arguments represents the port number used by the server
The client detects the server IP address using the broadcast address supplied as first argument:
The client sends a datagram containing "PING" to the broadcast address (eg. 10.10.10.255), port
number 7654
The server receives the datagram and responds with a datagram containing "PONG" directly to the
client (unicast), port number is computed directly from the previous datagram
The client responds with a datagram containing "PING-PONG" directly to the server which repplyed
(unicast);
If the client receives any other message than "PONG" it should continue to wait for the right message;

Important: When sending the PING-PONG message, be careful to send it on the socket address from where the
datagram came. See the method getSocketAddress from DatagramPacket class.
11

Example dialog
client->broadcast PING
server->client PONG
client->server PING-PONG

Server Source
import
import
import
import

java.net.DatagramPacket;
java.net.DatagramSocket;
java.net.InetAddress;
java.net.InetSocketAddress;

public class Server {


public static void main(String[] args) throws Exception {
// Creating and binding the server socket
DatagramSocket socket = new DatagramSocket(new InetSocketAddress(
InetAddress.getByName("0.0.0.0"), 7654));
// Creating the request buffer
byte[] requestBuffer = new byte[2048];
// Creating the request datagram
DatagramPacket requestDatagram = new DatagramPacket(requestBuffer, 0,
requestBuffer.length);
String responseString;
byte[] responseBuffer;
int responseOffset = 0;
int reponseLength;
while (true) {
socket.receive(requestDatagram);
InetAddress clientAddr = requestDatagram.getAddress();
requestBuffer = requestDatagram.getData();
String request = new String(requestBuffer, 0, requestDatagram.getLength());
if (request.equals("PING")) { // Send Pong back
System.out.println("PING <- " + clientAddr.getHostAddress());
responseString = "PONG";
responseBuffer = responseString.getBytes();
reponseLength = responseString.length();
DatagramPacket responseDatagram=new DatagramPacket(
responseBuffer,responseOffset,reponseLength);
responseDatagram.setAddress(clientAddr);
responseDatagram.setPort(requestDatagram.getPort());
socket.send(responseDatagram);
System.out.println("PONG -> " + clientAddr.getHostAddress());

} else if (request.startsWith("PING-PONG")) {
System.out.println("ESTABLISHED <-> " + clientAddr.getHostAddress());
}
}
}

12

You might also like