Sei sulla pagina 1di 18

Tutorials About RSS

Tech and Media Labs

This site uses cookies to improve the user experience. OK

Java Networking

1. Java Networking
2. Java Networking: Socket
3. Java Networking: ServerSocket
4. Java Networking: UDP DatagramSocket
5. Java Networking: URL + URLConnection
6. Java Networking: JarURLConnection
7. Java Networking: InetAddress
8. Java Networking: Protocol Design

Java Networking: Protocol Design


Client - Server Roundtrips
Demarcating the End of Requests and Responses
Penetrating Firewalls

Jakob Jenkov
Last update: 2014-06-23

If you are designing a client-server system you may also have to design a communication protocol between the client
and the server. Of course, sometimes this protocol is already have been decided for you, e.g. HTTP, XML-RPC (XML
over HTTP), or SOAP (also XML over HTTP). But once in a while the protocol decision is open, so let's look at a few
issued you may want to think about when designing your client - server protocol:

1. Client - Server Roundtrips


2. Demarcating the end of requests and responses
3. Penetrating Firewalls

Client - Server Roundtrips


When a client and server communicates to perform some operation they exchange information. For instance, the client
will ask for a service to be performed, and the server will attempt to perform it, and send back a response telling the
client of the result. Such an exchange of information between the client and server is called a roundtrip.
Client Server

Send Request

Receive Response

A Client - Server Roundtrip

When a computer (client or server) sends data to another computer over the internet it takes some time from the time
the data is sent, to the data is received at the other end. This is the time it takes the data to travel over the internet. This
time is called latency.

The more roundtrips you have in your protocol, the slower the protocol becomes, especially if latency is high. The
HTTP protocol consists of only a single request and a single response to perform its service. A single roundtrip in
other words. The SMTP protocol on the other hand, consists of several roundtrips between the client and the server
before an email is sent.

The only reason to break your protocol up into multiple roundtrips is, if you have a large amount of data to send from
the client to the server. You have two options in this case:

1. Send the header information in a separate roundtrip.


2. Break the message body up into smaller chunks.

Sending the header in a separate roundtrip (the first) can be smart if the server can do some initial pre-validation of e.g.
header information. If that header information is invalid, sending the large body of data would have been a waste
anyways.

If the network connection fails while you are transfering a large amount of data, you may have to resend all that data
from scratch. By breaking the data up into smaller chunks you only have to resend the chunks from the chunk where
the network connection failed and onwards. The successfully transfered chunks do not have be resent.

Demarcating the End of Requests and Responses


If your protocol allows multiple requests to be send over the same connection, you need some way for the server to
know when one request ends, and a new begins. The client also needs to know when one response ends, and
another begins.

You have two options for demarcating the end of a request:

1. Send the length in bytes of the request in the beginning of the request.
2. Send an end-of-request marker after the request data.

HTTP uses the first mechanism. In one of the request headers the "Content-Length" is sent. This header tells how
many bytes after the headers that belongs to the request.

The advantage of this model is that you don't have the overhead of the end-of-request marker. Nor do you have to
encode the body of the data to avoid the data looking like the end-of-request marker.

The disadvantage of the first method is that the sender must know how many bytes are transfered before the data is
transfered. If the data is generated dynamically you will first have to buffer all the data before sending it, to count the
number of bytes.

By using an end-of-request marker you don't have to know how many bytes you are sending. You just need to send an
end-of-request marker at the end of the data. You do, however, have to make sure that the data sent does not contain
any data that can be mistaken for the end-of-request marker. Here one way to do that:

Lets say the end-of-request marker is the byte value 255. Of course the data can contain the value 255 too. So, for
each byte in the data that contains the value 255 you add an extra byte, also with the value 255. The end-of-request
marker is changed from the byte value 255 to 255 followed by the value 0. Here are the encodings summarized:

255 in data --> 255, 255


end-of-request --> 255, 0

The sequence 255, 0 can never occur in the data, since you are changing all 255's to 255,255. And, a 255,255,0 will
not be mistaken for a 255,0. The first 255's will be interpreted together, and the last 0 by itself.
Penetrating Firewalls
Most firewalls block all other traffic than the HTTP protocol. Therefore it can be a good idea to layer your protocol
ontop of HTTP, like XML-RPC, SOAP and REST does.

To layer your protocol ontop of HTTP you send your data forth and back between client and server inside HTTP
requests and responses. Remember, an HTTP request and response can contain more than just text or HTML. You
can send binary data inthere too.

