Java Networking Tutorialshttps://owt.codejava.net/java-se/networkingMon, 20 May 2024 05:50:23 -0500Joomla! - Open Source Content Managementen-gbJava HttpURLConnection to download file from an HTTP URLhttps://owt.codejava.net/java-se/networking/use-httpurlconnection-to-download-file-from-an-http-urlhttps://owt.codejava.net/java-se/networking/use-httpurlconnection-to-download-file-from-an-http-url

In this post, I will guide you how to write Java code to download files from web server programmatically.

You know, in Java, we can use the classes URLand HttpURLConnection in the package java.net to programmatically download a file from a given URL by following these steps:

    • Create a URL object for a given URL. The URL can be either:
      • A direct link which contains the real file name at the end, for example:

http://jdbc.postgresql.org/download/postgresql-9.2-1002.jdbc4.jar

 

      • An indirect link which does not contain the real file name, for example:

http://myserver.com/download?id=1234

    • Open connection on the URL object – which would return an HttpURLConnection object if the URL is an HTTP URL.
    • Open the input stream of the opened connection.
    • Create an output stream to save file to disk.
    • Repeatedly read array of bytes from the input stream and write them to the output stream, until the input stream is empty.
    • Close the input stream, the output stream and the connection.

For the purpose of reusability, we create a utility class as follows:

package net.codejava.networking;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;

/**
 * A utility that downloads a file from a URL.
 * @author www.codejava.net
 *
 */
public class HttpDownloadUtility {
	private static final int BUFFER_SIZE = 4096;

	/**
	 * Downloads a file from a URL
	 * @param fileURL HTTP URL of the file to be downloaded
	 * @param saveDir path of the directory to save the file
	 * @throws IOException
	 */
	public static void downloadFile(String fileURL, String saveDir)
			throws IOException {
		URL url = new URL(fileURL);
		HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
		int responseCode = httpConn.getResponseCode();

		// always check HTTP response code first
		if (responseCode == HttpURLConnection.HTTP_OK) {
			String fileName = "";
			String disposition = httpConn.getHeaderField("Content-Disposition");
			String contentType = httpConn.getContentType();
			int contentLength = httpConn.getContentLength();

			if (disposition != null) {
				// extracts file name from header field
				int index = disposition.indexOf("filename=");
				if (index > 0) {
					fileName = disposition.substring(index + 10,
							disposition.length() - 1);
				}
			} else {
				// extracts file name from URL
				fileName = fileURL.substring(fileURL.lastIndexOf("/") + 1,
						fileURL.length());
			}

			System.out.println("Content-Type = " + contentType);
			System.out.println("Content-Disposition = " + disposition);
			System.out.println("Content-Length = " + contentLength);
			System.out.println("fileName = " + fileName);

			// opens input stream from the HTTP connection
			InputStream inputStream = httpConn.getInputStream();
			String saveFilePath = saveDir + File.separator + fileName;
			
			// opens an output stream to save into file
			FileOutputStream outputStream = new FileOutputStream(saveFilePath);

			int bytesRead = -1;
			byte[] buffer = new byte[BUFFER_SIZE];
			while ((bytesRead = inputStream.read(buffer)) != -1) {
				outputStream.write(buffer, 0, bytesRead);
			}

			outputStream.close();
			inputStream.close();

			System.out.println("File downloaded");
		} else {
			System.out.println("No file to download. Server replied HTTP code: " + responseCode);
		}
		httpConn.disconnect();
	}
}

Note that in the static method downloadFile(), we have to check HTTP response code from the server to make sure the URL is available (HTTP status 200). Then we extract the file name either from the HTTP header Content-Disposition (in case the URL is an indirect link), or from the URL itself (in case the URL is the direct link). We also print out some debugging information like Content-Type, Content-Disposition, Content-Length and file name.

And here is a test program which employs the utility class above:

package net.codejava.networking;

import java.io.IOException;

public class HttpDownloader {

	public static void main(String[] args) {
		String fileURL = "http://jdbc.postgresql.org/download/postgresql-9.2-1002.jdbc4.jar";
		String saveDir = "E:/Download";
		try {
			HttpDownloadUtility.downloadFile(fileURL, saveDir);
		} catch (IOException ex) {
			ex.printStackTrace();
		}
	}
}

This program downloads the file postgresql-9.2-1002.jdbc4.jar and saves it into the directory E:/Download. It would produce the following output:

Content-Type = application/java-archive
Content-Disposition = null
Content-Length = 579785
fileName = postgresql-9.2-1002.jdbc4.jar
File downloaded

 

Watch this video tutorial to see how to build, run and test this program:

https://www.youtube.com/watch?v=ayLZgxw1ALg

 

Related Java File Download Tutorials:

 

Other Java network tutorials:

]]>
hainatu@gmail.com (Nam Ha Minh)NetworkingFri, 04 Jan 2013 06:57:16 -0600
Java HTTP utility class to send GET/POST requesthttps://owt.codejava.net/java-se/networking/an-http-utility-class-to-send-getpost-requesthttps://owt.codejava.net/java-se/networking/an-http-utility-class-to-send-getpost-request

This post help you code a Java utility class that makes a connection to a HTTP server by sending a GET/POST request and receiving response from the server. The HttpUtility class is built upon the HttpURLConnection class under java.net package, and has two methods for sending a request to a remote server:

    •  sendGetRequest(requestURL):accepts only the URL string.
    •  sendPostRequest(requestURL, params): accepts a URL string and a  HashMap containing POST parameters.

Both methods return an HttpURLConnection  object which has been made with the remote server. So we can use this object to invoke methods of the HttpURLConnection class when needed, such as checking HTTP status code, or HTTP response message.

The class also provides two methods for reading the server's response:

    •  readSingleLineRespone():returns a String.
    •  readMultipleLinesRespone(): returns an array of Strings.

As the names suggest, the first method is suitable if the server returns a simple response such as a String; and the second one is suitable if the server returns something bigger.

Finally, there is a method to close the connection with the server:

    • disconnect()

Here is the source code of this utility class:

package net.codejava.networking;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
 * This class encapsulates methods for requesting a server via HTTP GET/POST and
 * provides methods for parsing response from the server.
 * 
 * @author www.codejava.net
 * 
 */
public class HttpUtility {

	/**
	 * Represents an HTTP connection
	 */
	private static HttpURLConnection httpConn;

	/**
	 * Makes an HTTP request using GET method to the specified URL.
	 * 
	 * @param requestURL
	 *            the URL of the remote server
	 * @return An HttpURLConnection object
	 * @throws IOException
	 *             thrown if any I/O error occurred
	 */
	public static HttpURLConnection sendGetRequest(String requestURL)
			throws IOException {
		URL url = new URL(requestURL);
		httpConn = (HttpURLConnection) url.openConnection();
		httpConn.setUseCaches(false);

		httpConn.setDoInput(true); // true if we want to read server's response
		httpConn.setDoOutput(false); // false indicates this is a GET request

		return httpConn;
	}

	/**
	 * Makes an HTTP request using POST method to the specified URL.
	 * 
	 * @param requestURL
	 *            the URL of the remote server
	 * @param params
	 *            A map containing POST data in form of key-value pairs
	 * @return An HttpURLConnection object
	 * @throws IOException
	 *             thrown if any I/O error occurred
	 */
	public static HttpURLConnection sendPostRequest(String requestURL,
			Map<String, String> params) throws IOException {
		URL url = new URL(requestURL);
		httpConn = (HttpURLConnection) url.openConnection();
		httpConn.setUseCaches(false);

		httpConn.setDoInput(true); // true indicates the server returns response

		StringBuffer requestParams = new StringBuffer();

		if (params != null && params.size() > 0) {

			httpConn.setDoOutput(true); // true indicates POST request

			// creates the params string, encode them using URLEncoder
			Iterator<String> paramIterator = params.keySet().iterator();
			while (paramIterator.hasNext()) {
				String key = paramIterator.next();
				String value = params.get(key);
				requestParams.append(URLEncoder.encode(key, "UTF-8"));
				requestParams.append("=").append(
						URLEncoder.encode(value, "UTF-8"));
				requestParams.append("&");
			}

			// sends POST data
			OutputStreamWriter writer = new OutputStreamWriter(
					httpConn.getOutputStream());
			writer.write(requestParams.toString());
			writer.flush();
		}

		return httpConn;
	}

	/**
	 * Returns only one line from the server's response. This method should be
	 * used if the server returns only a single line of String.
	 * 
	 * @return a String of the server's response
	 * @throws IOException
	 *             thrown if any I/O error occurred
	 */
	public static String readSingleLineRespone() throws IOException {
		InputStream inputStream = null;
		if (httpConn != null) {
			inputStream = httpConn.getInputStream();
		} else {
			throw new IOException("Connection is not established.");
		}
		BufferedReader reader = new BufferedReader(new InputStreamReader(
				inputStream));

		String response = reader.readLine();
		reader.close();

		return response;
	}

	/**
	 * Returns an array of lines from the server's response. This method should
	 * be used if the server returns multiple lines of String.
	 * 
	 * @return an array of Strings of the server's response
	 * @throws IOException
	 *             thrown if any I/O error occurred
	 */
	public static String[] readMultipleLinesRespone() throws IOException {
		InputStream inputStream = null;
		if (httpConn != null) {
			inputStream = httpConn.getInputStream();
		} else {
			throw new IOException("Connection is not established.");
		}

		BufferedReader reader = new BufferedReader(new InputStreamReader(
				inputStream));
		List<String> response = new ArrayList<String>();

		String line = "";
		while ((line = reader.readLine()) != null) {
			response.add(line);
		}
		reader.close();

		return (String[]) response.toArray(new String[0]);
	}
	
	/**
	 * Closes the connection if opened
	 */
	public static void disconnect() {
		if (httpConn != null) {
			httpConn.disconnect();
		}
	}
}

The following test program demonstrates how to use the utility class:

package net.codejava.networking;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

public class HttpUtilityTester {

	/**
	 * This program uses the HttpUtility class to send a GET request to
	 * Google home page; and send a POST request to Gmail login page.
	 */
	public static void main(String[] args) {
		// test sending GET request
		String requestURL = "http://www.google.com";
		try {
			HttpUtility.sendGetRequest(requestURL);
			String[] response = HttpUtility.readMultipleLinesRespone();
			for (String line : response) {
				System.out.println(line);
			}
		} catch (IOException ex) {
			ex.printStackTrace();
		}
		HttpUtility.disconnect();
		
		
		System.out.println("=====================================");
		
		// test sending POST request
		Map<String, String> params = new HashMap<String, String>();
		requestURL = "https://accounts.google.com/ServiceLoginAuth";
		params.put("Email", "your_email");
		params.put("Passwd", "your_password");
		
		try {
			HttpUtility.sendPostRequest(requestURL, params);
			String[] response = HttpUtility.readMultipleLinesRespone();
			for (String line : response) {
				System.out.println(line);
			}
		} catch (IOException ex) {
			ex.printStackTrace();
		}
		HttpUtility.disconnect();
	}
}

 

