Solved

HTTP Tunneling

Posted on 1998-05-31
3
865 Views
Last Modified: 2011-09-20
OK - To implement HTTP tunneling, I need to set up a HTTPUrlSocket at each end, right?

Then I can send requests for pages one way, and the 'pages' themselves back the other way.

How do I implement this?  Say, for instance, that I want an Applet to send username and password details to a Server.  If the username and password are correct, the Server then returns some information (a booking calender) to the Applet.

I'm not really even sure how to start!

Does the applet need to send a request for:
http://blah.blah.blah.blah/blah #username;password?

How does the Server then pick this up (how do I code it)?

Does the Server still retain normal Netscape functions (we use it as a desktop machine as well)?

What formats can the Server return information in?

How can the Applet decode this information?

I am developing on a Unix, using a late-ish version of  JDK.  I am fairly OK with the concept of setting up a telnet server (ServerSocket/Socket - I've managed to set one of these up, but it doesn't work with Applets 'cause we've got a firewall).

Thanks, Shane
0
Comment
Question by:sstephens
  • 2
3 Comments
 
LVL 4

Accepted Solution

by:
evijay earned 160 total points
ID: 1221831
Go to this page and you will find good implementation of httptunnelling


http://www.pbg.mcgraw-hill.com/betabooks/moss/chap10.html

excerpt from that page:


HTTP tunneling

In this chapter we’re going to take a look at how to user server-side objects from Java applets. Java’s RMI (Remote Method Invocation) specification
defines how this is done using TCP/IP over a secure network, but we’ll be using a process known as HTTP tunneling that will allow us to make remote
method calls over an unsecure network such as the Internet.

HTTP

HTTP (HyperText Transfer Prototcol) is an Internet client-server protocol designed for the delivery of hypertext materials such as HTML, images, and
sounds. All HTTP communication uses 8-bit characters which ensures the safe transmission of all forms of data; this will become an important point later
when we start sending and receiving binary data. Let’s take a look at the basic steps in servicing an HTTP service request:

          o Open the connection. It is very important to remember that HTTP is a state-less protocol meaning that each request is treated as an
          independent entity. Because of this a new connection must be made for each request. This is quite unlike TCP/IP, for example, where a
          connection can be maintained for the life of a given client session. We’ll see a little later that using servlet session tracking will solve the
          state-less server problem for us.

          o Send a request. The client will send a message to the Web server requesting some type of service. The request contains HTTP request
          headers that define the type and length of the request packet followed by the request data.

          o Service the request. The Web server will service the request. In our case we’ll be writing a new servlet to process the request.

          o Send the response. The server will send (or forward) a response to the client. The response contains a set of response headers that define the
          type and length of the response packet followed by the response data.

          o Close the connection. Remember that HTTP is state-less; connections cannot be preserved between requests.

You might think that HTTP (HyperText Transfer Protocol) is used just for requesting and downloading documents from a secure server over the Internet.
This is certainly the most common use of HTTP; however we can use it to serve other purposes as well such as method call tunneling.

What is tunneling

I like to think of tunneling as a way to use an existing road of communication (HTTP) and create a sub-protocol within it to perform specific tasks. The
sub-protocol that we’ll be creating will contain all of the information necessary to create an object on the Web server, invoke methods on that object, and
return results back to the client. The great thing about using HTTP tunneling is that you can concentrate on the specifics of the sub-protocol without
having to be concerned about transporting the data packets between the client and server - HTTP was designed for this very purpose and does it quite well.

The basic flow

To further illustrate this notion of tunneling let’s expand upon the basic HTTP flow:

          o Open the HTTP connection. Always remember that HTTP is a state-less protocol; because of this you will have to open a new connection
          for each request.

          o Format the method request. This will include some type of method indicator that describes which method to invoke and any parameters that
          are required by the method.

          o Set the HTTP request headers. This includes the type of data being sent (binary) and the total length of the data.

          o Send the request. Write the binary stream to the server

          o Read the request. The target servlet will be invoked and given the HTTP request data. The servlet can then extract the method to invoke and
          any necessary parameters. Note that if this is the first request for a given client that a new instance of the server object will be created.

          o Invoke the method. The method will be called on the server object.

          o Format the method response. If the method that was invoked throws an exception the error message will be sent to the client; otherwise the
          return type (if any) will be sent.

          o Set the HTTP response headers. Just like the request headers the type and length of the data being sent must be set.

          o Send the request. The binary data stream will be sent to the Web server which, in turn, will be returned back to the client.

          o Close the connection

