Chapter 30. Network Chat


Firewalls

Firewalls are unfortunately a part of today's networking experience. Most companies, government institutions, universities, and so on, utilize firewalls to block access to the wider Internet: socket creation on all nonstandard ports, and most standard ones, are typically prohibited, and web pages must be retrieved through a proxy that filters (limits) the traffic.

The firewall-related examples in this section can be found in the NetBasics/Firewall/ directory.


This situation means that the code described so far may not work because it requires the creation of sockets. The DayPing example given below is a Java application that attempts to contact a "time-of-day" server. The example below uses the server at the National Institute of Standards and Technology in Boulder, Colorado:

     >java DayPing time-A.timefreq.bldrdoc.gov     time-A.timefreq.bldrdoc.gov is alive at     53394 05-01-24 09:16:12 00 0 0 525.7 UTC(NIST) *

DayPing opens a socket to the host at port 13, where the standard time-of-day service is listening. The response is printed out using println( ) after layering a BufferedReader stream on top of the network link:

     public class DayPing     {        public static void main(String args[]) throws IOException        {  if (args.length != 1) {             System.out.println("usage:  java DayPing <host> ");             System.exit(0);           }           Socket sock = new Socket(args[0],13);   // host and port           BufferedReader br = new BufferedReader(                   new InputStreamReader( sock.getInputStream( ) ) );           System.out.println( args[0] + " is alive at ");           String line;           while ( (line = br.readLine( )) != null)             System.out.println(line);           sock.close( );        }     } // end of DayPing class

The desired DayPing output is shown above, but this isn't what's returned to most student machines in my department. For students, this is the result:

     >java DayPing time-A.timefreq.bldrdoc.gov       Exception in thread "main"       java.net.NoRouteToHostException: Operation timed out: no further information             at java.net.PlainSocketImpl.                 socketConnect (Native Method)                     :  // many lines, which I've edited out             at DayPing.main(DayPing.java:34)

There's a long delay (two to three minutes) before the exception is raised, due to the OS waiting for a possible connection. The exception indicates the presence of a firewall preventing the link.

With TCP client applications such as DayPing, it's possible to check the server with telnet:

     >telnet time-A.timefreq.bldrdoc.gov 13

There's a similar outcome: a delay of a few minutes, followed by an error message saying that the connection couldn't be made.

My university has a policy of disallowing socket creation for hosts outside the local domain, and web pages can be retrieved only by going through a proxy located at cache.psu.ac.th, port 8080. Therefore, there are two choices:

  • Use a commercial ISP that does allow socket creation.

  • Rewrite the DayPing application to utilize URLs.

The second approach is taken here.

Retrieving a Web Page

The simplest way of obtaining a web page in Java is with a URL object, which retrieves it as a stream of text in a similar way to streams connected to sockets. The GetWebPage application downloads a web page using a URL specified on the command line:

     public class GetWebPage     {        public static void main(String args[]) throws IOException        { if (args.length != 1) {            System.out.println("usage:  java GetWebPage <url> ");            System.exit(0);          }               URL url  = new URL(args[0]);          BufferedReader br = new BufferedReader(                                 new InputStreamReader( url.openStream( ) ));          // print first ten lines of contents          int numLine = 0;          String line;          while ( ((line = br.readLine( )) != null) && (numLine <= 10) ) {            System.out.println(line);            numLine++;          }          if (line != null)            System.out.println(". . .");          br.close( );        }     } // end of GetWebPage class

GetWebPage can access any web page, including one giving the current time in Thailand at http://www.timeanddate.com/worldclock/city.html?n=28. However, the command line must include three proxy options (proxySet, proxyHost, and proxyPort) to tell the JVM to employ the university's proxy server. The call and result are:

     >java -DproxySet=true -DproxyHost=cache.psu.ac.th -DproxyPort=8080 GetWebPage     http://www.timeanddate.com/worldclock/city.html?n=28     <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">     <!-- scripts and programs that download content transparent to the user are not     allowed without permision -->     <html>     <head>     <title>Current local time in Bangkok - Thailand</title>     <link rel="stylesheet" type="text/css" href="/common/style.css">     <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">     </head>     <body>      . . .     >

GetWebPage only displays the first 11 lines of the retrieved web page, which isn't enough to reach the time information on this page.

An alternative to command line settings is to specify the proxy details within the program:

     Properties props = System.getProperties( );     props.put("proxySet", "true");     props.put("proxyHost", "cache.psu.ac.th");     props.put("proxyPort", "8080");     System.setProperties(props);

This should be done before the creation of the URL object.

An important aspect of this coding style is the processing of the text stream arriving from the web server. It's often far from trivial to delve through the mix of HTML tags, JavaScript, and others to find the required piece of information (e.g., that the current time in Bangkok is 4:19 P.M.).

Another problem is that any text analysis code tends to break after awhile as the format of the web page is changed/updated.

Proxy Authorization

Some proxy servers demand a login and password before pages can be downloaded (this is true of one of the high bandwidth lines out of my department).

Supplying these from within a Java application requires the use of a URLConnection object to permit greater control over the URL link:

     URL url = new URL(args[0]);     URLConnection conn = url.openConnection( );

The login and password strings must be passed to the proxy server as a single string of the form "login:password" translated into Base64 encoding:

     Base64Converter bc = new Base64Converter( );     String encoding = bc.encode(login + ":" + password );

The Base64Converter class was written by David Wallace Croft and is available with documentation from "Java Tip 47," JavaWorld.com, April 6, 2000 (http://www.javaworld.com/javaworld/javatips/jw-javatip47.html).

There is also an undocumented BASE64Encoder class in the sun.misc package of J2SE used this way:

     Base64Encoder bc = new Base64Encoder( );     String mesg = login + ":" + password;     String encoding = bc.encode( mesg.getBytes( ) );

The encoded string is sent to the proxy as an authorization request:

     conn.setRequestProperty("Proxy-Authorization", "Basic " + encoding);

GetWebPageP.java contains all of this functionality; it reads the user's password and desired URL from the command line:

     public class GetWebPageP     {       private static final String LOGIN = "ad";  // modify this       public static void main(String args[]) throws IOException       {  if (args.length != 2) {           System.out.println("usage: java GetWebPageP <password> <url>");           System.exit(0);          }          // set the properties used for proxy support          Properties props = System.getProperties( );          props.put("proxySet", "true");          props.put("proxyHost", "cache.psu.ac.th");          props.put("proxyPort", "8080");          System.setProperties(props);          // create a URL and URLConnection          URL url  = new URL(args[1]);   // URL string          URLConnection conn = url.openConnection( );          // encode the "login:password" string          Base64Converter bc = new Base64Converter( );          String encoding = bc.encode( LOGIN + ":" + args[0] );          // send the authorization          conn.setRequestProperty("Proxy-Authorization",                                "Basic " + encoding);          BufferedReader br = new BufferedReader (                    new InputStreamReader ( conn.getInputStream( ) ));          // print first ten lines of contents          int numLine = 0;          String line;          while ( ((line = br.readLine( )) != null) && (numLine <= 10) ) {            System.out.println(line);            numLine++;          }          if (line != null)            System.out.println(". . .");          br.close( );          System.exit(0);       } // end of main( )     } // end of GetWebPageP class

A Web-Based Client and Server

These time-of-day examples fit the familiar client/server model in the case when a server exists. However, most applications require new clients and a new server. The question then is how to make the server side of the program act as a web server, deliver web pages, and satisfy the restrictions of the client-side firewall?

Enter the Java 2 Enterprise Edition (J2EE), aimed at the construction of web-based client/server applications: it supports simplified networking, concurrency, transactions, easy access to databases, and much more (http://java.sun.com/j2ee/). Aside from Sun's implementation, many companies offer J2EE compatible systems, including Tomcat from the Jakarta Project (http://jakarta.apache.org/tomcat/) and JRun from Macromedia (http://www.macromedia.com/software/jrun).

J2EE is a complex development environment, centered around servlets, Java Server Pages (JSPs), and Enterprise JavaBeans (EJBs). Servlets are objects specialized for the serving of web content, typically web pages, in response to client requests. JSPs are web pages that may contain embedded Java. EJBs focus on server-side processing, including the connection of server-side applications to other Java functionality, such as the Java Transaction API (JTA), the Java Message Service (JMS), and Java Database Connectivity (JDBC).

Servlets deal with client requests using HTTP, which thankfully only contains a few commands; the two principal ones are the GET and POST methods. A GET method (request) is usually sent by a web browser when it asks for a page from a server. A POST method (request) is more typically associated with the submission of details taken from a web-page form.

A servlet that inherits the HttpServlet class will automatically call its doGet( ) method when a GET request arrives from a client; there's a doPost( ) for processing POST requests.

My web-based client will communicate with a servlet that implements a time-of-day service. The use of HTTP to "bypass" firewall restrictions on client/server communication is called HTTP Tunneling.

TimeServlet will be called when the TimeClient application refers to the servlet's URL (i.e., sends a GET request to the web server managing the servlet). The situation is illustrated by Figure 29-17.

Figure 29-17. Client and servlet configuration


A servlet can output a stream of HTML that is displayed nicely in the client if it's a browser. However, TimeServlet will deliver ordinary text since the client doesn't require extraneous formatting around the result.

An excellent book on servlets and JSPs is Core Servlets and Java Server Pages by Marty Hall (Sun Microsystems Press; http://www.coreservlets.com/). The complete contents of the first edition can be downloaded from http://pdf.coreservlets.com/ source code and teaching materials are available for the second edition.

A servlet that serves up time

The doGet( ) method in TimeServlet is called automatically when the servlet's URL is sent to the web server:

     public class TimeServlet extends HttpServlet     {        public void doGet( HttpServletRequest request, HttpServletResponse response)                 throws ServletException, IOException        {           SimpleDateFormat formatter = new SimpleDateFormat("d M yyyy HH:mm:ss");           Date today = new Date( );           String todayStr = formatter.format(today);           System.out.println("Today is: " + todayStr);           PrintWriter output = response.getWriter( );           output.println( todayStr );  // send date & time           output.close( );        }     }

Various client and request information is made available in the HttpServletRequest object passed to doGet( ), but TimeServlet doesn't need it.

The other argument of doGet( ) is a HttpServletResponse object that permits various forms of output to be delivered to the client. TimeServlet creates an output stream and sends a formatted date and time string.

The time client

The TimeClient application is a variant of the GetWebPage program described earlier except that the servlet's URL is hardwired into it.

Since the client and servlet are running on the same machine, proxy settings aren't needed. The web server is running at port 8100 and stores its servlets in a fixed location referred to by the URL http://localhost:8100/servlet/:

     public class TimeClient     {        public static void main(String args[]) throws IOException        {          URL url = new URL("http://localhost:8100/servlet/TimeServlet");          BufferedReader br = new BufferedReader(                   new InputStreamReader( url.openStream( ) ));          String line;          while ( (line = br.readLine( )) != null)            System.out.println(line);          br.close( );        }     }     Typical output from TimeClient is:     >java TimeClient     24 1 2548 16:27:18     >java TimeClient     24 1 2548 16:27:23

The output shows the year to be 2548, which is 2005 in the Buddhist calendar, the system used in Thailand.

An advantage of (simple) servlets is they can be tested from a browser. Figure 29-18 shows the output when http://localhost:8100/servlet/TimeServlet is typed into the Opera browser.

Figure 29-18. A browser as client for TimeServlet


A browser as client for TimeServlet enable clients to use HTTP for communication with the server part of the application (i.e., the clients employ URLs to access the server). This mode of communication is permitted by firewalls, which usually block socket links.

The downside is that HTTP is a request/response protocoli.e., the client must initiate the communication to receive a reply. It's difficult for the server to send a message to a client without first receiving one from it. This means that a web-based server has trouble broadcasting (multicasting) a message received from one client to all the others, which is a common requirement of multiplayer games and chat applications.

In Chapter 30, I will implement a web-based version of a chat system by having a client periodically query the server to collect messages from the other clients.

Applets as Clients

The default security associated with applets means they can only connect back to their home server. This restriction applies to sockets and to the downloading of web pages. However, the security can be modified with a policy file and by signing the applet. However, most multiplayer games that utilize applets host them on their own servers, so the default security policy is sufficient.

The real problem with applets is the excessive download time required to move the necessary functionality and resources (e.g., images, sounds) to the client side. Commercial games (e.g., Everquest) distribute CDs containing client applications.



Killer Game Programming in Java
Killer Game Programming in Java
ISBN: 0596007302
EAN: 2147483647
Year: 2006
Pages: 340

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net