Other Java network tutorials:

]]>
hainatu@gmail.com (Nam Ha Minh)NetworkingThu, 29 Mar 2012 08:48:52 -0500
How to use Java URLConnection and HttpURLConnectionhttps://owt.codejava.net/java-se/networking/how-to-use-java-urlconnection-and-httpurlconnectionhttps://owt.codejava.net/java-se/networking/how-to-use-java-urlconnection-and-httpurlconnection

In this Java network programming tutorial, you will learn how to use the URLConnection and HttpURLConnection classes for developing Java programs that communicate to a server via URLs (mostly using HTTP protocol).

You will be able to write code for uploading and downloading files, web pages; sending and retrieving HTTP requests and responses; and the like.

 

The URLConnection and HttpURLConnection Classes

URLConnection is the superclass of all classes that represent a connection between a Java application and a URL. The URLConnection class provides API for generic URLs, and its subclass HttpURLConnection provides additional support for HTTP-specific features.

Note that both of these classes are abstract - meaning that you can’t directly create new instances of URLConnection and HttpURLConnection. Instead, an instance of URLConnection is obtained by opening the connection from a URL object.

Typically, a client program communicates with a server via a URL follows this sequence of steps:

  1. Create a URL object
  2. Obtain a URLConnection object from the URL
  3. Configure the URLConnection
  4. Read the header fields
  5. Get an input stream and read data
  6. Get an output stream and write data
  7. Close the connection

The steps 3 to 6 are optional, and the steps 5 and 6 are interchangeable.

Let’s explore the API of URLConnection and HttpURLConnection classes based on this sequence.

 

1. Create a URL object

Simply create a new URL object for a given URL like this:

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

This constructor will throw a MalformedURLException if the URL is malformed. This checked exception is a subclass of IOException.

 

2. Obtain a URLConnection object from the URL

A URLConnection instance is obtained by invoking the openConnection() method on the URL object:

URLConnection urlCon = url.openConnection();

If the protocol is http://, you can cast the returned object to an HttpURLConnection object:

HttpURLConnection httpCon = (HttpURLConnection) url.openConnection();

Note that the openConnection() method doesn’t establish an actual network connection. It just returns an instance of URLConnection class.

The network connection is made explicitly when the connect() method is invoked, or implicitly when reading header fields or getting an input stream / output stream.

The URL’s openConnection() method throws IOException if an I/O error occurs.

 

3. Configure the URLConnection

Before actually establish the connection, you can configure various aspects that affect the ongoing communication between the client and the server, such as timeout, cache, HTTP request method, etc.

The URLConnection class provides the following methods for configuring the connection:

  • setConnectTimeout(int timeout): sets the connection timeout in milliseconds. A java.net.SocketTimeoutException is thrown if the timeout expires before the connection can be established. A timeout of zero indicates infinite timeout (the default value).
  • setReadTimeout(int timeout): sets the read timeout in milliseconds. After the timeout expires and there’s no data available to read from the connection’s input stream, a SocketTimeoutException is raised. A timeout of zero indicates infinite timeout (the default value).
  • setDefaultUseCaches(boolean default): sets whether the URLConnection uses caches by default or not (default is true). This method affects future instances of the URLConnection class.
  • setUseCaches(boolean useCaches): sets whether this connection uses cache or not (default is true).
  • setDoInput(boolean doInput): sets whether this URLConnection can be used for reading content from the server (default is true).
  • setDoOutput(boolean doOutput): sets whether this URLConnection can be used for sending data to the server (default is false).
  • setIfModifiedSince(long time): sets the last modified time of the content retrieved by the client, primarily for HTTP protocol. For example, if the server finds that the content has not changed since the specified time, it doesn’t fetch the content and returns status code 304 - not modified. The client will get the fresh content if it has been modified more recently than the specified time.
  • setAllowUserInteraction(boolean allow): enables or disables user interaction, e.g. popping up an authentication dialog if required (default is false).
  • setDefaultAllowUserInteraction(boolean default): sets the default value for user interaction for all future URLConnection objects.
  • setRequestProperty(String key, String value): sets a general request property specified by a key=value pair. If a property with the key already exists, the old value is overwritten with the new value.

 

Note that these methods should be invoked before establishing the connection. Some methods throw IllegalStateException if the connection is already made.

In addition, the subclass HttpURLConnection provides the following methods for configuring the connection with HTTP-specific features:

  • setRequestMethod(String method): sets the method for the URL request, which is one of HTTP methods GET, POST, HEAD, OPTIONS, PUT, DELETE and TRACE. The default method is GET.
  • setChunkedStreamingMode(int chunkLength): enables streaming of a HTTP request body without internal buffering, when the content length is not known in advanced.
  • setFixedLengthStreamingMode(long contentLength): enables streaming of a HTTP request body without internal buffering, when the content length is known in advanced.
  • setFollowRedirects(boolean follow): this static method sets whether HTTP redirects should be automatically followed by future objects of this class (default is true).
  • setInstanceFollowRedirects(boolean follow): sets whether HTTP redirects should be automatically followed by instance of this HttpURLConnection class (default is true).

 

The above methods are setters. And the URLConnection and HttpURLConnection classes also provide corresponding getters:

  • getConnectTimeout()
  • getReadTimeout()
  • getDefaultUseCaches()
  • getUseCaches()
  • getDoInput()
  • getDoOutput()
  • getIfModifiedSince()
  • getAllowUserInteraction()
  • getDefaultAllowUserInteraction()
  • getRequestProperty(String key)
  • getRequestMethod()
  • getFollowRedirects()
  • getInstanceFollowRedirects()

 

4. Read the header fields

Once the connection is made, the server processes the URL request and sends back a response that consists of metadata and actual content. The metadata is a collection of key=value pairs which are called header fields.

The header fields reveal information about the server, status code, protocol information, etc. The actual content can be in text, HTML, image, etc. depending on the type of the document.

The URLConnection class provides the following methods for reading the header fields:

  • getHeaderFields(): returns a map that contains all header fields. The key is field name and the value is a list of String represents the corresponding field values.
  • getHeaderField(int n): reads the value of the n-th header field.
  • getHeaderField(String name): reads the value of the named header field.
  • getHeaderFieldKey(int n): reads the key of the n-th header field.
  • getHeaderFieldDate(String name, long default): reads the value of the named field parsed as Date. If the field is missing or value is malformed, the default value is returned instead.
  • getHeaderFieldInt(String name, int default): reads the value of the named field parsed as an integer number. If the field is missing or value is malformed, the default value is returned instead.
  • getHeaderFieldLong(String name, long default): reads the value of the named field parsed as a long number. If the field is missing or value is malformed, the default value is returned instead.

 

These are general methods for reading any header fields. And for some frequently-accessed header fields, the URLConnection class provides more specific methods:

  • getContentEncoding(): reads the value of the content-encoding header field, which indicates the encoding type of the content.
  • getContentLength(): reads the value of the content-length header field, which indicates the size of the content (in bytes).
  • getContentType(): reads the value of the content-type header field, which indicates the type of the content.
  • getDate(): reads the value of the date header field, which indicates the date time on the server.
  • getExpiration(): reads the value of the expires header field, indicates the time after which the response is considered stale. This is for cache control.
  • getLastModified(): reads the value of the last-modified header field, which indicates the last modified time of the content.

 

And the subclass HttpURLConnection provides an additional method:

  • getResponseCode(): returns the HTTP status code sent by the server.

Note that when the header fields are read, the connection is implicitly established, without calling connect().

 

5. Get an input stream and read data

To read the actual content, you need to obtain an InputStream instance from the connection, and then use the InputStream’s read() methods to read the data:

InputStream inputStream = urlCon.getInputStream();
byte[] data = new byte[1024];
inputStream.read(data);

The InputStream’s read() is a low-level method that reads data to an array of bytes. So it is more convenient to wrap the InputStream in an InputStreamReader for reading data to characters:

InputStream inputStream = urlCon.getInputStream();
InputStreamReader reader = new InputStreamReader(inputStream);

int character = reader.read();	// reads a single character
char[] buffer = new char[4096];
reader.read(buffer);	// reads to an array of characters

Or wrap the InputStream in a BufferedReader for reading data to Strings:

BufferedReader reader = new BufferedReader(new InputStreamReader(input));
String line = reader.readLine(); // reads a line

Note that the getInputStream() method can throw the following exceptions:

  • IOException: if an I/O error occurs while creating the input stream.
  • SocketTimeoutException: if the read timeout expires before data is available for read.
  • UnknownServiceExcepetion: if the protocol does not support input.

 

6. Get an output stream and write data

To send data to the server, you have to enable output on the connection first:

urlCon.setDoOutput(true);

Then get the OutputStream object associated with the connection, and then use the OutputStream’s write() methods to write the data:

OutputStream outputStream = urlCon.getOutputStream();
byte[] data = new byte[1024];
outputStream.write(data);

As you can see, the OutputStreams write() is a low-level method that writes an array of bytes. So it is more convenient to wrap the OutputStream in an OutputStreamWriter for writing characters:

OutputStreamWriter writer = new OutputStreamWriter(outputStream);
int character = 'a';
writer.write(character); // writes a single character

char[] buffer = new char[4096];
writer.write(buffer); // writes an array of characters

Or wrap the OutputStream in a PrintWriter for writing Strings:

PrintWriter writer = new PrintWriter(outputStream);
String line = "This is String";
writer.print(line);

Note that the getOutputStream() method can throw IOException or UnknownServiceException.

 

7. Close the connection

To close the connection, invoke the close() method on either the InputStream or OutputStream object. Doing that may free the network resources associated with the URLConnection instance.

That’s about how to use the API of URLConnection and HttpURLConnection. Check the following articles for real-world examples:

So you can use URLConnection and HttpURLConnection for simple network programming, i.e. send and receive data to and from a server. I recommend you to read this book to learn more in-depth about Java network programming, or take this Java masterclass course to dive deep into Java programming.

 

Other Java network tutorials:

]]>
hainatu@gmail.com (Nam Ha Minh)NetworkingFri, 08 Dec 2017 02:25:23 -0600
Java URLConnection and HttpURLConnection Exampleshttps://owt.codejava.net/java-se/networking/java-urlconnection-and-httpurlconnection-exampleshttps://owt.codejava.net/java-se/networking/java-urlconnection-and-httpurlconnection-examples

In this article, you will learn how to use the URLConnectionand HttpURLConnection classes for developing Java network applications through various examples.

For understanding the API for URLConnection and HttpURLConnection, please refer to this tutorial.

Here is the list of examples in this article:

 

Example #1: Download a web page’s HTML source code

The following code snippet downloads HTML source code of a webpage and save it to a file:

String url = "https://google.com";
String filePath = "Google.html";

URL urlObj = new URL(url);
URLConnection urlCon = urlObj.openConnection();