There’s a lot of work going on just to send a single request. For performance reasons you should always try to pass as much information as possible with
each request/response; the weak link in the HTTP tunneling chain is creating a new connection for each request.

Tunneling for Java 1.0.2

A lot of focus has been placed on the current versions of the Java Developer’s Kit (JDK), whether it be JDK 1.1 or JDK 1.2 (or later). Don’t forget about
the first official release of the JDK: version 1.0.2. You might not think that it is important to use this version for much of anything, but I have found that
later versions of the JDK are not totally supported in some browsers or that the behavior is (at best) unpredictable. Applets created with JDK 1.0.2, on the
other hand, seem quite well behaved in all of the Java-enabled browsers that I have tried. Sure, there’s a lot of new functionality in the later versions of the
JDK but if you have some somewhat basic applet requirements that can be satisfied using version 1.0.2 you may want to consider using it; especially if you
will be distributing your applet over the Internet (as opposed to an Intranet) where you do not have control over the type or version of browser is in use.

Marshaling parameters and return values

Just exactly what is marshaling you might ask? Quite simply it is the process of packaging a piece of data for transmission and unpackaging it after it has
been received. Later in this chapter you will discover that starting with JDK 1.1 this is made very easy with serialization; not so with JDK 1.0.2. Java 1.0.2
provides us with a mechanism to read and write all of the basic scalar data types (boolean, char, byte, short, int, long, float, double, and String); all other
types of data must be marshaled as a combination of these types. Also, when you write a particular type of data the reader must know what type of data to
expect. You can get around this by preceding each piece of data with some type of indicator, but there is no generic way to determine what type of data is
present.

Using DataOutputStream and DataInputStream

To illustrate how to marshal data with any version of the JDK, let’s take a look at a simple client application that that uses java.io.DataOutputStream for
writing the request data and java.io.DataInputStream for reading the response data. The flow of our client application is as follows:

          o Open an HTTP connection.

          o Format the request data.

          o Send the request to the server.

          o Read the response data.

          o Close the HTTP connection.

The server (which we’ll look at a little bit later) will simply read the request data and echo it back to the client.

Figure 10-1 shows the complete application. To invoke the application you must supply the URL of the server process that will echo the data (a servlet, of
course!):

          java javaservlets.tunnel.TestDataStream

          http://larryboy/servlet/javaservlets.tunnel.DataStreamEcho

Note that the command has been split over multiple lines to improve readability; it should be entered as a single line. We will be using the ‘larryboy’ server
to invoke the DataStreamEcho servlet found in the javaservlets.tunnel package. You may have to configure your Web server and specify a servlet alias for
the DataStreamEcho servlet; I’m using JRun from Live Software which allows me to specify the full package name of the servlet without pre-registering.

Notice how the request data is actually being written to an in-memory buffer (java.io.ByteArrayOutputStream). We could have written the data directly to
the HTTP output stream but then you could not set the request length in the request header properly. To be able to do this we write all of the data to a
buffer and then retrieve the raw byte array which we can then get the length from. After the request headers are set we can get the HTTP output stream
from the URLConnection object and write out the entire contents of the internal buffer. Once the data has been sent we can request an input stream from
the URLConnection object which will be used to read the response. Note that requesting the input stream will block execution on the thread until the
response is received. Once we have the input stream we can simply read the data and display what was echoed by the servlet. Figure 10-2 shows the output
from our application.

What about the servlet? From looking at the client you should be able to write the servlet quite easily, since the process is very similar:

          o Wait for a service request from a client

          o Read the request data

          o Write the response using the data read from the request

Figure 10-3 shows the source code for the DataStreamEcho servlet. It is very important to remember to read the data in the same order that it was written
by the client.

The base tunnel client class

Now that you know how to get data back and forth between the client and server, let’s get started on some supporting classes to make method tunneling
much easier. Since I had the distinct advantage of looking ahead in this chapter I know that we are going to write two types of clients: a lite version (for
marshaling scalar types only) and a full version (using Java serialization). Because of this I think it would be an excellent idea to implement an abstract base
class that these two types of clients can extend.

What types of methods will the client need? All clients will definitely need to initialize themselves. Since we are invoking methods on the server, part of this
initialization step should be to instantiate the server-side object. Figure 10-4 shows the initialization method from the base client class.