The only thing that can be a little weird by layering your request ontop of the HTTP protocol is that an HTTP request
must contain a "Host" header field. If you are designing a P2P protocol ontop of HTTP, your peers most likely won't be
running multiple "Hosts". This required header field is in that situation an unnecessary overhead (but a small one).

Tweet
Jakob Jenkov

Copyright Jenkov Aps

All Trails

Trail TOC

Page TOC

Previous

Next
Tutorials About RSS
Tech and Media Labs

This site uses cookies to improve the user experience. OK

Java Networking

1. Java Networking
2. Java Networking: Socket
3. Java Networking: ServerSocket
4. Java Networking: UDP DatagramSocket
5. Java Networking: URL + URLConnection
6. Java Networking: JarURLConnection
7. Java Networking: InetAddress
8. Java Networking: Protocol Design

Java Networking: ServerSocket


Creating a ServerSocket
Listening For Incoming Connections
Closing Client Sockets
Closing Server Sockets

Jakob Jenkov
Last update: 2014-06-25

In order to implement a Java server that listens for incoming connections from clients via TCP/IP, you need to use a
java.net.ServerSocket . In case you prefer to use Java NIO instead of Java Networking (standard API), then
you can also use a ServerSocketChannel instead of the java.net.ServerSocket.

Creating a ServerSocket
Here is a simple code example that creates a ServerSocket that listens on port 9000:

ServerSocket serverSocket = new ServerSocket(9000);

Listening For Incoming Connections


In order to accept incoming connections you must call the ServerSocket.accept() method. The accept()
method returns a Socket which behaves like an ordinary Java Socket. Here is how that looks:

ServerSocket serverSocket = new ServerSocket(9000);

boolean isStopped = false;


while(!isStopped){
Socket clientSocket = serverSocket.accept();

//do something with clientSocket


}
Only one incoming connection is opened for each call to the accept() method.