InputStream inputStream = urlCon.getInputStream();
BufferedInputStream reader = new BufferedInputStream(inputStream);

BufferedOutputStream writer = new BufferedOutputStream(new FileOutputStream(filePath));

byte[] buffer = new byte[4096];
int bytesRead = -1;

while ((bytesRead = reader.read(buffer)) != -1) {
	writer.write(buffer, 0, bytesRead);
}

writer.close();
reader.close();

As you can see, this code opens a connection from the specified URL, gets an input stream and an output stream. Then it reads data from the input stream and writes the data to a specified file.

Adding exception handling code and parameterize the URL and file path, we have a complete program as follows:

import java.net.*;
import java.io.*;
import java.util.*;

public class DownloadWebPage {

	public static void main(String[] args) {
		if (args.length < 2) {
			System.out.println("Syntax: <url> <file>");
			return;
		}

		String url = args[0];
		String filePath = args[1];

		try {

			URL urlObj = new URL(url);
			URLConnection urlCon = urlObj.openConnection();

			InputStream inputStream = urlCon.getInputStream();
			BufferedInputStream reader = new BufferedInputStream(inputStream);

			BufferedOutputStream writer = new BufferedOutputStream(new FileOutputStream(filePath));

			byte[] buffer = new byte[4096];
			int bytesRead = -1;

			while ((bytesRead = reader.read(buffer)) != -1) {
				writer.write(buffer, 0, bytesRead);
			}

			writer.close();
			reader.close();

			System.out.println("Web page saved");

		} catch (MalformedURLException e) {
			System.out.println("The specified URL is malformed: " + e.getMessage());
		} catch (IOException e) {
			System.out.println("An I/O error occurs: " + e.getMessage());
		}
	}
}

You can run this program from command line using this syntax:

java DownloadWebPage <url> <file>

For example, download the Google’s homepage:

java DownloadWebPage https://google.com Google.html

The page’s HTML code is saved to the file Google.html.

 

Example #2: Check HTTP Response Code

The above program will fail silently if the server returns a response code other than 200 - the HTTP response code indicates the server returns the document without any problem. For example, if you run the above program using this command:

java DownloadWebPage http://facebook.com Facebook.html

The program terminates normally but the file Facebook.html is empty (0 byte). So let use the following code to check the server’s response code before reading and writing data:

URL urlObj = new URL(url);
HttpURLConnection httpCon = (HttpURLConnection) urlObj.openConnection();

int responseCode = httpCon.getResponseCode();

if (responseCode != HttpURLConnection.HTTP_OK) {
	System.out.println("Server returned response code " + responseCode + ". Download failed.");
	System.exit(0);
}

This code will terminate the program if the response code is not 200 (HTTP_OK). Update, recompile and run the program again:

java DownloadWebPage http://facebook.com Facebook.html

And you should see the following output:

Server returned response code 301. Download failed.

The HTTP status code 301 indicates that the requested document is moved permanently. That means we should use https:// instead of http://. Run the program again with this command:

java DownloadWebPage https://facebook.com Facebook.html

And you see the file Facebook.html is saved with HTML code.

 

Example #3: Set Client’s HTTP Request Header Fields

Use the setRequestProperty(String key, String value) method of the URLConnection class to set header fields for the request. The client’s header fields provide additional information about the client and how the client expects response from the server.

Here’s an example:

URL urlObj = new URL(url);
URLConnection urlCon = urlObj.openConnection();

urlCon.setRequestProperty("User-Agent", "Java Client; Mac OS");
urlCon.setRequestProperty("Accept", "text/html");
urlCon.setRequestProperty("Accept-Language", "en-US");
urlCon.setRequestProperty("Connection", "close");

As you can see, this code snippet specifies 4 header fields for the request:

- User-Agent: information about the client such as browser type, operating system, architecture, etc.

- Accept: the content type understood by the client

- Accept-Language: the language understood by the client

- Connection: type of the connection. In this case, the connection is closed after a request-response roundtrip finished.

 

Example #4: Read all Server’s Header Fields

We can use the getHeaderFields() method of the URLConnection class to read all header fields sent from the server. Here’s an example:

String url = "https://google.com";
URL urlObj = new URL(url);
URLConnection urlCon = urlObj.openConnection();

Map<String, List<String>> map = urlCon.getHeaderFields();


for (String key : map.keySet()) {
	System.out.println(key + ":");

	List<String> values = map.get(key);

	for (String aValue : values) {
		System.out.println("\t" + aValue);
	}
}

Run this code and you should see the output looks like this (from google.com):

Transfer-Encoding:
        chunked
null:
        HTTP/1.1 200 OK
Server:
        gws
Date:
        Sat, 09 Dec 2017 15:38:16 GMT
Accept-Ranges:
        none
Cache-Control:
        private, max-age=0

Content-Type:
        text/html; charset=ISO-8859-1

This information varies, depending on each server.

 

Example #5: Read Common Header Fields

Using descriptive get header fields methods, the following code snippet reads and prints the values of common header fields such as response code, response message, content type, content encoding, content length, and so on:

String url = "https://facebook.com";

URL urlObj = new URL(url);
HttpURLConnection httpCon = (HttpURLConnection) urlObj.openConnection();

int responseCode = httpCon.getResponseCode();
String responseMessage = httpCon.getResponseMessage();
String contentType = httpCon.getContentType();
String contentEncoding = httpCon.getContentEncoding();
int contentLength = httpCon.getContentLength();

long date = httpCon.getDate();
long expiration = httpCon.getExpiration();
long lastModified = httpCon.getLastModified();

System.out.println("Response Code: " + responseCode);
System.out.println("Response Message: " + responseMessage);
System.out.println("Content Type: " + contentType);
System.out.println("Content Encoding: " + contentEncoding);
System.out.println("Content Length: " + contentLength);
System.out.println("Date: " + new Date(date));
System.out.println("Expiration: " + new Date(expiration));
System.out.println("Last Modified: " + new Date(lastModified));

The output would be:

Response Code: 200
Response Message: OK
Content Type: text/html; charset=UTF-8
Content Encoding: null
Content Length: -1
Date: Sun Dec 10 10:52:31 ICT 2017
Expiration: Sat Jan 01 07:00:00 ICT 2000
Last Modified: Thu Jan 01 07:00:00 ICT 1970

 

Example #6: Set HTTP Request Method 

By default the HTTP request method is GET. You can call the setRequestMethod(String method) to set the request method which is one of GET, POST, HEAD, PUT, DELETE, TRACE, and OPTIONS.

For example, the following code sets the request method to HEAD:

URL urlObj = new URL(url);
HttpURLConnection httpCon = (HttpURLConnection) urlObj.openConnection();
httpCon.setRequestMethod("HEAD");

When processing a HEAD request, the server returns a response without the body content. Only the header fields are returned. Hence the method name “HEAD”.

Also note that when you set the request method to POST, you must also enable output for the connection, as POST method is about send data to the server. For example:

httpCon.setDoOutput(true);
httpCon.setRequestMethod("POST");

See how to send a POST request in the next example.

 

Example #7: Send HTTP POST Request

To send an HTTP POST request along with parameters, you need to constructor the parameters in the following form:

param1=value1&param2=value2&param3=value3

The following code snippet demonstrates how to send a login request to Twitter via HTTP POST:

String url = "https://twitter.com/sessions";
String email = "yourname@gmail.com";
String password = "yourpass";


URL urlObj = new URL(url);
HttpURLConnection httpCon = (HttpURLConnection) urlObj.openConnection();

httpCon.setDoOutput(true);
httpCon.setRequestMethod("POST");

String parameters = "username=" + email;
parameters += "password=" + password;


OutputStreamWriter writer = new OutputStreamWriter(
    httpCon.getOutputStream());
writer.write(parameters);
writer.flush();

Of course this won’t work because Twitter requires more complex parameters for the login process (i.e. authentication key). Anyway, let try to combine this code with the example of reading all header fields and save to file to see what will happen.

And for more practical URLConnection/HttpURLConnection examples, refer to the following articles:

 

API References:

 

If you want to learn in-depth network programming with Java, I recommend you to read this Java Network programming book, or study this Java course for a complete training.

 

Other Java network tutorials:

]]>
hainatu@gmail.com (Nam Ha Minh)NetworkingSun, 10 Dec 2017 01:50:25 -0600
Java upload files by sending multipart request programmaticallyhttps://owt.codejava.net/java-se/networking/upload-files-by-sending-multipart-request-programmaticallyhttps://owt.codejava.net/java-se/networking/upload-files-by-sending-multipart-request-programmatically

In this post, you will learn how to code a Java client program that upload files to a web server programmatically.

In the article Upload file to servlet without using HTML form,we discussed how to fire an HTTP POST request to transfer a file to a server – but that request’s content type is not of multipart/form-data, so it may not work with the servers which handle multipart request and it requires both client and server are implemented in Java.

To overcome that limitation, in this article, we are going to discuss a different solution for uploading files from a Java client to any web server in a programmatic way, without using upload form in HTML code. Let’s examine this interesting solution now.

 

Code Java multipart utility class:

We build the utility class called MultipartUtilitywith the following code:

package net.codejava.networking;

import java.io.BufferedReader;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.List;

/**
 * This utility class provides an abstraction layer for sending multipart HTTP
 * POST requests to a web server. 
 * @author www.codejava.net
 *
 */
public class MultipartUtility {
	private final String boundary;
	private static final String LINE_FEED = "\r\n";
	private HttpURLConnection httpConn;
	private String charset;
	private OutputStream outputStream;
	private PrintWriter writer;

	/**
	 * This constructor initializes a new HTTP POST request with content type
	 * is set to multipart/form-data
	 * @param requestURL
	 * @param charset
	 * @throws IOException
	 */
	public MultipartUtility(String requestURL, String charset)
			throws IOException {
		this.charset = charset;
		
		// creates a unique boundary based on time stamp
		boundary = "===" + System.currentTimeMillis() + "===";
		
		URL url = new URL(requestURL);
		httpConn = (HttpURLConnection) url.openConnection();
		httpConn.setUseCaches(false);
		httpConn.setDoOutput(true);	// indicates POST method
		httpConn.setDoInput(true);
		httpConn.setRequestProperty("Content-Type",
				"multipart/form-data; boundary=" + boundary);
		httpConn.setRequestProperty("User-Agent", "CodeJava Agent");
		httpConn.setRequestProperty("Test", "Bonjour");
		outputStream = httpConn.getOutputStream();
		writer = new PrintWriter(new OutputStreamWriter(outputStream, charset),
				true);
	}

	/**
	 * Adds a form field to the request
	 * @param name field name
	 * @param value field value
	 */
	public void addFormField(String name, String value) {
		writer.append("--" + boundary).append(LINE_FEED);
		writer.append("Content-Disposition: form-data; name=\"" + name + "\"")
				.append(LINE_FEED);
		writer.append("Content-Type: text/plain; charset=" + charset).append(
				LINE_FEED);
		writer.append(LINE_FEED);
		writer.append(value).append(LINE_FEED);
		writer.flush();
	}