All this method does is send a message packet to the server instructing it to instantiate a new server-side object (we’ll get to that later). It’s important to
note the basic steps involved in sending our packet of data to the server:

          o Create a new in-memory buffer to hold the contents of the data stream.

          o Invoke a helper method to create the packet header. We’re going to invoke remote methods by assigning each method an ordinal (a number)
          that will uniquely identify a particular method. The ordinal -1 is reserved to indicate that the request is not to invoke a method but rather to
          initialize the server.

          o Invoke a helper method to send the request packet to the server. This method will return an input stream that we can then use to read any
          return values from the server.

If you think back to the TestDataOutput sample application presented earlier this should all sound quite familiar.

Figure 10-5 shows the code necessary to create the packet header that will be used on every tunneled method request.

Not a lot of magic going on here; just opening an output stream, writing the method ordinal, and flushing the data to the output stream. But wait! What are
these _getOutputStream and _flush methods? Each client that extends the base client will have to implement these abstract methods to create the proper
type of output stream and to flush the data if necessary. By defining these methods as abstract we can write a very generic base class that can be reused for
different types of tunnel clients.

The last method we need to look at from the base class is the one that actually sends the packet to the server (see Figure 10-6).

The first thing that is done is to connect to a given URL. The URL is set when the tunnel client is instantiated (which we’ll see later). Part of connecting to
a particular URL is initializing the connection settings. Of note here is the setUseCaches method which tells the browser whether to use internal caching
for information or to always read directly from the connection itself. In our case we will turn off all browser caching capabilities. Next we’ll set the request
headers (the data type and data length) and write the data buffer to the server. After the request is sent we will block until a response is available. Notice
the _getInputStream method that will return the type of input stream being used by the client; it is an abstract method that must be implemented by each
tunnel client. Once the response has arrived we can read the response header which will always be prefixed with the same method ordinal that was sent in
the request header. A returning ordinal value of -2 indicates that an exception was encountered during the execution of the remote method. If this is the
case we can read the exception message from the input stream and throw a new exception to the client. If all goes well we can return the input stream back
to the caller so that it can read any additional data that was sent by the server.

The tunnel ‘lite’ client

Writing the client implementation for our ‘lite’ tunnel client is very straight forward (see Figure 10-7). Remember that our definition of a lite client is one
that uses DataInputStream and DataOutputStream to marshal data. This type of client can be used with any version of the JDK.

The base tunnel servlet class

In the same manner that we created an abstract base client class, let’s create a base servlet class as well. Just like the client, it will contain abstract methods
to create input and output streams specific to the type of marshaling being used. Figure 10-8 shows the service method of the base servlet class.

The basic flow of the service method is:

          o Create an input stream to read the request from the client. The server implementation that extends the base servlet will create the proper
          type of input stream.

          o Get the instance of the server side object from the session.

          o Setup the response header.

          o Create an in-memory buffer to hold the raw data of the response. We need to set the length of the response in the response header, so we’ll
          cache the response data in an internal buffer and then get the length.

          o Read the method ordinal indicating which method to invoke on the server object. An ordinal of -1 directs us to initialize the server by
          instantiating a new server object and placing it in the session object.

          o Invoke the method. The server implementation will evaluate the method ordinal, read any parameters, and invoke the proper method. Once
          the method has been invoked the server implementation will write any return value to the output stream so that it can be forwarded to the
          client.

          o Send the response buffer to the client.

The tunnel ‘lite’ server

Writing the server implementation for our ‘lite’ tunnel server (shown in Figure 10-9) is very similar to the ‘lite’ client.

Note that we are using DataInputStream and DataOutputStream just like the client.

Tunneling example: RemoteMathLite

To bring all of these pieces together let’s write a very simple applet that will perform some simple math operations (add, subtract, multiply). Big deal, right?
The exciting aspect of this applet is that all of the calculations will be performed on the server via HTTP tunneling.

Writing the server interface

I always like to begin by defining an interface that describes the methods available on a particular server object. While this is not necessary for what we are
doing now it will be critically important in Chapter 11 when we start automating the creation remote objects. If you have worked with CORBA you are
already used to writing the IDL (Interface Definition Language) necessary to generate CORBA proxies and stubs; in essence we will be doing the same
thing.

Figure 10-10 shows the interface definition for our Math object.

As you can see we have three methods: add, subtract, and multiply.

Writing the server object

Implementing the three math methods is, as you would expect, no difficult task (see Figure 10-11). Note that there is nothing special about implementing
the server object even though we will be using it via HTTP tunneling.