Additionally, incoming connections can only be accepted while the thread running the server has called accept().
All the time the thread is executing outside of this method no clients can connect. Therefore the "accepting" thread
normally passes incoming connections (Socket's) on to a pool of worker threads, who then communicate with the
client. See the tutorial trail Java Multithreaded Servers for more information on multithreaded server design.

Closing Client Sockets


Once a client request is finished, and no further requests will be received from that client, you must close that Socket,
just like you would close a normal client Socket. This is done by calling:

socket.close();

Closing Server Sockets


Once the server is to shut down you need to close the ServerSocket. This is done by calling:

serverSocket.close();

Next: Java Networking: UDP DatagramSocket

Tweet
Jakob Jenkov

Copyright Jenkov Aps

All Trails

Trail TOC

Page TOC

Previous

Next
Tutorials About RSS
Tech and Media Labs

This site uses cookies to improve the user experience. OK

Java Networking

1. Java Networking
2. Java Networking: Socket
3. Java Networking: ServerSocket
4. Java Networking: UDP DatagramSocket
5. Java Networking: URL + URLConnection
6. Java Networking: JarURLConnection
7. Java Networking: InetAddress
8. Java Networking: Protocol Design

Java Networking: Socket


Creating a Socket
Writing to a Socket
Reading from a Socket
Closing a Socket

Jakob Jenkov
Last update: 2014-06-25

In order to connect to a server over the internet (via TCP/IP) in Java, you need to create a java.net.Socket and
connect it to the server. Alternatively you can use a Java NIO SocketChannel, in case you prefer to use Java NIO.

Creating a Socket
This code example connects to the server with IP address 78.46.84.171 on port 80. That server happens to be my
web server (www.jenkov.com), and port 80 is the web servers port.

Socket socket = new Socket("78.46.84.171", 80);

You can also use a domain name instead of an IP address, like this:

Socket socket = new Socket("jenkov.com", 80);

Writing to a Socket
To write to a Java Socket you must obtain its OutputStream. Here is how that is done:
Socket socket = new Socket("jenkov.com", 80);
OutputStream out = socket.getOutputStream();

out.write("some data".getBytes());
out.flush();
out.close();

socket.close();

That's how simple it is!

Don't forget to call flush() when you really, really want the data sent across the internet to the server. The
underlying TCP/IP implementation in your OS may buffer the data and send it in larger chunks to fit with with the size
of TCP/IP packets.

Reading from a Socket


To read from a Java Socket you will need to obtains its InputStream. Here is how that is done:

Socket socket = new Socket("jenkov.com", 80);


InputStream in = socket.getInputStream();

int data = in.read();


//... read more data...

in.close();
socket.close();

Pretty simple, right?

Keep in mind that you cannot always just read from the Socket's InputStream until it returns -1, as you can when
reading a file. The reason is that -1 is only returned when the server closes the connection. But a server may not
always close the connection. Perhaps you want to send multiple requests over the same connection. In that case it
would be pretty stupid to close the connection.

Instead you must know how many bytes to read from the Socket's InputStream. This can be done by either the
server telling how many bytes it is sending, or by looking for a special end-of-data character.

Closing a Socket
When you are done using a Java Socket you must close it to close the connection to the server. This is done by
calling the Socket.close() method, like this:

Socket socket = new Socket("jenkov.com", 80);

socket.close();

Next: Java Networking: ServerSocket

Tweet
Jakob Jenkov

Copyright Jenkov Aps

All Trails

Trail TOC
Tutorials About RSS
Tech and Media Labs

This site uses cookies to improve the user experience. OK

Java Networking

1. Java Networking
2. Java Networking: Socket
3. Java Networking: ServerSocket
4. Java Networking: UDP DatagramSocket
5. Java Networking: URL + URLConnection
6. Java Networking: JarURLConnection
7. Java Networking: InetAddress
8. Java Networking: Protocol Design

Java Networking: UDP DatagramSocket


UDP vs. TCP
Sending Data via a DatagramSocket
Receiving Data via a DatagramSocket

Jakob Jenkov
Last update: 2014-06-23

DatagramSocket's are Java's mechanism for network communication via UDP instead of TCP. UDP is still layered
ontop of IP. You can use Java's DatagramSocket both for sending and receiving UPD datagrams.

UDP vs. TCP


UDP works a bit differently from TCP. When you send data via TCP you first create a connection. Once the TCP
connection is established TCP guarantess that your data arrives at the other end, or it will tell you that an error
occurred.

With UDP you just send packets of data (datagrams) to some IP address on the network. You have no guarantee that
the data will arrive. You also have no guarantee about the order which UDP packets arrive in at the receiver. This
means that UDP has less protocol overhead (no stream integrity checking) than TCP.

UDP is appropriate for data transfers where it doesn't matter if a packet is lost in transition. For instance, imagine a
transfer of a live TV-signal over the internet. You want the signal to arrive at the clients as close to live as possible.
Therefore, if a frame or two are lost, you don't really care. You don't want the live broadcast to be delayed just to make
sure all frames are shown at the client. You'd rather skip the missed frames, and move directly to the newest frames at
all times.

This could also be the case with a surveillance camera broadcasting over the internet. Who cares what happened in
the past, when you are trying to monitor the present. You don't want to end up being 30 seconds behind reality, just
because you want to show all frames to the person monitoring the camera. It is a bit different with the storage of the
camera recordings. You may not want to lose a single frame when recording the images from the camera to disk. You
may rather want a little delay, than not have those frames to go back and examine, if something important occurs.
Sending Data via a DatagramSocket
To send data via Java's DatagramSocket you must first create a DatagramPacket. Here is how that is done:

byte[] buffer = new byte[65508];


InetAddress address = InetAddress.getByName("jenkov.com");

DatagramPacket packet = new DatagramPacket(


buffer, buffer.length, address, 9000);

The byte buffer (the byte array) is the data that is to be sent in the UDP datagram. The length of the above buffer,
65508 bytes, is the maximum amount of data you can send in a single UDP packet.

The length given to the DatagramPacket constructor is the length of the data in the buffer to send. All data in the
buffer after that amount of data is ignored.

The InetAddress instance contains the address of the node (e.g. server) to send the UDP packet to. The
InetAddress class represents an IP address (Internet Address). The getByName() method returns an
InetAddress instance with the IP address matching the given host name.

The port parameter is the UDP port the server to receiver the data is listeing on. UDP and TCP ports are not the same.
A computer can have different processes listening on e.g. port 80 in UDP and in TCP at the same time.

To send the DatagramPacket you must create a DatagramSocket targeted at sending data. Here is how that is
done:

DatagramSocket datagramSocket = new DatagramSocket();

To send data you call the send() method, like this:

datagramSocket.send(packet);

Here is a full example:

DatagramSocket datagramSocket = new DatagramSocket();

byte[] buffer = "0123456789".getBytes();


InetAddress receiverAddress = InetAddress.getLocalHost();

DatagramPacket packet = new DatagramPacket(


buffer, buffer.length, receiverAddress, 80);
datagramSocket.send(packet);

Receiving Data via a DatagramSocket


Receiving data via a DatagramSocket is done by first creating a DatagramPacket and then receiving data into it
via the DatagramSocket's receive() method. Here is an example:

DatagramSocket datagramSocket = new DatagramSocket(80);

byte[] buffer = new byte[10];


DatagramPacket packet = new DatagramPacket(buffer, buffer.length);

datagramSocket.receive(packet);

Notice how the DatagramSocket is instantiated with the parameter value 80 passed to its constructor. This
parameter is the UDP port the DatagramSocket is to receive UDP packets on. As mentioned earlier, TCP and UDP
ports are not the same, and thus do not overlap. You can have two different processes listening on both TCP and UDP
port 80, without any conflict.

Second, a byte buffer and a DatagramPacket is created. Notice how the DatagramPacket has no information
about the node to send data to, as it does when creating a DatagramPacket for sending data. This is because we
are going to use the DatagramPacket for receiving data, not sending it. Thus no destination address is needed.

Finally the DatagramSocket's receive() method is called. This method blocks until a DatagramPacket is
received.

The data received is located in the DatagramPacket's byte buffer. This buffer can be obtained by calling:
byte[] buffer = packet.getData();

How much data was received in the buffer is up to you to find out. The protocol you are using should specify either
how much data is sent per UDP packet, or specify an end-of-data marker you can look for instead.

A real server program would probably call the receive() method in a loop, and pass all received
DatagramPacket's to a pool of worker threads, just like a TCP server does with incoming connections (see Java
Multithreaded Servers for more details).