	/**
	 * Adds a upload file section to the request 
	 * @param fieldName name attribute in <input type="file" name="..." />
	 * @param uploadFile a File to be uploaded 
	 * @throws IOException
	 */
	public void addFilePart(String fieldName, File uploadFile)
			throws IOException {
		String fileName = uploadFile.getName();
		writer.append("--" + boundary).append(LINE_FEED);
		writer.append(
				"Content-Disposition: form-data; name=\"" + fieldName
						+ "\"; filename=\"" + fileName + "\"")
				.append(LINE_FEED);
		writer.append(
				"Content-Type: "
						+ URLConnection.guessContentTypeFromName(fileName))
				.append(LINE_FEED);
		writer.append("Content-Transfer-Encoding: binary").append(LINE_FEED);
		writer.append(LINE_FEED);
		writer.flush();

		FileInputStream inputStream = new FileInputStream(uploadFile);
		byte[] buffer = new byte[4096];
		int bytesRead = -1;
		while ((bytesRead = inputStream.read(buffer)) != -1) {
			outputStream.write(buffer, 0, bytesRead);
		}
		outputStream.flush();
		inputStream.close();
		
		writer.append(LINE_FEED);
		writer.flush();		
	}

	/**
	 * Adds a header field to the request.
	 * @param name - name of the header field
	 * @param value - value of the header field
	 */
	public void addHeaderField(String name, String value) {
		writer.append(name + ": " + value).append(LINE_FEED);
		writer.flush();
	}
	
	/**
	 * Completes the request and receives response from the server.
	 * @return a list of Strings as response in case the server returned
	 * status OK, otherwise an exception is thrown.
	 * @throws IOException
	 */
	public List<String> finish() throws IOException {
		List<String> response = new ArrayList<String>();

		writer.append(LINE_FEED).flush();
		writer.append("--" + boundary + "--").append(LINE_FEED);
		writer.close();

		// checks server's status code first
		int status = httpConn.getResponseCode();
		if (status == HttpURLConnection.HTTP_OK) {
			BufferedReader reader = new BufferedReader(new InputStreamReader(
					httpConn.getInputStream()));
			String line = null;
			while ((line = reader.readLine()) != null) {
				response.add(line);
			}
			reader.close();
			httpConn.disconnect();
		} else {
			throw new IOException("Server returned non-OK status: " + status);
		}

		return response;
	}
}

This utility class uses java.net.HttpURLConnection class and follows the RFC 1867 (Form-based File Upload in HTML) to make an HTTP POST request with multipart/form-data content type in order to upload files to a given URL. It has one constructor and three methods:

    • MultipartUtility(String requestURL, String charset): creates a new instance of this class for a given request URL and charset.
    • void addFormField(String name, String value): adds a regular text field to the request.
    • void addHeaderField(String name, String value): adds an HTTP header field to the request.
    • void addFilePart(String fieldName, File uploadFile): attach a file to be uploaded to the request.
    • List<String> finish(): this method must be invoked lastly to complete the request and receive response from server as a list of String.

Now let’s take a look at an example of how to use this utility class.

 

Code Java Client program to upload file:

Since the MultipartUtilityclass abstracts all the detailed implementation, a usage example would be pretty simple as shown in the following program:

package net.codejava.networking;

import java.io.File;
import java.io.IOException;
import java.util.List;

/**
 * This program demonstrates a usage of the MultipartUtility class.
 * @author www.codejava.net
 *
 */
public class MultipartFileUploader {

	public static void main(String[] args) {
		String charset = "UTF-8";
		File uploadFile1 = new File("e:/Test/PIC1.JPG");
		File uploadFile2 = new File("e:/Test/PIC2.JPG");
		String requestURL = "http://localhost:8080/FileUploadSpringMVC/uploadFile.do";

		try {
			MultipartUtility multipart = new MultipartUtility(requestURL, charset);
			
			multipart.addHeaderField("User-Agent", "CodeJava");
			multipart.addHeaderField("Test-Header", "Header-Value");
			
			multipart.addFormField("description", "Cool Pictures");
			multipart.addFormField("keywords", "Java,upload,Spring");
			
			multipart.addFilePart("fileUpload", uploadFile1);
			multipart.addFilePart("fileUpload", uploadFile2);

			List<String> response = multipart.finish();
			
			System.out.println("SERVER REPLIED:");
			
			for (String line : response) {
				System.out.println(line);
			}
		} catch (IOException ex) {
			System.err.println(ex);
		}
	}
}

In this program, we connect to the servlet’s URL of the application FileUploadSpringMVC (see this tutorial: Upload files with Spring MVC):

http://localhost:8080/FileUploadSpringMVC/uploadFile.do

We added two header fields, two form fields and two upload files under the name “fileUpload” – which must match the fields declared in the upload form of the FileUploadSpringMVC application.

When running the above program, it will produce the following output:

server response

We can realize that the server’s response is actually HTML code of the application FileUploadSpringMVC’s result page.

So far in this article, we’ve discussed about how to implement a command line program in Java which is capable of upload files to any URL that can handle multipart request, without implementing an HTML upload form. This would be very useful in case we want to upload files to a web server programmatically.

 

Related Java File Upload Tutorials:

 

Other Java network tutorials:

]]>
hainatu@gmail.com (Nam Ha Minh)NetworkingSun, 23 Dec 2012 22:45:35 -0600
Java Socket Server Examples (TCP/IP)https://owt.codejava.net/java-se/networking/java-socket-server-examples-tcp-iphttps://owt.codejava.net/java-se/networking/java-socket-server-examples-tcp-ip

In this Java network programming tutorial, you will learn how to develop a socket server program to implement fully functional network client/server application. You will also learn how to create a multi-threaded server.

First, let’s understand about the workflow and the API.

 

1. ServerSocket API

The ServerSocketclass is used to implement a server program. Here are the typical steps involve in developing a server program:

1. Create a server socket and bind it to a specific port number

2. Listen for a connection from the client and accept it. This results in a client socket is created for the connection.

3. Read data from the client via an InputStream obtained from the client socket.

4. Send data to the client via the client socket’s OutputStream.

5. Close the connection with the client.

The steps 3 and 4 can be repeated many times depending on the protocol agreed between the server and the client.

The steps 1 to 5 can be repeated for each new client. And each new connection should be handled by a separate thread.

Let’s dive into each step in details.

 

Create a Server Socket:

Create a new object of the ServerSocket class by using one of the following constructors:

- ServerSocket(int port): creates a server socket that is bound to the specified port number. The maximum number of queued incoming connections is set to 50 (when the queue is full, new connections are refused).

- ServerSocket(int port, int backlog): creates a server socket that is bound to the specified port number and with the maximum number of queued connections is specified by the backlog parameter.

- ServerSocket(int port, int backlog, InetAddress bindAddr): creates a server socket and binds it to the specified port number and a local IP address.

So when to use which?

Use the first constructor for a small number of queued connections (less than 50) and any local IP address available.

Use the second constructor if you want to explicitly specify the maximum number of queued requests.

And use the third constructor if you want to explicitly specify a local IP address to be bound (in case the computer has multiple IP addresses).

And of course, the first constructor is preferred for simple usage. For example, the following line of code creates a server socket and binds it to the port number 6868:

ServerSocket serverSocket = new ServerSocket(6868);

Note that these constructors can throw IOException if an I/O error occurs when opening the socket, so you have to catch or re-throw it.

 

Listen for a connection:

Once a ServerSocket instance is created, call accept() to start listening for incoming client requests:

Socket socket = serverSocket.accept();

Note that the accept() method blocks the current thread until a connection is made. And the connection is represented by the returned Socket object.

 

Read data from the client:

Once a Socket object is returned, you can use its InputStream to read data sent from the client like this:

InputStream input = socket.getInputStream();

The InputStream allows you to read data at low level: read to a byte array. So if you want to read the data at higher level, wrap it in an InputStreamReader to read data as characters:

InputStreamReader reader = new InputStreamReader(input);
int character = reader.read();	// reads a single character

You can also wrap the InputStream in a BufferedReader to read data as String, for more convenient:

BufferedReader reader = new BufferedReader(new InputStreamReader(input));
String line = reader.readLine();	// reads a line of text

 

Send data to the client:

Use the OutputStream associated with the Socket to send data to the client, for example:

OutputStream output = socket.getOutputStream();

As the OutputStream provides only low-level methods (writing data as a byte array), you can wrap it in a PrintWriter to send data in text format, for example:

PrintWriter writer = new PrintWriter(output, true);
writer.println(“This is a message sent to the server”);

The argument true indicates that the writer flushes the data after each method call (auto flush).

 

Close the client connection:

Invoke the close() method on the client Socket to terminate the connection with the client:

socket.close();

This method also closes the socket’s InputStream and OutputStream, and it can throw IOException if an I/O error occurs when closing the socket.

We recommend you to use the try-with-resource structure so you don’t have to write code to close the socket explicitly.

Of course the server is still running, for serving other clients.

 

Terminate the server:

A server should be always running, waiting for incoming requests from clients. In case the server must be stopped for some reasons, call the close() method on the ServerSocket instance:

serverSocket.close();

When the server is stopped, all currently connected clients will be disconnected.

The ServerSocket class also provides other methods which you can consult in its Javadoc here.

 

Implement a multi-threaded server:

So basically, the workflow of a server program is something like this:

ServerSocket serverSocket = new ServerSocket(port);

while (true) {
	Socket socket = serverSocket.accept();
	
	// read data from the client
	// send data to the client
}

The while(true) loop is used to allow the server to run forever, always waiting for connections from clients. However, there’s a problem: Once the first client is connected, the server may not be able to handle subsequent clients if it is busily serving the first client.

Therefore, to solve this problem, threads are used: each client socket is handled by a new thread. The server’s main thread is only responsible for listening and accepting new connections. Hence the workflow is updated to implement a multi-threaded server like this:

while (true) {
	Socket socket = serverSocket.accept();
	
	// create a new thread to handle client socket
}

You will understand clearly in the examples below.

 

2. Java Server Socket Example #1: Time Server

The following program demonstrates how to implement a simple server that returns the current date time for every new client. Here’s the code:

import java.io.*;
import java.net.*;
import java.util.Date;

/**
 * This program demonstrates a simple TCP/IP socket server.
 *
 * @author www.codejava.net
 */
public class TimeServer {

	public static void main(String[] args) {
		if (args.length < 1) return;

		int port = Integer.parseInt(args[0]);

		try (ServerSocket serverSocket = new ServerSocket(port)) {

			System.out.println("Server is listening on port " + port);

			while (true) {
				Socket socket = serverSocket.accept();

				System.out.println("New client connected");

				OutputStream output = socket.getOutputStream();
				PrintWriter writer = new PrintWriter(output, true);

				writer.println(new Date().toString());
			}

		} catch (IOException ex) {
			System.out.println("Server exception: " + ex.getMessage());
			ex.printStackTrace();
		}
	}
}

