- [Tim] Alright, so we've finished our discussion
on TCP/IP in the last video.
Now it's time to look at another protocol, UDP,
and that stands for User Datagram Protocol.
Now, when using TCP,
some handshaking has to take place
between the server and the client.
So, in other words,
the client has to connect to the server,
and the server has to accept that connexion.
So, the client sends a request,
and the server sends a response.
So, it's a two way connexion,
and there's tight coupling
between the client and the server.
Now, the TCP protocol also performs error checking
and will resend messages that don't make it to the server.
So, it's quite a reliable protocol,
but that reliability requires overhead
which can ultimately affect performance.
Now, when using UDP there's no handshaking at all,
and the destination host,
which may or may not be a server,
doesn't actually send any responses to the message sender.
So, you use it when you don't need a reliable connexion
or a two-way connexion
or when speed is essential.
So, if you require a response
to a message you send over the network,
then you wouldn't use UDP.
So, UDP uses datagrams,
and a datagram is a self-contained message,
and it's not guaranteed to arrive at its destination.
Now, UDP is often used for time-sensitive communication
and when losing the odd message
or packet here or there won't matter.
For example, voice over IP applications
like Skype and video streaming usually use UDP,
because speed is more important
than ensuring that absolutely every package arrives.
Our eyes won't notice
if the occasional package isn't received,
for example, when we're watching a video.
Also, the data arriving at the client
is immediately replaced by more data
so it's not critical that all the messages reach the client.
As mentioned, UDP is used for time sensitive communication
because the overhead involved with TCP
is actually significant,
and, so, data can be sent much more quickly using UDP.
So, as usual, which protocol to use
will depend on the application that you're looking to write.
So, we're going to rewrite
the client and server applications to use UDP.
And you can see that I've actually created
two new projects here.
I've got a UDP server project on the left,
and the UDP client project on the right.
So, starting with a fresh base basically.
And we're not gonna worry about threads this time
since you now know how to do that
from the TCP kind that we worked on.
And for this demo,
I just want to show how to send data using a datagram.
In a real-world application,
you would definitely want to use threads
like we did in the last few videos.
Right, so let's start with the server side of things.
Here we're gonna write our server code.
You're gonna start with a try,
and we're going to catch, firstly, a socket exception.
And we'll just print out a message if we do get one,
a look at message will do us.
We also want to catch an IO exception.
We wanna catch 'em in that order as well.
Same deal there.
We'll just put IO exception
plus e dot get message.
Alright, in terms of the code,
we're gonna start by datagram socket.
This is Java dot net as you can see there.
Socket is equal to new datagram socket 5,000.
We're gonna create an infinite loop.
So, while true.
And then we're gonna do
byte array buffer
equals new byte 50.
And, we're gonna do datagram packet.
Packet is equal to new datagram packet,
and that's going to be buffer, buffer dot length.
And we're gonna do socket dot receive packet.
And then we're just going to print out that text.
So, text received
is plus
new string buffer.
So, just output that the console.
Alright, so that's actually our code,
pretty straight forward.
First thing,
notice that we're now creating a datagram socket on line 12.
And that accepts a port number.
And inside the loop,
we're creating that byte array that I mentioned on line 15.
And that's going to accept data from the socket.
We then create the datagram packet itself on line 16.
And that's going to be populated
with whatever is received from the socket.
And, finally,
we're calling the datagram socket dot receive method
on line 17,
passing the packet as a parameter
so it can actually fill that packet with the content.
And this method actually blocks until data is received.
You know, once the data has arrived,
the buffer you pass to the datagram packet constructor
will contain the data,
that packet in this case on line 17,
and we're then printing that to the console on line 18.
Now, it's important to note
that the socket dot receive method
doesn't create an end-to-end connexion
between the server and the client.
So, it doesn't return anything
the server can use to send data back to the client.
Now when using TCP,
the accept method did create an end-to-end connexion.
So, it returned a socket
the server could use to communicate with the client,
but that's not the case here.
Alright, so let's actually go back and code the client now.
Alright, so the actual code:
We're gonna do a try again.
We're going to catch a socket timeout exception,
which we talked about in the previous video.
And, if we get one of those,
we're just gonna print out a message to socket timed out.
And we'll also catch an IO exception
if you get one.
That should just say client error.
That's e dot get message.
Alright, now in terms of the code, though,
we're gonna start with I net address.
Java dot net again.
Address is equal to I net address
dot get local host.
Then we're gonna do datagram socket.
Java dot net again.
Datagram socket is equal to new datagram socket.
Scanner, scanner.
Accepted import.
Java dot util equals new scanner.
That's gonna be system dot in.
And string echo string.
Then we need a do while loop.
So, do.
And we're gonna do...
We're gonna print out a message.
Enter string to be echoed.
Then echo string is equal to scanner dot next line.
So, we're just getting a line of input.
That's what we've done previously.
We're now gonna create a buffer.
So, buffer array.
Buffer is equal to echo string dot get byte.
So, we're just converting it to a byte array essentially.
Then we're gonna do a datagram packet.
Packet is equal to new datagram packet.
And it's buffer,
which is gonna be buffer dot length,
address, which we defined on line 14,
and 5,000,
which will obviously be the port there.
So, basically, we're just passing
the buffer, the length of the buffer, the I net address,
which is local host,
and the port.
And then we're gonna send it.
So, diagram socket dot send our packet.
And the condition for the while loop is gonna be
while
not
echo string
dot equals
exit.
Sounds before we're gonna allow
exit, the typing of exit
to actually close down the app.
Alright, so,
firstly, we're actually getting the address
of the host we'd like to send data to.
So, we're getting local host
because we're gonna be running the server on this machine.
So, obviously, if this was another machine
that you wanted to connect to,
you'd be setting up the IP address there,
but we're using the get local host method
to get the local host.
Now, there's also an I net address dot get by name method,
and that lets use pass a host name to it.
And it actually returns the I net address of the host.
So, it's the
get by name.
So, you'd use that
if you're running the server on a different machine.
Alright, so next after we've done that
we're creating a datagram socket to the,
or that this client's gonna use.
And note that the socket
isn't associated with a port number.
And after that,
we're just going through getting some input from the user
and converting the input to a byte array.
And then we're done here creating the packet.
Now, recall that I said
the datagram is a self-contained message.
Now it's clearer what I meant by that, hopefully,
'cause you can see what we're doing here.
The message contains not only the data
but also the address and the port number.
So, if the server wants to respond,
it can get all the information it needs
from the datagram packet.
In the TCP case,
once the end-to-end connexion was established,
the socket had all the information required
to communicate with the client.
So, the server didn't have to get the information
from each message.
Alright, so after we've created the datagram packet,
we're sending it to the server on line 27.
And the rest of the code is just error handling
and enabling us to exit the do while loop.
Alright, so let's actually try this out.
So, I'm gonna start by firstly running the server.
Move that down to the bottom,
and we can see something there.
Alright.
And let's do the same to the client.
Let's run the client.
Alright, so I'll type in a string now.
We'll see what happens.
We'll put "Tim was here."
And you can see that the server has come up
and actually put that text
or shows us that text on the screen here.
"Tim was here."
And note that we're not getting an echo back
from the server to the client this time,
because it's no longer sending anything back to the client.
But we can type in some more strings.
And note, also, that at the moment,
we're actually seeing the complete buffer showing here.
So, we've got all these null characters.
So, if we just have a look at the code again.
Alright, the problem is at the moment,
where we're seeing these characters
is we've got a byte array buffer equals new byte 50.
So, we've just allocated 50 bytes for our byte array,
and we're saving the packet into that,
and when we're trying to extract only the characters
that aren't null there,
we're just actually dumping everything
and creating a new string called buffer.
So, if we wanted to only output the number of...
You know, the information related
to the number of characters received, the actual message,
we can change this by me creating a new string buffer
turning return the actual amounts.
I will start with zero comma,
and then we can do packet dot length
or dot get length.
And that should now give us a string of just the actual
right size that was actually retrieved
instead of actually trying to dump all output,
the entire byte array.
So, let's actually just go back
and test that with another message.
What we'll have to do is just close down
our server and client and start again.
I guess, technically,
we don't have to close down the client,
'cause there's not a connexion anymore.
But we'll do that anyway.
So we'll just run this again now.
And we'll go back and run our client again.
"Testing 1, 2, 3."
You can see we're now correctly showing the output
minus all the other trailing characters.
"Tim was here."
So, that's working fine.
And let's just also exit to make sure exit still works.
Exit's finished here, and...
Obviously we'd need to go back
and actually close down the client, the server rather,
manually as well,
if you want to do that.
And also don't forget again, in a real-world application,
we would be using threads here,
but we're not doing that
because we've seen how to do that
in a previous video in this section of the course.
Alright, now, before I move on to the high-level API,
let's see how the server would get the information it needs
from a packet to be able to send data back to the client.
So, we're gonna actually update this server code.
So, let's go ahead and do that.
So, we're gonna add some code now
after the system dot out dot print length.
And we're gonna do string
return string
is equal to
echo colon
space plus
new string
buffer.
And we'll do the same thing:
zero and then packet dot get length
to return just the data or send back only the data
that was sent back, or sent to, this server.
And we'll
byte array
buffer two
is equal to return string dot get bytes.
And we're going
I net address, a Java dot net address,
is equal to
packet dot get address.
Then we're going
int port
is equal to
packet dot get port
And then we're going
packet
to be equal to
new datagram packet,
this time it's gonna be buffer two,
buffer two dot length
address port.
So, we're constructing a packet
similar to what we've done in the client.
We're gonna be
socket dot send packet.
So, once the server's received a packet,
it uses the address and port in the received packet
to create a new datagram packet
which it then sends back to the client.
Now, we could've used the same byte array
for both input and output,
but we're using two different ones here for clarity.
The code gets the I net address
and the port from the packet it received,
and that's because
there's no permanent end-to-end connexion
between the server and the client.
In fact, UDP's often referred
to as a connectionless protocol for that reason.
So, you can see that we've retrieved the address
and the port from the packet
that was sent to us.
Then we've constructed a new datagram packet
with all the information in the string which is gonna be,
basically, an echo of what was sent to us,
which is basically the contents of the message
that was sent to to us with the words echo colon and a space
prefixed to that.
And then we're sending it using a socket dot send package.
Right, so now we've done that.
We'll actually run the server,
and what we need to do is change the client code
so that the client code can expect a response,
or it gets a response we can actually output
something to that...
We can actually output the response.
So, let's just bring that up on the screen.
Now keep in mind that when using UDP,
you often don't want a response.
We're setting up the client at the moment, now,
waiting for a response purely for demonstration purposes.
But, again, you wouldn't necessarily do that
in a real-world application.
Alright, so we've got our code at the moment
that sends the packet.
What we're going to do now
is put some code in here that actually receives it.
So,
byte array
buffer two
is equal to
new byte array.
And we'll make it 50, allow 50 characters.
Packet is equal to new datagram packet,
and it's gonna be
buffer two
buffer two dot length,
allocating our package, packet so it can receive the data.
And we're gonna do
datagram socket dot receive packet.
And we can print out a message
text received is
plus new string
buffer two zero buffer two dot
Sorry, that should be package,
'cause we want to actually get the package
to tell us how much or how long the data was,
dot get length.
Alright, so that should be it.
So, the other code we're adding here
from lines 29 through 32
includes the byte array so we can store the data
coming back to us.
We're creating a packet based on that byte array
so it can be used to receive the data.
We're actually receiving the data itself on line 31
and then outputting it on line 32.
And, again, note that we're blocking here on line 31,
so it's gonna sit there and wait
until it receives or gets the server's message.
So, let's actually try
this code out.
So, I've got the server still running.
Let's now run the client.
Type in "Tim was here."
We're got the text appearing over here on the server,
"Tim was here" received,
and text received is echo colon space "Tim was here."
So, clearly, the server sent that data back to the client.
And, again, to finish,
we'll have to just type exit,
closes down the client,
but we'll need to close down the server manually,
like so.
Alright, so that's UDP at a low level.
So, at this point
we've now finished looking at the low-level API,
and you can see that, even though it's quite low level,
we're still working with abstractions here.
All the complexity of handshaking in constructing packages
is largely taken care of by Java.
So, you're free to focus on the data you want to send,
but as you'll start seeing in the next video,
the high-level API
hides even more of these details from you.
But we'll start working that high-level API
in the next video.