Writing the client proxy

We now have to implement the client proxy. A proxy is defined by Webster as "the agency, function, or power of a person authorized to act as the deputy
or substitute for another". What we are interested in is creating a proxy to take the place of the real Math object and instead tunnel any method calls to the
server where they will be processed. Our client Math proxy (RemoteMathLiteClient) will extend our ‘lite’ client class and implement the Math interface
that we defined earlier. We then have to implement each method in the interface and, using methods in the base class, write any parameters to the output
stream that will be sent to the server. After invoking the remote method an input stream will be returned that we can use to read any return values from the
method call. This is shown in Figure 10-12.

Note that the initialize routine specifies the name of the servlet to invoke; we’ll be creating this next. Also, I’ve only shown the code for the add method;
subtract and multiply are identical other than the method ordinal that is used.

Writing the server stub

The server stub will extend the base ‘lite’ server and implement the _getNewInstance and _invokeMethod routines. Though it may not look like it the stub
is actually the servlet that will be invoked; all of the servlet details have already been implemented in the base class that the stub extends. The
_getNewInstance method will return an instance of the server object that will be persisted with the HTTP session object in the Web server. In our case this
is the Math object with the implementation for all of the math routines (add, subtract, multiply).

The _invokeMethod method will be given an instance of the server object (retrieved from the HTTP session), the method ordinal of the method to invoke
on the server object, an input stream to read parameters from, and an output stream which will be used to write return values. The complete code is shown
in Figure 10-13.

Writing the applet

To test this ‘lite’ remote object I’ll be using JDK 1.0.2 to prove that it works as described. Because of this our MathLiteApplet will use the ‘handleEvent’
applet method instead of the JDK 1.1 event model. Don’t worry, we’ll be writing an applet using the event model later in this chapter. Since this is not a
book on applet programming (there are plenty of those around) I won’t spend too much time diving into the particulars of applet development. The critical
piece of this applet is how to create our remote object. In essence all we need to do is create an instance of our client proxy and cast it to the Math
interface that we have defined. This is another great benefit of using interfaces; you can invoke the remote object by making calls on the interface without
having to know (or care) that it is indeed a remote object. This makes remote object programming much easier because there is no special syntax to learn;
just make method calls on an object - the client proxy is hiding all of the work.

Figure 10-14 shows the complete code for the applet. Again, note how the client proxy is instantiated and how making remote method calls is done with a
simple call on the interface.

See it in action

After adding the RemoteMathLiteServer servlet to the Web server (via an alias) and writing a simple HTML page to load our applet (shown in Figure
10-15), it’s time to give it a test drive. Don’t forget to place the applet and all supporting classes on your Web server’s class path so that the client browser
can locate them (or jump ahead to Chapter 12 to find out how to automatically create an archive file for distributing the applet). After entering values and
selecting an operator type, pressing the ‘Calculate’ button will tunnel a method call to the servlet which will then invoke the proper method on the
server-side object. The return value is then read from the server and placed in the result field (see Figure 10-16).

New for Java 1.1: Serialization

Starting with JDK 1.1 we have a new option for marshaling data between a client and server: serialization. Serialization is the process of storing (serializing)
and retrieving (deserializing) the internal state of an object without having to be aware of the internal structure of that object. In other words the Java
virtual machine handles writing all of the properties of an object and can, given this stored information, re-create the object at a later time and place.
JavaSoft added serialization to the JDK to enable RMI (Remote Method Invocation) to pass objects between a client and server; we’ll take this built-in
functionality and put it to use in a new version of our tunneling client and server.

Before going too far there are a few pitfalls when using serialization:

          o Not all objects are serializable. An object must implement the java.io.Serializable interface in order to be serializable. Remember that the
          whole purpose of serialization is to save the state of an object so that it can be re-created later; for some types of objects this does not make
          sense (such as database connections, open file handles, etc).

          o Serialization will add a significant amount of overhead to the size of a request/response packet. Serializing an object not only writes the
          properties but it also generates versioning and class file information. This may not be a big concern for you, but this additional data may have a
          small impact on performance.

          o Serialization errors can occur if the version of the object that was serialized differs than the one present when the object is deserialized. An
          example of this is a new copy of an object on the client and an older (or missing) version of the object on the server.

          o Some browsers (especially older versions) may not fully support serialization. Remember that serialization is a JDK 1.1 feature; but even if a
          browser claims to support 1.1 it may not properly support serialization.