You need to specify a port number when running this server program, for example:

java TimeServer 6868

This makes the server listens for client requests on the port number 6868. You would see the server’s output:

Server is listening on port 6868

And the following code is for a client program that simply connects to the server and prints the data received, and then terminates:

import java.net.*;
import java.io.*;

/**
 * This program demonstrates a simple TCP/IP socket client.
 *
 * @author www.codejava.net
 */
public class TimeClient {

	public static void main(String[] args) {
		if (args.length < 2) return;

		String hostname = args[0];
		int port = Integer.parseInt(args[1]);

		try (Socket socket = new Socket(hostname, port)) {

			InputStream input = socket.getInputStream();
			BufferedReader reader = new BufferedReader(new InputStreamReader(input));

			String time = reader.readLine();

			System.out.println(time);


		} catch (UnknownHostException ex) {

			System.out.println("Server not found: " + ex.getMessage());

		} catch (IOException ex) {

			System.out.println("I/O error: " + ex.getMessage());
		}
	}
}

To run this client program, you have to specify the hostname/IP address and port number of the server. If the client is on the same computer with the server, type the following command to run it:

java TimeClient localhost 6868

Then you see a new output in the server program indicating that the client is connected:

New client connected

And you should see the client’s output:

Mon Nov 13 11:00:31 ICT 2017

This is the date time information returned from the server. Then the client terminates and the server is still running, waiting for new connections. It’s that simple.

 

3. Java Socket Server Example #2: Reverse Server (single-threaded)

Next, let’s see a more complex socket server example. The following server program echoes anything sent from the client in reversed form (hence the name ReverseServer). Here’s the code:

import java.io.*;
import java.net.*;

/**
 * This program demonstrates a simple TCP/IP socket server that echoes every
 * message from the client in reversed form.
 * This server is single-threaded.
 *
 * @author www.codejava.net
 */
public class ReverseServer {

	public static void main(String[] args) {
		if (args.length < 1) return;

		int port = Integer.parseInt(args[0]);

		try (ServerSocket serverSocket = new ServerSocket(port)) {

			System.out.println("Server is listening on port " + port);

			while (true) {
				Socket socket = serverSocket.accept();
				System.out.println("New client connected");

				InputStream input = socket.getInputStream();
				BufferedReader reader = new BufferedReader(new InputStreamReader(input));

				OutputStream output = socket.getOutputStream();
				PrintWriter writer = new PrintWriter(output, true);


				String text;

				do {
					text = reader.readLine();
					String reverseText = new StringBuilder(text).reverse().toString();
					writer.println("Server: " + reverseText);

				} while (!text.equals("bye"));

				socket.close();
			}

		} catch (IOException ex) {
			System.out.println("Server exception: " + ex.getMessage());
			ex.printStackTrace();
		}
	}
}

As you can see, the server continues serving the client until it says ‘bye’. Run this server program using the following command:

java ReverseServer 9090

The server is up and running, waiting for incoming requests from clients:

Server is listening on port 9090

Now, let’s create a client program. The following program connects to the server, reads input from the user and prints the response from the server. Here’s the code:

import java.net.*;
import java.io.*;

/**
 * This program demonstrates a simple TCP/IP socket client that reads input
 * from the user and prints echoed message from the server.
 *
 * @author www.codejava.net
 */
public class ReverseClient {

	public static void main(String[] args) {
		if (args.length < 2) return;

		String hostname = args[0];
		int port = Integer.parseInt(args[1]);

		try (Socket socket = new Socket(hostname, port)) {

			OutputStream output = socket.getOutputStream();
			PrintWriter writer = new PrintWriter(output, true);

			Console console = System.console();
			String text;

			do {
				text = console.readLine("Enter text: ");

				writer.println(text);

				InputStream input = socket.getInputStream();
				BufferedReader reader = new BufferedReader(new InputStreamReader(input));

				String time = reader.readLine();

				System.out.println(time);

			} while (!text.equals("bye"));

			socket.close();

		} catch (UnknownHostException ex) {

			System.out.println("Server not found: " + ex.getMessage());

		} catch (IOException ex) {

			System.out.println("I/O error: " + ex.getMessage());
		}
	}
}

As you can see, this client program is running until the user types ‘bye’. Run it using the following command:

java ReverseClient localhost 9090

Then it asks you to enter some text:

Enter text:_

Type something, say ‘Hello’ and you should see the server’s response like this:

Enter text: Hello
Server: olleH
Enter text:_

You see the server responds ‘Server: olleH’ in which ‘olledH’ is the reversed form of ‘Hello’. The text ‘Server:’ is added to clearly separate client’s message and server’s message. The client program is still running, asking input and printing server’s response until you type ‘bye’ to terminate it.

Keep this first client program running, and start a new one. In the second client program, you will see it asks for input and then hangs forever. Why?

It’s because the server is single-threaded, and while it is busily serving the first client, subsequent clients are block.

Let’s see how to solve this problem in the next example.

 

4. Java Socket Server Example #3: Reverse Server (multi-threaded)

Modify the server’s code to handle each socket client in a new thread like this:

import java.io.*;
import java.net.*;

/**
 * This program demonstrates a simple TCP/IP socket server that echoes every
 * message from the client in reversed form.
 * This server is multi-threaded.
 *
 * @author www.codejava.net
 */
public class ReverseServer {

	public static void main(String[] args) {
		if (args.length < 1) return;

		int port = Integer.parseInt(args[0]);

		try (ServerSocket serverSocket = new ServerSocket(port)) {

			System.out.println("Server is listening on port " + port);

			while (true) {
				Socket socket = serverSocket.accept();
				System.out.println("New client connected");

				new ServerThread(socket).start();
			}

		} catch (IOException ex) {
			System.out.println("Server exception: " + ex.getMessage());
			ex.printStackTrace();
		}
	}
}

You see, the server creates a new ServerThread for every socket client:

while (true) {
	Socket socket = serverSocket.accept();
	System.out.println("New client connected");

	new ServerThread(socket).start();
}

The ServerThread class is implemented as follows:

import java.io.*;
import java.net.*;

/**
 * This thread is responsible to handle client connection.
 *
 * @author www.codejava.net
 */
public class ServerThread extends Thread {
	private Socket socket;

	public ServerThread(Socket socket) {
		this.socket = socket;
	}

	public void run() {
		try {
			InputStream input = socket.getInputStream();
			BufferedReader reader = new BufferedReader(new InputStreamReader(input));

			OutputStream output = socket.getOutputStream();
			PrintWriter writer = new PrintWriter(output, true);


			String text;

			do {
				text = reader.readLine();
				String reverseText = new StringBuilder(text).reverse().toString();
				writer.println("Server: " + reverseText);

			} while (!text.equals("bye"));

			socket.close();
		} catch (IOException ex) {
			System.out.println("Server exception: " + ex.getMessage());
			ex.printStackTrace();
		}
	}
}

As you can see, we just move the processing code to be executed into a separate thread, implemented in the run() method.

Now let run this new server program and run several client programs, you will see the problem above has solved. All clients are running smoothly.

Let experiment the examples in this lesson in different ways: run multiple clients, test on local computer, and test on different computers (the server runs on a machine and the client runs on another).

 

API Reference:

Socket Class Javadoc

ServerSocket Class Javadoc 

 

Related Java Network Tutorials:

 

Other Java network tutorials:

]]>
hainatu@gmail.com (Nam Ha Minh)NetworkingSun, 12 Nov 2017 22:37:51 -0600
Java Socket Client Examples (TCP/IP)https://owt.codejava.net/java-se/networking/java-socket-client-examples-tcp-iphttps://owt.codejava.net/java-se/networking/java-socket-client-examples-tcp-ip

In this Java network programming tutorial, we’ll guide you how to write a client program that talks to a server using TCP/IP protocol. In the next few minutes, you will see that Java makes it easy to develop networking applications as Java was built for the Internet. The examples are very interesting: a daytime client, a Whois client, a HTTP client and a SMTP client.

 

1. Client Socket API

The Socketclass represents a socket client. You use this class to make connection to a server, send data to and read data from that server. The following steps are applied for a typical communication with the server:

1. The client initiates connection to a server specified by hostname/IP address and port number.

2. Send data to the server using an OutputStream.

3. Read data from the server using an InputStream.

4. Close the connection.

The steps 2 and 3 can be repeated many times depending on the nature of the communication.

Now, let’s study how to use the Socket class to implement these steps.

 

Initiate Connection to a Server:

To make a connection to a server, create a new Socket object using one of the following constructors:

- Socket(InetAddress address, int port)

- Socket(String host, int port)

- Socket(InetAddress address, int port, InetAddress localAddr, int localPort)

You see, it requires the IP address/hostname of the server and the port number.

With the first two constructors, the system automatically assigns a free port number and a local address for the client computer. With the third constructor, you can explicitly specify the address and port number of the client if needed. The first constructor is often used because of its simplicity.

These constructors can throw the following checked exceptions:

- IOException: if an I/O error occurs when creating the socket.

- UnknownHostException: if the IP address of the host could not be determined.

That means you have to catch (or re-throw) these checked exceptions when creating a Socket instance. The following line of code demonstrates how to create a client socket that attempts to connect to google.com at port number 80:

Socket socket = new Socket("google.com", 80)

 

Send Data to the Server:

To send data to the server, get the OutputStream object from the socket first:

OutputStream output = socket.getOutputStream();

Then you can use the write() method on the OutputStream to write an array of byte to be sent:

byte[] data = ….
output.write(data);

And you can wrap the OutputStream in a PrintWriter to send data in text format, like this:

PrintWriter writer = new PrintWriter(output, true);
writer.println(“This is a message sent to the server”);

The argument true indicates that the writer flushes the data after each method call (auto flush).

 

Read Data from the Server:

Similarly, you need to obtain an InputStream object from the client socket to read data from the server:

InputStream input = socket.getInputStream();

Then use the read() method on the InputStream to read data as an array of byte, like this:

byte[] data =…
input.read(data);

You can wrap the InputStream object in an InputStreamReader or BufferedReader to read data at higher level (character and String). For example, using InputStreamReader:

InputStreamReader reader = new InputStreamReader(input);
int character = reader.read();	// reads a single character

And using BufferedReader:

BufferedReader reader = new BufferedReader(new InputStreamReader(input));
String line = reader.readLine();	// reads a line of text

 

Close the Connection:

Simply call the close() method on the socket to terminate the connection between the client and the server:

socket.close();

This method also closes the socket’s InputStream and OutputStream, and it can throw IOException if an I/O error occurs when closing the socket.

We recommend you to use the try-with-resource structure so you don’t have to write code to close the socket explicitly.

Now, let’s see some sample programs to learn to code a complete client application. The following examples illustrate how to connect to some well-known Internet services.

 

2. Java Socket Client Example #1: a Daytime Client

The server at time.nist.gov (NIST - National Institute of Standards and Technology) provides a time request service on port 13 (port 13 is for Daytime protocol).