Next: Java Networking: URL + URLConnection

Tweet
Jakob Jenkov

Copyright Jenkov Aps

All Trails

Trail TOC

Page TOC

Previous

Next
Tutorials About RSS
Tech and Media Labs

This site uses cookies to improve the user experience. OK

Java Networking

1. Java Networking
2. Java Networking: Socket
3. Java Networking: ServerSocket
4. Java Networking: UDP DatagramSocket
5. Java Networking: URL + URLConnection
6. Java Networking: JarURLConnection
7. Java Networking: InetAddress
8. Java Networking: Protocol Design

Java Networking: InetAddress


Creating an InetAddress Instance
Additional InetAddress Methods

Jakob Jenkov
Last update: 2014-06-23

The InetAddress is Java's representation of an IP address. Instances of this class are used together with UDP
DatagramSockets and normal Socket's and ServerSocket's.

Creating an InetAddress Instance


InetAddress has no public contructor, so you must obtain instances via a set of static methods.

Here is how to get the InetAddress instance for a domain name:

InetAddress address = InetAddress.getByName("jenkov.com");

And here is how to get the InetAddress matching a String representation of an IP address:

InetAddress address = InetAddress.getByName("78.46.84.171");

And, here is how to obtain the IP address of the localhost (the computer the program is running on):

InetAddress address = InetAddress.getLocalHost();

Additional InetAddress Methods


The InetAddress class has a lot of additional methods you can use. For instance, you can obtain the IP address as
a byte array by calling getAddress() etc. To learn more about these methods, it is easier to read the JavaDoc for
the InetAddress class though.

Next: Java Networking: Protocol Design

Tweet
Jakob Jenkov

Copyright Jenkov Aps

All Trails

Trail TOC

Page TOC

Previous

Next
Tutorials About RSS
Tech and Media Labs

This site uses cookies to improve the user experience. OK

Java Networking

1. Java Networking
2. Java Networking: Socket
3. Java Networking: ServerSocket
4. Java Networking: UDP DatagramSocket
5. Java Networking: URL + URLConnection
6. Java Networking: JarURLConnection
7. Java Networking: InetAddress
8. Java Networking: Protocol Design

Java Networking
Jakob Jenkov
Last update: 2014-06-25

Java has a reasonably easy-to-use builtin networking API which makes it easy to communicate via TCP/IP sockets or
UDP sockets over the internet. TCP is typically used more often than UDP, but both options are explained in this
tutorial.

There are three other tutorials here at tutorials.jenkov.com that are relevant to this Java networking tutorial. These
are:

1. Java IO Tutorial
2. Java NIO Tutorial
3. Java Multithreaded Servers Tutorial

Even though the Java Networking APIs enable you to open and close network connections via sockets, all
communication happens via the Java IO classes InputStream and OutputStream.

Alternatively you can use the networking classes in the Java NIO API. These classes are similar to the classes found
in the Java Networking API, except the Java NIO API can work in non-blocking mode. Non-blocking mode may give a
performance boost in some situations.

Java TCP Networking Basics


Typically a client opens a TCP/IP connection to a server. The client then starts to communicate with the server. When
the client is finished it closes the connection again. Here is an illustration of that:
Client Server

Open Connection

Send Request

Receive Response

Close Connection

A client may send more than one request through an open connection. In fact, a client can send as much data as the
server is ready to receive. The server can also close the connection if it wants to.

Java Socket's and ServerSocket's