Using ObjectOutputStream and ObjectInputStream

To illustrate how to marshal data with version 1.1 (or later) of the JDK, let’s take a look at a simple client application that that uses
java.io.ObjectOutputStream for writing the request data and java.io.ObjectInputStream for reading the response data. This application is b
0
 
LVL 4

Expert Comment

by:evijay
ID: 1221832
Sorry for break in data. here is rest


asically the same
as the TestDataStream application we saw earlier. To recap, the flow of our client application is as follows:

          o Open an HTTP connection.

          o Format the request data.

          o Send the request to the server.

          o Read the response data.

          o Close the HTTP connection.

The server will simply read the request data and echo it back to the client.

Figure 10-17 shows the complete client application. To invoke the application you must supply the URL of the servlet that will echo the data:

          java javaservlets.tunnel.TestObjectStream

          http://larryboy/servlet/javaservlets.tunnel.ObjectStreamEcho

Note that the command has been split over multiple lines to improve readability; it should be entered as a single line. We will be using the ‘larryboy’ server
to invoke the ObjectStreamEcho servlet found in the javaservlets.tunnel package. The output from the application is shown in Figure 10-18.

Just like the TestDataStream application the data is being written to an in-memory buffer. Notice how we are using the generic ‘writeObject’ method found
in the ObjectInputStream class. The following description is given in the JDK documentation for ‘writeObject’:

          "Write the specified object to the ObjectOutputStream. The class of the object, the signature of the class, and the values of the non-transient
          and non-static fields of the class and all of its supertypes are written. Default serialization for a class can be overridden using the writeObject
          and the readObject methods. Objects referenced by this object are written transitively so that a complete equivalent graph of objects can be
          reconstructed by an ObjectInputStream."

What this means is that ‘writeObject’ causes the object to be serialized to the underlying output stream which then must be deserialized using the
‘readObject’ method of the ObjectInputStream class. The object should be read in the same order that they were written. However, serialization has one
distinct advantage over the simple marshaling that we have seen earlier; you can read a generic object and reflect upon the object to determine what type it
is (such as using the instanceof comparison operator).

The servlet used to read the response and echo the data is very similar to what we have seen before. Instead of using data input and output streams we’ll be
using object input and output streams. Figure 10-19 shows the source code for the ObjectStreamEcho servlet.

A tunnel client class for serialization

Writing the client implementation for our tunnel client that uses serialization is also very straight forward (see Figure 10-20). The only real difference
between this tunnel client and our ‘lite’ client that we developed earlier is the type of input and output streams that will be used. The base tunnel client does
not need to change since you had the foresight to separate the creation of the input and output streams from the base code (great job!).

A tunnel server class for serialization

As you might expect the implementation for the tunnel server that uses serialization is the same as the ‘lite’ version except that object input and output
streams are used (see Figure 10-21).

Tunneling example: RemoteIndy

To further illustrate the use of Java serialization let’s develop a simple applet that will use HTTP tunneling to make method calls to a server-side object that
will retrieve data from a database. The database contains a row for each year that the Indianapolis 500 was run; each row contains the year, the name of the
winning driver, and the average speed of the winning car.

Writing the server interface

Let’s start by writing an interface that describes the services available for our server-side object. By services I mean the methods, parameter types, and
return types of the server object. Our server object will provide the following services:

          o Initialize. Calling the initialize method will cause a database connection to be established and ready the object for use.

          o Query. The query method will accept a single parameter which will be used to form a SQL WHERE clause to select data out of the database.
          An object containing the selected data will be returned to the caller.

          o Close. Calling the close method will close the database connection and perform any necessary clean-up in the server object.

Figure 10-22 shows the code listing for the Indy interface. Notice that the query method returns an IndyRecord object. This object (shown in Figure
10-23) contains a public attribute for each column in the database. Notice that it implements java.io.Serializable; by doing so Java can properly serialize
and deserialize the object.

Note that to be a Java Beans compliant the IndyRecord class should really contain a ‘get’ and ‘set’ method for each of the properties; I have chosen to just
make the properties public so you can get the values directly.

Writing the server object

The beauty of writing the server object is that you do not need to know (or care) that the object will be used by HTTP tunneling; all we need to be
concerned about is implementing the interface. Figure 10-24 shows the implementation for the Indy object.