The following program connects to NIST time server to read the current date and time:

import java.net.*;
import java.io.*;

/**
 * This program is a socket client application that connects to a time server
 * to get the current date time.
 *
 * @author www.codejava.net
 */
public class TimeClient {

	public static void main(String[] args) {
		String hostname = "time.nist.gov";
		int port = 13;

		try (Socket socket = new Socket(hostname, port)) {

			InputStream input = socket.getInputStream();
			InputStreamReader reader = new InputStreamReader(input);

			int character;
			StringBuilder data = new StringBuilder();

			while ((character = reader.read()) != -1) {
				data.append((char) character);
			}

			System.out.println(data);


		} catch (UnknownHostException ex) {

			System.out.println("Server not found: " + ex.getMessage());

		} catch (IOException ex) {

			System.out.println("I/O error: " + ex.getMessage());
		}
	}
}

As you can see, this program simply makes a connection and read data from the server. It doesn’t send any data to the server, due to the simple nature of Daytime protocol.

Run this program and you would see the output like this (two blank lines - one after and one before):

58068 17-11-11 10:26:13 00 0 0 152.5 UTC(NIST) *

 This is the current date and time returned by the server, in UTC time zone.

 

3. Java Socket Client Example #2: a Whois Client

Whois is an Internet service that allows you to query information about a specific domain name.

The InterNIC (The Network Information Center) provides a Whois service on port number 43 (port 43 is for Whois protocol).

Hence we can develop the following program to “whois” any domain name we want:

import java.net.*;
import java.io.*;

/**
 * This program demonstrates a client socket application that connects
 * to a Whois server to get information about a domain name.
 * @author www.codejava.net
 */
public class WhoisClient {

	public static void main(String[] args) {
		if (args.length < 1) return;

		String domainName = args[0];

		String hostname = "whois.internic.net";
		int port = 43;

		try (Socket socket = new Socket(hostname, port)) {

			OutputStream output = socket.getOutputStream();
			PrintWriter writer = new PrintWriter(output, true);
			writer.println(domainName);

			InputStream input = socket.getInputStream();

			BufferedReader reader = new BufferedReader(new InputStreamReader(input));

			String line;

			while ((line = reader.readLine()) != null) {
				System.out.println(line);
			}
		} catch (UnknownHostException ex) {

			System.out.println("Server not found: " + ex.getMessage());

		} catch (IOException ex) {

			System.out.println("I/O error: " + ex.getMessage());
		}
	}
}

As you can see, the domain name is passed to the program as an argument. After connected to the server, it sends the domain name, and reads the response from the server.

Run this program from command line using the following command:

java WhoisClient google.com

And you would see some information about the domain google.com like this:

   Domain Name: GOOGLE.COM
   Registry Domain ID: 2138514_DOMAIN_COM-VRSN
   Registrar WHOIS Server: whois.markmonitor.com
   Registrar URL: http://www.markmonitor.com
   Updated Date: 2011-07-20T16:55:31Z
   Creation Date: 1997-09-15T04:00:00Z
   Registry Expiry Date: 2020-09-14T04:00:00Z
   Registrar: MarkMonitor Inc.
   Registrar IANA ID: 292
…

You can see the domain google.com was registered in 1997 and it will expire in 2020.

 

4. Java Socket Client Example #3: a HTTP Client

The following program demonstrates how to connect to a web server via port 80, send a HEAD request and read message sent back from the server:

import java.net.*;
import java.io.*;

/**
 * This program demonstrates a client socket application that connects to
 * a web server and send a HTTP HEAD request.
 *
 * @author www.codejava.net
 */
public class HttpClient {

	public static void main(String[] args) {
		if (args.length < 1) return;

		URL url;

		try {
			url = new URL(args[0]);
		} catch (MalformedURLException ex) {
			ex.printStackTrace();
			return;
		}

		String hostname = url.getHost();
		int port = 80;

		try (Socket socket = new Socket(hostname, port)) {

			OutputStream output = socket.getOutputStream();
			PrintWriter writer = new PrintWriter(output, true);

			writer.println("HEAD " + url.getPath() + " HTTP/1.1");
			writer.println("Host: " + hostname);
			writer.println("User-Agent: Simple Http Client");
			writer.println("Accept: text/html");
			writer.println("Accept-Language: en-US");
			writer.println("Connection: close");
			writer.println();

			InputStream input = socket.getInputStream();

			BufferedReader reader = new BufferedReader(new InputStreamReader(input));

			String line;

			while ((line = reader.readLine()) != null) {
				System.out.println(line);
			}
		} catch (UnknownHostException ex) {

			System.out.println("Server not found: " + ex.getMessage());

		} catch (IOException ex) {

			System.out.println("I/O error: " + ex.getMessage());
		}
	}
}

As you can see, the URL is passed to the program as an argument. The program basically sends a HEAD request (follows HTTP protocol) in the following format:

HEAD <URL> HTTP/1.1
Host: <hostname>
User-Agent: <information about the client>
Accept: <format accepted by the client>
Accept-Language: <language accepted by the client>
Connection: <connection type, close or keep-alive>

Run this program from command line using this command:

java HttpClient http://www.codejava.net/java-core

You would see the server’s response like this:

HTTP/1.1 200 OK
Server: nginx/1.12.2
Date: Sat, 11 Nov 2017 10:46:57 GMT
Content-Type: text/html; charset=utf-8
Connection: close
P3P: CP="NOI ADM DEV PSAi COM NAV OUR OTRo STP IND DEM"
Cache-Control: no-cache
Pragma: no-cache
…

It’s very interesting, isn’t it?

 

5. Java Socket Client Example #4: a SMTP Client

The following program is more interesting, as it demonstrates communication between the program and a SMTP server (We use Google’s mail server - smtp.gmail.com). Here’s the code:

import java.net.*;
import java.io.*;

/**
 * This program demonstrates a socket client program that talks to a SMTP server.
 *
 * @author www.codejava.net
 */
public class SmtpClient {

	public static void main(String[] args) {

		String hostname = "smtp.gmail.com";
		int port = 25;

		try (Socket socket = new Socket(hostname, port)) {

			InputStream input = socket.getInputStream();

			OutputStream output = socket.getOutputStream();
			PrintWriter writer = new PrintWriter(output, true);

			BufferedReader reader = new BufferedReader(new InputStreamReader(input));

			String line = reader.readLine();
			System.out.println(line);

			writer.println("helo " + hostname);

			line = reader.readLine();
			System.out.println(line);

			writer.println("quit");
			line = reader.readLine();
			System.out.println(line);

		} catch (UnknownHostException ex) {

			System.out.println("Server not found: " + ex.getMessage());

		} catch (IOException ex) {

			System.out.println("I/O error: " + ex.getMessage());
		}
	}
}

Basically, this program talks to a server via SMTP protocol, by sending a couple simple SMTP commands like HELO and QUIT. Run this program and you would see the following output:

220 smtp.gmail.com ESMTP w17sm23360916pfa.70 - gsmtp
250 smtp.gmail.com at your service
221 2.0.0 closing connection w17sm23360916pfa.70 - gsmtp

These are the response messages from a SMTP server. The dialogue between the client and the server is actually like this (S for server and C for client):

C: Connect to smtp.gmail.com on port 25
S: 220 smtp.gmail.com ESMTP w17sm23360916pfa.70 - gsmtp
C: helo smtp.gmail.com
S: 250 smtp.gmail.com at your service
C: quit
S: 221 2.0.0 closing connection w17sm23360916pfa.70 - gsmtp

As you can see in the examples above, you can create fully functional Internet applications if you understand the protocol or communication between the client and the server.

 

API Reference:

Socket Class Javadoc

 

Related Java Network Tutorials:

 

Other Java network tutorials:

]]>
hainatu@gmail.com (Nam Ha Minh)NetworkingSat, 11 Nov 2017 07:07:21 -0600
How to Create a Chat Console Application in Java using Sockethttps://owt.codejava.net/java-se/networking/how-to-create-a-chat-console-application-in-java-using-sockethttps://owt.codejava.net/java-se/networking/how-to-create-a-chat-console-application-in-java-using-socket

In this Java network programming tutorial, you will learn how to create a chat application in Java using Socket programming. Source code is provided for you to download.

 

1. Overview of the Java Chat Application

The Java Chat application you are going to build is a console application that is launched from the command line. The server and clients can run on different computers in the same network, e.g. Local Area Network (LAN).

There can be multiple clients connect to a server and they can chat to each other, just like in a chat room where everyone can see other users’ messages. There’s no private chat between two users, for simplicity.

After getting connected to the server, a user must provide his or her name to enter the chat. The server sends a list of currently online users to the new user.

Every user is notified when a new user arrives and when a user has gone. Each message is prefixed with the username to keep track who sent the message.

And finally, the user says ‘bye’ to quit the chat.

The application consists of two parts: server and client. Each part can run independently on separate computers.

Now, let’s see how to code this Java chat application in details.

 

2. Create the Chat Server Program

The server is implemented by two classes: ChatServer and UserThread.

The ChatServer class starts the server, listening on a specific port. When a new client gets connected, an instance of UserThread is created to serve that client. Since each connection is processed in a separate thread, the server is able to handle multiple clients at the same time.

The following is source code of the ChatServer class:

package net.codejava.networking.chat.server;

import java.io.*;
import java.net.*;
import java.util.*;

/**
 * This is the chat server program.
 * Press Ctrl + C to terminate the program.
 *
 * @author www.codejava.net
 */
public class ChatServer {
	private int port;
	private Set<String> userNames = new HashSet<>();
	private Set<UserThread> userThreads = new HashSet<>();

	public ChatServer(int port) {
		this.port = port;
	}

	public void execute() {
		try (ServerSocket serverSocket = new ServerSocket(port)) {

			System.out.println("Chat Server is listening on port " + port);

			while (true) {
				Socket socket = serverSocket.accept();
				System.out.println("New user connected");

				UserThread newUser = new UserThread(socket, this);
				userThreads.add(newUser);
				newUser.start();

			}

		} catch (IOException ex) {
			System.out.println("Error in the server: " + ex.getMessage());
			ex.printStackTrace();
		}
	}

	public static void main(String[] args) {
		if (args.length < 1) {
			System.out.println("Syntax: java ChatServer <port-number>");
			System.exit(0);
		}

		int port = Integer.parseInt(args[0]);

		ChatServer server = new ChatServer(port);
		server.execute();
	}

	/**
	 * Delivers a message from one user to others (broadcasting)
	 */
	void broadcast(String message, UserThread excludeUser) {
		for (UserThread aUser : userThreads) {
			if (aUser != excludeUser) {
				aUser.sendMessage(message);
			}
		}
	}

	/**
	 * Stores username of the newly connected client.
	 */
	void addUserName(String userName) {
		userNames.add(userName);
	}