When a client wants to open a TCP/IP connection to a server, it does so using a Java Socket. The socket is told what
IP address and TCP port to connect to and the rest is done by Java.

If you want to start a server that listens for incoming connections from clients on some TCP port, you have to use a
Java ServerSocket. When a client connects via a client socket to a server's ServerSocket, a Socket is assigned on
the server to that connection. The client and server now communicates Socket-to-Socket.

Socket's and ServerSocket's are covered in more detail in later texts.

Java UDP Networking Basics


UDP works a bit differently from TCP. Using UDP there is no connection between the client and server. A client may
send data to the server, and the server may (or may not) receive this data. The client will never know if the data was
received at the other end. The same is true for the data sent the other way from the server to the client.

Because there is no guarantee of data delivery, the UDP protocol has less protocol overhead.

There are several situations in which the connectionless UDP model is preferable over TCP. These are covered in
more detail in the text on Java's UDP DatagramSocket's.

Next: Java Networking: Socket

Tweet
Jakob Jenkov

Copyright Jenkov Aps

All Trails

Trail TOC

Page TOC

Previous
Tutorials About RSS
Tech and Media Labs

This site uses cookies to improve the user experience. OK

Java Networking

1. Java Networking
2. Java Networking: Socket
3. Java Networking: ServerSocket
4. Java Networking: UDP DatagramSocket
5. Java Networking: URL + URLConnection
6. Java Networking: JarURLConnection
7. Java Networking: InetAddress
8. Java Networking: Protocol Design

Java Networking: JarURLConnection


Jakob Jenkov
Last update: 2014-06-23

Java's JarURLConnection class is used to connect to a Java Jar file. Once connected you can obtain information
about the contents of the Jar file. Here is a simple example:

String urlString = "http://butterfly.jenkov.com/"


+ "container/download/"
+ "jenkov-butterfly-container-2.9.9-beta.jar";

URL jarUrl = new URL(urlString);


JarURLConnection connection = new JarURLConnection(jarUrl);

Manifest manifest = connection.getManifest();

JarFile jarFile = connection.getJarFile();

//do something with Jar file...

...

Next: Java Networking: InetAddress

Tweet
Jakob Jenkov
Copyright Jenkov Aps

All Trails

Trail TOC

Page TOC

Previous

Next
Tutorials About RSS
Tech and Media Labs

This site uses cookies to improve the user experience. OK

Java Networking

1. Java Networking
2. Java Networking: Socket
3. Java Networking: ServerSocket
4. Java Networking: UDP DatagramSocket
5. Java Networking: URL + URLConnection
6. Java Networking: JarURLConnection
7. Java Networking: InetAddress
8. Java Networking: Protocol Design

Java Networking: URL + URLConnection


HTTP GET and POST
URLs to Local Files

Jakob Jenkov
Last update: 2014-06-23

The java.net package contains two interesting classes: The URL class and the URLConnection class. These
classes can be used to create client connections to web servers (HTTP servers). Here is a simple code example:

URL url = new URL("http://jenkov.com");

URLConnection urlConnection = url.openConnection();


InputStream input = urlConnection.getInputStream();

int data = input.read();


while(data != -1){
System.out.print((char) data);
data = input.read();
}
input.close();

HTTP GET and POST


By default the URLConnection sends an HTTP GET request to the webserver. If you want to send an HTTP POST
request instead, call the URLConnection.setDoOutput(true) method, like this:

URL url = new URL("http://jenkov.com");

URLConnection urlConnection = url.openConnection();


urlConnection.setDoOutput(true);

Once you have set called setDoOutput(true) you can open the URLConnection's OutputStream like this:
OutputStream output = urlConnection.getOutputStream();

Using this OutputStream you can write any data you want in the body of the HTTP request. Remember to URL
encode it (search Google for an explanation of URL encoding).

Remember to close the OutputStream when you are done writing data to it.

URLs to Local Files


The URL class can also be used to access files in the local file system. Thus the URL class can be a handy way to
open a file, if you need your code to not know whether the file came from the network or local file system.

Here is an example of how to open a file in the local file system using the URL class:

URL url = new URL("file:/c:/data/test.txt");

URLConnection urlConnection = url.openConnection();


InputStream input = urlConnection.getInputStream();

int data = input.read();


while(data != -1){
System.out.print((char) data);
data = input.read();
}
input.close();

Notice how the only difference from accessing a file on a web server via HTTP is the the URL:
"file:/c:/data/test.txt".

Next: Java Networking: JarURLConnection

Tweet
Jakob Jenkov

Copyright Jenkov Aps

All Trails

Trail TOC

Page TOC

Previous

Next

Potrebbero piacerti anche