Notice that the initialize method is creating a database connection using the JDBC-ODBC Bridge and an Access database. Also, a JDBC
PreparedStatement object is being created as well. Preparing an SQL statement is a great way to boost performance for queries that you will be using
multiple times. In our case we’ll be re-executing the same query over and over with a different year value (this is done in the query method).

Note also how the data is being gathered from the result of the select statement in the query method. You should always retrieve column data in order and
each column should only be retrieved once; some JDBC drivers are rather strict in enforcing this requirement, especially the Bridge (due to the way ODBC
functions).

The close method simple ensures that the database connection is properly terminated. Make sure that you always close the database so that you don’t have
any unwanted memory leaks or wasted resources on the server.

Writing the client proxy

The client proxy is responsible for marshaling method and parameter data to the server and reading the return value from the response stream. Remember
that we’ve already done a lot of work in the base client object, so the client proxy is quite simple (see Figure 10-25). The constructor takes the base servlet
URL (such as http://larryboy/servlet/) and causes a new server-side object to be instantiated. The rest of the client proxy implementation is very repetitive;
because of this I’ve only included the query method.

Note that the method ordinal is unique within the method and is used to create the method header and how the object input and output streams are used to
marshal data back and forth to the server.

Writing the server stub

The server stub (which is also the servlet that will be invoked) implements the _getNewInstance and _invokeMethod routines. The _getNewInstance
method will return an instance of the Indy object that will be persisted with the HTTP session object in the Web server.

The _invokeMethod method will be given an instance of the server object (retrieved from the HTTP session), the method ordinal of the method to invoke
on the server object, an input stream to read parameters from, and an output stream which will be used to write return values. The RemoteIndyServer code
is shown in Figure 10-26.

Writing the applet

Now it’s time to put our remote object to use by writing a simple applet that uses the client proxy. Most of the work involved is in formatting the display;
calling methods on the remote object is nothing more than instantiating a new client proxy and making Java method calls on the Indy interface. Figure
10-27 shows the code for the Indy applet.

Note that the applet implements the ActionListener interface; doing so will force us to implement the actionPerformed method. After registering the applet
as a action listener for the button (addActionListener) the actionPerformed method will be called whenever the button is pressed. We can then perform
our query which will return the results from the database.

See it in action

After adding the RemoteIndyServer servlet to the Web server (via an alias) and writing a simple HTML page to load our applet (shown in Figure 10-28),
it’s time to give it a test drive. Don’t forget to place the applet and all supporting classes on your Web server’s class path so that the client browser can
locate them (or check out Chapter 12 to find out how to automatically create an archive file for distributing the applet). After entering the year, pressing
the ‘Query’ button will tunnel a method call to the servlet and display the results (see Figure 10-29).

Summary

In this chapter we’ve covered how to make remote method calls using HTTP tunneling. We’ve seen how to marshal data generically for all versions of the
JDK (which we called ‘lite’ version) as well as how to marshal data specifically for JDK 1.1 and higher. Along the way a base class was developed for both
the client and server which made writing client proxies and server stubs much easier. We also wrote applets to exercise the remote objects that were
developed; these applets can be deployed over the Internet very easily.

In the next chapter we’ll make developing remote objects painless by automating the process. You may have noticed that writing client proxies and server
stubs was somewhat repetitive; we’ll be developing an application that will automatically generate the source code for these classes by using Java reflection
to discover the methods, parameters, and return types of the server object.
0
 

Expert Comment

by:YSaadat
ID: 2791907
I got 'page not found' when I tried to follow the link http://www.pbg.mcgraw-hill.com/betabooks/moss/chap10.html .So, Figure xx could not be consulted.Can you give the current URL of that book?
In http/1.1 ,the concept of persistent connection comes, how to implement that?
Thanks for good explanation on tunneling.
Saadat
0

Featured Post

How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

Join & Write a Comment

For customizing the look of your lightweight component and making it look lucid like it was made of glass. Or: how to make your component more Apple-ish ;) This tip assumes your component to be of rectangular shape and completely opaque. (COD…
Go is an acronym of golang, is a programming language developed Google in 2007. Go is a new language that is mostly in the C family, with significant input from Pascal/Modula/Oberon family. Hence Go arisen as low-level language with fast compilation…
Viewers will learn one way to get user input in Java. Introduce the Scanner object: Declare the variable that stores the user input: An example prompting the user for input: Methods you need to invoke in order to properly get  user input:
This tutorial covers a practical example of lazy loading technique and early loading technique in a Singleton Design Pattern.

760 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

23 Experts available now in Live!

Get 1:1 Help Now