	/**
	 * When a client is disconneted, removes the associated username and UserThread
	 */
	void removeUser(String userName, UserThread aUser) {
		boolean removed = userNames.remove(userName);
		if (removed) {
			userThreads.remove(aUser);
			System.out.println("The user " + userName + " quitted");
		}
	}

	Set<String> getUserNames() {
		return this.userNames;
	}

	/**
	 * Returns true if there are other users connected (not count the currently connected user)
	 */
	boolean hasUsers() {
		return !this.userNames.isEmpty();
	}
}

As you can see, the ChatServer class has two Set collections to keep track the names and threads of the connected clients. Set is used because it doesn’t allow duplication and the order of elements does not matter:

private Set<String> userNames = new HashSet<>();
private Set<UserThread> userThreads = new HashSet<>();

An important method in the ChatServer class is broadcast() which deliver a message from one client to all others clients:

void broadcast(String message, UserThread excludeUser) {
	for (UserThread aUser : userThreads) {
		if (aUser != excludeUser) {
			aUser.sendMessage(message);
		}
	}
}

The UserThread class is responsible for reading messages sent from the client and broadcasting messages to all other clients. First, it sends a list of online users to the new user. Then it reads the username and notifies other users about the new user.

The following code is of the UserThread class:

package net.codejava.networking.chat.server;

import java.io.*;
import java.net.*;
import java.util.*;

/**
 * This thread handles connection for each connected client, so the server
 * can handle multiple clients at the same time.
 *
 * @author www.codejava.net
 */
public class UserThread extends Thread {
	private Socket socket;
	private ChatServer server;
	private PrintWriter writer;

	public UserThread(Socket socket, ChatServer server) {
		this.socket = socket;
		this.server = server;
	}

	public void run() {
		try {
			InputStream input = socket.getInputStream();
			BufferedReader reader = new BufferedReader(new InputStreamReader(input));

			OutputStream output = socket.getOutputStream();
			writer = new PrintWriter(output, true);

			printUsers();

			String userName = reader.readLine();
			server.addUserName(userName);

			String serverMessage = "New user connected: " + userName;
			server.broadcast(serverMessage, this);

			String clientMessage;

			do {
				clientMessage = reader.readLine();
				serverMessage = "[" + userName + "]: " + clientMessage;
				server.broadcast(serverMessage, this);

			} while (!clientMessage.equals("bye"));

			server.removeUser(userName, this);
			socket.close();

			serverMessage = userName + " has quitted.";
			server.broadcast(serverMessage, this);

		} catch (IOException ex) {
			System.out.println("Error in UserThread: " + ex.getMessage());
			ex.printStackTrace();
		}
	}

	/**
	 * Sends a list of online users to the newly connected user.
	 */
	void printUsers() {
		if (server.hasUsers()) {
			writer.println("Connected users: " + server.getUserNames());
		} else {
			writer.println("No other users connected");
		}
	}

	/**
	 * Sends a message to the client.
	 */
	void sendMessage(String message) {
		writer.println(message);
	}
}

Then it enters a loop of reading message from the user and sending it to all other users, until the user sends ‘bye’ indicating he or she is going to quit. And finally it notifies other users about the disconnection of this user and closes the connection.

 

3. Create the Chat Client Program

The client is implemented by three classes: ChatClient, ReadThread and WriteThread.

The ChatClient starts the client program, connects to a server specified by hostname/IP address and port number. Once the connection is made, it creates and starts two threads ReadThread and WriteThread.

Here is source code of the ChatClient class:

package net.codejava.networking.chat.client;

import java.net.*;
import java.io.*;

/**
 * This is the chat client program.
 * Type 'bye' to terminte the program.
 *
 * @author www.codejava.net
 */
public class ChatClient {
	private String hostname;
	private int port;
	private String userName;

	public ChatClient(String hostname, int port) {
		this.hostname = hostname;
		this.port = port;
	}

	public void execute() {
		try {
			Socket socket = new Socket(hostname, port);

			System.out.println("Connected to the chat server");

			new ReadThread(socket, this).start();
			new WriteThread(socket, this).start();

		} catch (UnknownHostException ex) {
			System.out.println("Server not found: " + ex.getMessage());
		} catch (IOException ex) {
			System.out.println("I/O Error: " + ex.getMessage());
		}

	}

	void setUserName(String userName) {
		this.userName = userName;
	}

	String getUserName() {
		return this.userName;
	}


	public static void main(String[] args) {
		if (args.length < 2) return;

		String hostname = args[0];
		int port = Integer.parseInt(args[1]);

		ChatClient client = new ChatClient(hostname, port);
		client.execute();
	}
}

The ReadThread is responsible for reading input from the server and printing it to the console repeatedly, until the client disconnects. This class is implemented as follows:

package net.codejava.networking.chat.client;

import java.io.*;
import java.net.*;

/**
 * This thread is responsible for reading server's input and printing it
 * to the console.
 * It runs in an infinite loop until the client disconnects from the server.
 *
 * @author www.codejava.net
 */
public class ReadThread extends Thread {
	private BufferedReader reader;
	private Socket socket;
	private ChatClient client;

	public ReadThread(Socket socket, ChatClient client) {
		this.socket = socket;
		this.client = client;

		try {
			InputStream input = socket.getInputStream();
			reader = new BufferedReader(new InputStreamReader(input));
		} catch (IOException ex) {
			System.out.println("Error getting input stream: " + ex.getMessage());
			ex.printStackTrace();
		}
	}

	public void run() {
		while (true) {
			try {
				String response = reader.readLine();
				System.out.println("\n" + response);

				// prints the username after displaying the server's message
				if (client.getUserName() != null) {
					System.out.print("[" + client.getUserName() + "]: ");
				}
			} catch (IOException ex) {
				System.out.println("Error reading from server: " + ex.getMessage());
				ex.printStackTrace();
				break;
			}
		}
	}
}

And the WriteThread is responsible for reading input from the user and sending it to the server, continuously until the user types ‘bye’ to end the chat. This class is implemented as follows:

package net.codejava.networking.chat.client;

import java.io.*;
import java.net.*;

/**
 * This thread is responsible for reading user's input and send it
 * to the server.
 * It runs in an infinite loop until the user types 'bye' to quit.
 *
 * @author www.codejava.net
 */
public class WriteThread extends Thread {
	private PrintWriter writer;
	private Socket socket;
	private ChatClient client;

	public WriteThread(Socket socket, ChatClient client) {
		this.socket = socket;
		this.client = client;

		try {
			OutputStream output = socket.getOutputStream();
			writer = new PrintWriter(output, true);
		} catch (IOException ex) {
			System.out.println("Error getting output stream: " + ex.getMessage());
			ex.printStackTrace();
		}
	}

	public void run() {

		Console console = System.console();

		String userName = console.readLine("\nEnter your name: ");
		client.setUserName(userName);
		writer.println(userName);

		String text;

		do {
			text = console.readLine("[" + userName + "]: ");
			writer.println(text);

		} while (!text.equals("bye"));

		try {
			socket.close();
		} catch (IOException ex) {

			System.out.println("Error writing to server: " + ex.getMessage());
		}
	}
}

The reasons for running these two threads simultaneously is that the reading operation always blocks the current thread (both reading user’s input from command line and reading server’s input via network). That means if the current thread is waiting for the user’s input, it can’t read input from the server.

Therefore, two separate threads are used to make the client responsive: it can display messages from other users while reading message from the current user.

That’s how the chat application is designed. For more details, you can read the comments in the source code provided. But there are no many comments because the code is self-explanatory.

 

4. How to Run the Chat Server

You need to specify the port number when running the server program from the command line. For example:

java ChatServer 8989

This starts the server listening on the port number 8989, and you see the following output in the server once it started:

Chat Server is listening on port 8989

The server is waiting for new clients forever, so you have to press Ctrl + C to terminate it.

 

5. How to Run a Chat Client

To run the client, you need to specify the server’s hostname/IP address and port number in the command line. For example:

java ChatClient localhost 8989

This tells the client to connect to the server at localhost on port 8989. Then you see the following message in the server’s console:

New user connected

And in the client’s console:

Connected to chat server
No other users connected

You see, the server tells the client how many users are connected, but there’s no user at this time. Then the program asks for the username:

Enter your name:_

Enter a username, say John, and then you can start chatting:

Enter your name: John
[John]:_

Now, let’s start the second client with username is Peter. At this time, you see the server tells that there’s one online user is John:

Connected users: [John]

The user John is notified about new user Peter:

New user connected: Peter

Type some messages from John and Peter and you see each user sees other’s messages, just like talking in a chat room.

Now, John wants to quit so he types ‘bye’- the client program terminates, and you see the following output in the server’s console:

The user John quitted

Peter also gets a message from the server:

John has quitted.

That’s basically how the chat application is running. You can test it with more clients and the application is still running smoothly. The following screenshot illustrates a test with 4 clients:

Chat Console Application Testing

Now, it’s your time to play around with this chat application with the source code attached.

 

Related Java Network Tutorials:

 

Other Java network tutorials:

]]>
hainatu@gmail.com (Nam Ha Minh)NetworkingWed, 20 Dec 2017 03:20:08 -0600
Java UDP Client Server Program Examplehttps://owt.codejava.net/java-se/networking/java-udp-client-server-program-examplehttps://owt.codejava.net/java-se/networking/java-udp-client-server-program-example

In this Java Network programming tutorial, you will learn how to code a client/server application based on UDP protocol.

First, let’s see how Java Network API is designed to support development of network applications that make use of UDP.

DatagramPacket and DatagramSocket are the two main classes that are used to implement a UDP client/server application. DatagramPacket is a data container and DatagramSocket is a mechanism to send and receive DatagramPackets.

 

1. DatagramPacket

In UDP’s terms, data transferred is encapsulated in a unit called datagram. A datagram is an independent, self-contained message sent over the network whose arrival, arrival time, and content are not guaranteed. And in Java, DatagramPacket represents a datagram.

You can create a DatagramPacket object by using one of the following constructors:

  • DatagramPacket(byte[] buf, int length)
  • DatagramPacket(byte[] buf, int length, InetAddress address, int port)

As you can see, the data must be in the form of an array of bytes. The first constructor is used to create a DatagramPacket to be received.

The second constructor creates a DatagramPacket to be sent, so you need to specify the address and port number of the destination host.

The parameter length specifies the amount of data in the byte array to be used, usually is the length of the array (buf.length).

 

There are also other constructors that allow you to specify the offset in the byte array, as well as using a SocketAddress:

  • DatagramPacket(byte[] buf, int offset, int length)
  • DatagramPacket(byte[] buf, int offset, int length, SocketAddress address)

In addition, the DatagramPacket provides setter and getter methods for address, data and port number. Consult its DatagramPacket Javadoc for full details.

 

2. DatagramSocket

You use DatagramSocket to send and receive DatagramPackets. DatagramSocket represents a UDP connection between two computers in a network.

In Java, we use DatagramSocket for both client and server. There are no separate classes for client and server like TCP sockets.

So you create a DatagramSocket object to establish a UDP connection for sending and receiving datagram, by using one of the following constructors:

  • DatagramSocket()
  • DatagramSocket(int port)
  • DatagramSocket(int port, InetAddress laddr)

The no-arg constructor is used to create a client that binds to an arbitrary port number. The second constructor is used to create a server that binds to the specific port number, so the clients know how to connect to.

And the third constructor binds the server to the specified IP address (in case the computer has multiple IP addresses).

These constructors can throw SocketException if the socket could not be opened, or the socket could not bind to the specified port or address. So you have catch or re-throw this checked exception.

 

The key methods of the DatagramSocket include:

  • send(DatagramPacket p): sends a datagram packet.
  • receive(DatagramPacket p): receives a datagram packet.
  • setSoTimeout(int timeout): sets timeout in milliseconds, limiting the waiting time when receiving data. If the timeout expires, a SocketTimeoutException is raised.
  • close(): closes the socket.

These methods can throw IOException, PortUnreachableException, SocketTimeoutException… so you have to catch or re-throw them. Consult the DatagramSocket Javadoc for full details.

Now, let’s see some sample programs in action.

 

3. Java UDP Client Example

We will write code for a client program that requests for quotes from a server that implements the Quote of the Day (QOTD) service - an Internet standard. The following code snippet sends a DatagramPacket to a server specified by hostname and port:

String hostname = "djxmmx.net";
int port = 17;

InetAddress address = InetAddress.getByName(hostname);
DatagramSocket socket = new DatagramSocket();

byte[] buffer = new byte[512];

DatagramPacket request = new DatagramPacket(buffer, buffer.length, address, port);
socket.send(request);

As you can see, the buffer has no data because QOTD service doesn’t require a client sends any specific message. And you have to specify the server’s address and port in the DatagramPacket. So this code just sends a signal to the server implying that “Hey, I’d like to get a quote from you”.

And the following code snippet receives a DatagramPacket from the server:

DatagramPacket response = new DatagramPacket(buffer, buffer.length);
socket.receive(response);

String quote = new String(buffer, 0, response.getLength());

System.out.println(quote);

As you can see, once the socket is opened, receiving a packet is very simple. And the code converts the byte array to a String to be printed in readable format.

And here is the code of the full client program that parameterizes the hostname and port number, handles exceptions and gets a quote from the server for every 10 seconds:

import java.io.*;
import java.net.*;

/**
 * This program demonstrates how to implement a UDP client program.
 *
 *
 * @author www.codejava.net
 */
public class QuoteClient {

	public static void main(String[] args) {
		if (args.length < 2) {
			System.out.println("Syntax: QuoteClient <hostname> <port>");
			return;
		}

		String hostname = args[0];
		int port = Integer.parseInt(args[1]);

		try {
			InetAddress address = InetAddress.getByName(hostname);
			DatagramSocket socket = new DatagramSocket();

			while (true) {

				DatagramPacket request = new DatagramPacket(new byte[1], 1, address, port);
				socket.send(request);

				byte[] buffer = new byte[512];
				DatagramPacket response = new DatagramPacket(buffer, buffer.length);
				socket.receive(response);

				String quote = new String(buffer, 0, response.getLength());

				System.out.println(quote);
				System.out.println();

				Thread.sleep(10000);
			}

		} catch (SocketTimeoutException ex) {
			System.out.println("Timeout error: " + ex.getMessage());
			ex.printStackTrace();
		} catch (IOException ex) {
			System.out.println("Client error: " + ex.getMessage());
			ex.printStackTrace();
		} catch (InterruptedException ex) {
			ex.printStackTrace();
		}
	}
}

To test this client program, type the following command:

java QuoteClient djxmmx.net 17

djxmmx.net is a public QOTD server we can use, and 17 is the port number reserved for QOTD service.

You would see the output something like this:

"When a stupid man is doing something he is ashamed of, he always declares that it is his duty." George Bernard Shaw (1856-1950)

"Oh the nerves, the nerves; the mysteries of this machine called man!
 Oh the little that unhinges it, poor creatures that we are!"
 Charles Dickens (1812-70)

 In Heaven an angel is nobody in particular." George Bernard Shaw (1856-1950)

If you test this program yourself, you may see different quotes because the server returns random quotes. Press Ctrl + C to terminate the program.

 

4. Java UDP Server Example

The following sample program demonstrates how to implement a server for the above client. The following code creates a UDP server listening on port 17 and waiting for client’s request:

DatagramSocket socket = new DatagramSocket(17);

byte[] buffer = new byte[256];

DatagramPacket request = new DatagramPacket(buffer, buffer.length);
socket.receive(request);

The receive() method blocks until a datagram is received. And the following code sends a DatagramPacket to the client:

InetAddress clientAddress = request.getAddress();
int clientPort = request.getPort();

String data = "Message from server";
buffer = data.getBytes();

DatagramPacket response = new DatagramPacket(buffer, buffer.length, clientAddress, clientPort);
socket.send(response);

As you can see, the server also needs to know client’s address and port to send the DatagramPacket. This information can be obtained from the DatagramPacket received from the client previously. And a String is converted to an array of bytes which then can be wrapped in a DatagramPacket.

And the following is a full-featured server program that reads quotes from a text file, and sends a random quote for every client’s request. The quote file and port number are given as program’s arguments. Here’s the code:

import java.io.*;
import java.net.*;
import java.util.*;

/**
 * This program demonstrates how to implement a UDP server program.
 *
 *
 * @author www.codejava.net
 */
public class QuoteServer {
	private DatagramSocket socket;
	private List<String> listQuotes = new ArrayList<String>();
	private Random random;

	public QuoteServer(int port) throws SocketException {
		socket = new DatagramSocket(port);
		random = new Random();
	}

	public static void main(String[] args) {
		if (args.length < 2) {
			System.out.println("Syntax: QuoteServer <file> <port>");
			return;
		}

		String quoteFile = args[0];
		int port = Integer.parseInt(args[1]);

		try {
			QuoteServer server = new QuoteServer(port);
			server.loadQuotesFromFile(quoteFile);
			server.service();
		} catch (SocketException ex) {
			System.out.println("Socket error: " + ex.getMessage());
		} catch (IOException ex) {
			System.out.println("I/O error: " + ex.getMessage());
		}
	}

	private void service() throws IOException {
		while (true) {
			DatagramPacket request = new DatagramPacket(new byte[1], 1);
			socket.receive(request);

			String quote = getRandomQuote();
			byte[] buffer = quote.getBytes();

			InetAddress clientAddress = request.getAddress();
			int clientPort = request.getPort();

			DatagramPacket response = new DatagramPacket(buffer, buffer.length, clientAddress, clientPort);
			socket.send(response);
		}
	}

	private void loadQuotesFromFile(String quoteFile) throws IOException {
		BufferedReader reader = new BufferedReader(new FileReader(quoteFile));
		String aQuote;

		while ((aQuote = reader.readLine()) != null) {
			listQuotes.add(aQuote);
		}

		reader.close();
	}

	private String getRandomQuote() {
		int randomIndex = random.nextInt(listQuotes.size());
		String randomQuote = listQuotes.get(randomIndex);
		return randomQuote;
	}
}

Suppose we have a Quotes.txt file with the following content (each quote is in a single line):

Whether you think you can or you think you can't, you're right - Henry Ford
There are no traffic jams along the extra mile - Roger Staubach
Build your own dreams, or someone else will hire you to build theirs - Farrah Gray
What you do today can improve all your tomorrows - Ralph Marston
Remember that not getting what you want is sometimes a wonderful stroke of luck - Dalai Lama

Type the following command to run the server program:

java QuoteServer Quotes.txt 17

And run the client program (on the same computer):

java QuoteClient localhost 17

Both the client and server are running in an infinite loop, so you have to press Ctrl + C to terminate.

That’s the lesson about how to develop a network client/server application relying on UDP protocol. Based on this knowledge, you are able to develop client programs that communicate with servers via UDP, and developing your own UDP client/server applications.

 

API References:

 

Related Java Network Tutorials:

 

Other Java network tutorials:

]]>
hainatu@gmail.com (Nam Ha Minh)NetworkingFri, 17 Nov 2017 19:52:00 -0600
Java InetAddress Exampleshttps://owt.codejava.net/java-se/networking/java-inetaddress-exampleshttps://owt.codejava.net/java-se/networking/java-inetaddress-examples

This article helps you understand InetAddress- a fundamental class in Java Network API.

The InetAddress class represents an IP address, both IPv4 and IPv6. Basically you create instances of this class to use with other classes such as Socket, ServerSocket, DatagramPacket and DatagramSocket. In the simplest case, you can use this class to know the IP address from a hostname, and vice-versa.

The InetAddress class doesn’t have public constructors, so you create a new instance by using one of its factory methods:

  • getByName(String host): creates an InetAddress object based on the provided hostname.
  • getByAddress(byte[] addr): returns an InetAddress object from a byte array of the raw IP address.
  • getAllByName(String host): returns an array of InetAddress objects from the specified hostname, as a hostname can be associated with several IP addresses.
  • getLocalHost(): returns the address of the localhost.

 

To get the IP address/hostname you can use a couple of methods below:

  • getHostAddress(): returns the IP address in text.
  • getHostname(): gets the hostname.

 

Note that the InetAddress class’s toString() method returns both hostname and IP address, e.g. www.codejava.net/198.57.151.22.

In addition, this class also provides several methods for checking the address type, which would be useful for system programmers. However we don’t have to concern about those methods, most of the time.

 

Let’s see some examples that demonstrate how to use the InetAddress class.

 

Get IP address of a given domain/hostname:

The following code prints the IP address of a given hostname:

InetAddress address1 = InetAddress.getByName("www.codejava.net");
System.out.println(address1.getHostAddress());

 

Get hostname from IP address:

The following code finds out the hostname from an IP address:

InetAddress address2 = InetAddress.getByName("8.8.8.8");
System.out.println(address2.getHostName());

 

List all IP addresses associate with a hostname/domain:

The following code prints all the IP addresses associated with the hostname google.com:

InetAddress[] google = InetAddress.getAllByName("google.com");

for (InetAddress addr : google) {
	System.out.println(addr.getHostAddress());
}

 

Get the localhost address:

And the following code gets the localhost address:

InetAddress localhost = InetAddress.getLocalHost();
System.out.println(localhost);

 

Inet4Address and Inet6Address:

These are subclasses of the InetAddress class. Inet4Address and Inet6Address represent IPv4 and IPv6 addresses, respectively. However, when writing network applications, you don’t have to concern about IPv4 or IPv6 as Java hides all the details.

The InetAddress can refer to either Inet4Address or Inet6Address so most of the time, using InetAddress is enough.

 

References:

InetAddress Class Javadoc

 

Related Java Network Tutorials:

 

Other Java network tutorials:

]]>
hainatu@gmail.com (Nam Ha Minh)NetworkingTue, 07 Nov 2017 00:50:13 -0600