A quick way to achieve non-blocking communication using JSSE and NIO

xiaoxiao2021-03-06  95

From IBM Developer Works

Http://www-900.ibm.com/developerWorks/cn/java/j-sslnb/

Kenneth Ballard (Kenneth.ballard@ptk.org) Computer Science Student, Perst University November 2003

Although SSL blocking operation - When the access data is read, the access is blocked - provides a better I / O error notification compared to the corresponding non-blocking method, but the non-blocking operation allows the call to continue to operate. . In this article, the author describes how to create a non-blocking secure connection using Java Secure Socket Extensions (JSSE) and Java NIO (JSSE) and Java NIO (JSSE) and the Java Nio (JAVA NIO) and introduces the tradition of creating non-blocking sockets. Method, and an optional (required) method using JSSE and NIO.

Block, or non-blocking? This is where the problem lies. Whether it is more expensive in the programmer ... Of course, this is not Shakespeare, this article proposes an important issue that any programmer should consider when writing the Internet client. Is the communication operation be blocked or non-blocking?

Many programmers have not considered this problem when writing an Internet client using Java language, mainly because there is only one option - blocking communication. But now the Java programmers have a new option, so we should consider every customer program we have written.

Non-blocking communication is introduced into the Java language in the Java 2 SDK version 1.4. If you have used this version of the program, you may have an impression of the new I / O library (NIO). Before introducing it, Non-blocking communications can only be used when implementing a third-party library, and third libraries often introduce defects to applications.

The NIO library contains files, pipes, and non-blocking features of client and server socket. One of the lack of the library is a secure non-block socket connection. There is no secure non-blocking channel class in the NIO or JSSe library, but this does not mean that secure non-blocking communications cannot be used. Just happen a little.

To fully collapse this article, you need to be familiar:

Java socket communication concept. You should also be able to write applications. And not only open the connection, read a line and exiting the simple application, should be a program that implements a client or a communication library that implements the POP3 or HTTP protocol. SSL basic concepts and concepts of encryption. Basically, I know how to set a secure connection (but don't worry about JSSE - this is about its "emergency tutorial"). NiO library. Install Java 2 SDK 1.4 or later version on your selection platform. (I used 1.4.1_01 on Windows 98.)

If you need an introduction to these technologies, see the reference part.

So what is the blocked and non-blocking communication?

Blocking and non-blocking communication blocking communication means that the communication method blocks access to the socket when attempting to access the socket or read and write data. Before JDK 1.4, the method of bypassing the blocking limit is unlimited, but this often causes a large number of thread overhead, which affects the performance and scalability of the system. The Java.NIO package has changed this situation, allowing the server to effectively use the I / O stream to handle the served customer request within a reasonable time.

Without non-blocking communication, this process is like "for what you want". Basically, this process is to send and read anything that can send / read. If there is no thing you can read, it will stop reading, do other things until you can read. When data is sent, the process will attempt to send all data, but return the content that actually transmits. It may be all data, some data, or no data at all.

Blocking does have some advantages over non-blocking, especially when the error control problem is encountered. In blocking socket communication, if an error occurs, the access automatically returns the code of the flag error. The error may be due to the network timeout, the socket is closed or any type of I / O error is caused. In non-block socket communication, the only error that the method can handle is a network timeout. In order to detect a network timeout using non-blocking communication, you need to write a little bit of code to determine how long it has been in the last time it receives data. Which way is better dependent on the application. If you are using synchronous communication, if the data does not have to process before reading any data, blocking communication is better, not blocking communication, provides an opportunity to process any data that has been read. Asynchronous communications, such as IRC and chat clients require non-blocking communication to avoid freezing sockets.

Create a traditional non-blocking client set of Java NIO libraries use channels and not streaming. Channels can be used simultaneously to block and non-blocking communications, but create a default to non-blocking version. However, all non-blocking communications are completed by a class that contains Channel. The classes used in socket communication are SocketChannel, and the process of creating objects of this class is different from the process used by typical sockets, as shown in Listing 1.

Listing 1. Create and connect to the SocketChannel object

Socketchannel sc = socketchannel.open ();

Sc.Connect ("www.ibm.com", 80);

sc.finishconnect ();

A socketchannel type pointer must be declared, but you cannot create an object with a New operator. Instead, you must call a static method of the SocketChannel class to open the channel. Once the channel is turned on, you can connect it to it by calling the connect () method. But when the method returns, the socket is not necessarily connected. To ensure that the socket is already connected, FinishConnect () must then be called.

When the socket connection is connected, non-blocking communication can start using the READ () and Write () methods of the SocketChannel class. It is also possible to force the object to convert to a separate ReadableBytechannel and WritableBytechannel object. Either way, use the buffer object to the data. Because the use of the NIO library beyond the scope of this article, we no longer discuss this.

You can use the close () method to close it when you need a socket:

Sc.close ();

This will close the socket connection and the underlying communication channel.

Creating an alternative non-blocking client set The above method is slightly troublesome than the routine that is connected to the traditional creation socket. However, traditional routines can also be used to create non-blocking sockets, but there is a need to add several steps to support non-blocking communication.

The underlying communication in the SocketChannel object consists of two Channel classes: ReadableByTechannel and WritableBytechannel. These two classes can be created from the newchannel () method of the Channels class from the existing InputStream and OutputStream blocking stream, as shown in Listing 2:

Listing 2. Detecting channels from flow

ReadableBytechannel RBC = Channels.NewChannel (S.GetinputStream ());

WriteableBytechannel WBC = Channels.NewChannel (s.getOutputStream ());

The Channels class is also used to convert channels to flow or reader and write. This seems to switch communication to block mode, but not. If you try to read the stream derived from the channel, the reading method will throw an IllegalBlockingModeException.

The same is true for conversion in the opposite direction. You cannot use the Channels class to turn the stream into channels to count on non-blocking communication. If you try to read the channel from a stream, read is still blocked. But like many things in programming, this rule has exceptions. This exception is suitable for categories of the SelectableChannel abstract class. SelectableChannel and its derived class can choose to use blockage or non-blocking mode. SocketChannel is such a derived class.

However, in order to switch back and forth between the two, the interface must be implemented as a SelectableChannel. For sockets, in order to achieve this ability, SocketChannel must be used instead of socket.

Review, create a socket, first you must create a socket like usually using the Socket class. After the socket connection, the stream is converted into a channel using the two lines of code in Listing 2.

Listing 3. Another way to create a socket

Socket S = New Socket ("www.ibm.com", 80);

ReadableBytechannel RBC = Channels.NewChannel (S.GetinputStream ());

WriteableBytechannel WBC = Channels.NewChannel (s.getOutputStream ());

As mentioned earlier, this does not implement non-block socket communication - all communications are still in blocking mode. In this case, non-blocking communication must be simulated. How much code does not need to simulate the layer. Let's take a look.

From the analog layer read data simulation layer, check the availability of the data before trying to read the operation. If data is read, you will start reading. If there is no data available, it may be because the socket is turned off, then the code indicating this situation is returned. Be careful in Listing 4 still uses ReadableByteChannel read, although InputStream can perform this action. Why do you do this? In order to cause NIO instead of the simulated layer to perform an illusion of communication. In addition, the simulation layer can be easier to combine with other channels, such as writing data to the file channel.

Listing 4. A simulating non-blocking read operation

/ * The checkconnection method returns the character read by hen

DETERMININING IF A Connection IS Open.

* /

y = CheckConnection ();

IF (y <= 0) Return Y;

Buffer.putchar ((char) y);

Return Rbc.read (buffer);

Write data to the analog layer For non-blocking communication, the write operation is written only to write data. The size of the transmit buffer and the data that can be written can be written. The size of the buffer can be determined by calling the GetSendBuffersize () method of the socket object. This size must be taken into account when trying non-blocking write operation. If you try to write more data than buffer block, you must be removed from multiple non-blocking write operations. Too big single write operation may be blocked.

Listing 5. Simulated non-blocking write operation

INT X, Y = s.getsendBuffersize (), z = 0;

Int expectedwrite;

BYTE [] P = buffer.Array ();

Bytebuffer buf = bytebuffer.allocatedIRect (Y);

/ * If there isn't any data to write, return, Otherwise flush the stream * /

IF (buffer.remaining () == 0) Return 0;

Os.flush ()

For (x = 0; x

{

IF (p.length - x

{

BUF.PUT (P, x, p.length - x);

EXPECTEDWRITE = P.LENGTH - X;

}

Else

{

BUF.PUT (P, X, Y);

ExpectedWrite = Y;

}

/ * Check the status of the socket to make sure it's still Open * /

IF (! s.isconnected ()) BREAK;

/ * Write the data to the strean, flushing immediately instance * /

BUF.FLIP ();

z = wbc.write (buf); Os.Flush ();

IF (z

BUF.CLEAR ();

}

IF (x> p.Length) Return P.Length;

ELSE IF (x == 0) Return -1;

ELSE RETURN X Z;

Similar to the read operation, first check if the socket is still connected. However, if the data is written to the WritableBytebuffer object, as in Listing 5, the object will automatically check and throw the necessary anomalies when there is no connection. Before this action begins to write, the stream must be emptied immediately to ensure that there is a space to send data in the transmit buffer. All write operations must be done. The data sent to the block is the same as the size of the send buffer. Performing a clear operation ensures that the send buffer does not overflow and the write operation is blocked.

Because if the write operation can only be written, this process must also check the socket to ensure that it is still open after each data block is written. If the socket is turned off when the write data is written, the write operation must be aborted and the amount of data that can be sent before the socket is turned off.

BufferedOutputReader can be used to simulate non-blocking write operations. If you try to write data that exceed twice the length of the buffer, data directly written directly into the buffer system (buffer data). For example, if the length of the buffer is 256 bytes, it is necessary to write 529 bytes of data, and the object will clear the current buffer and send 512 bytes and save the remaining 17 bytes.

This is not what we expect for non-blocking. We want to write data into the same size buffer, and finally write all the data. If some data is buffered, the write operation will be blocked when all data is sent.

The simulation layer template can be placed in a class to make it easier and application integration. If you want to do this, I suggest that this class is derived from Bytechannel. This class can be forced to convert into a separate ReadableBytechannel and WritableBytechannel class.

Listing 6 gives an example of an analog layered template derived from Bytechannel. This class will always use this class represents the non-blocking operation performed by blocking the connection.

Listing 6. Template of the analog layers

Public Class Nbchannel Implements bytechannel

{

Socket S;

InputStream IS; OUTPUTSTREAM OS;

ReadableBytechannel RBC;

WritableBytechannel WBC;

Public nbchannel (socket socket);

Public int in (bytebuffer dest);

Public int Write (Bytebuffer SRC);

Public void close ();

protected int checkconnection ();

}

Creating a socket using an analog layer This is very simple to create a socket with a new simulated layer. As long as you create a socket object like usually, you can create an NBChannel object, such as Listing 7: Listing 7. Using analog layers

Socket S = New Socket ("www.ibm.com", 80);

Nbchannel socketchannel = new nbchannel (s);

ReadableBytechannel RBC = (ReadableBytechannel) SocketChannel;

WritableBytechannel WBC = (WritableBytechannel) SocketChannel

Creating a traditional non-blocking server socket server-side non-block socket and the client is not very different. A little trouble is just a socket that accepts the input connection. Sockets must be bound to the blocking mode by deriving a blocking server socket from the server socket channel. Listing 8 lists the steps that need to do.

Listing 8. Creating a non-blocking server socket (SocketChannel)

ServersocketChannel SSC = ServersocketChannel.Open ();

Serversocket ss = ssc.socket ();

SS.BIND (New InetSocketAddress (port);

Socketchannel sc = ssc.accept ();

Similar to the client suitcase, the server socket must also open instead of using a New operator or constructor. After opening, the server socket object must be derived to bind the socket channel to a port. Once the socket is bound, the server socket object can be discarded.

The channel uses the accept () method to receive the connection and transfer them to the socket channel. Once the arrival connection is received and transferred to the socket channel object, the communication can start with the read () and Write () methods.

Creating an alternative non-blocking server socket is actually alternative. Because the server socket must use the server socket object binding, why not completely bypass the server socket channel and use only the server socket object? However, the communication here does not use SocketChannel, and the simulation layer NBChannel is used.

Listing 9. Another way to establish server socket

Serversocket SS = New Serversocket (Port);

Socket s = ss.accept ();

Nbchannel socketchannel = new nbchannel (s);

ReadableBytechannel RBC = (ReadableBytechannel) SocketChannel;

WritableBytechannel WBC = (WritableBytechannel) SocketChannel

Creating an SSL connection Create an SSL connection, we have to visit the client and server side separately.

Creating a traditional way to create an SS L connection from the client involves using sockets and other things. I will not discuss how to create SSL connections in detail, but there is a very good tutorial, "Secure Your Sockets with JSSE" (see Resources), from which you can learn more information.

The default method for creating SSL socket is very simple, including only a few short steps:

Create a socket factory. Create a connection socket. Start shaking hands. Derived stream. Communication.

Listing 10 describes these steps:

Listing 10. Creating a secure client sleeve

SSLSocketFactory SSLFactory =

SSLSocketFactory.getDefault (); sslsocket ssl = (sslsocket) sslfactory.createsocket (Host, Port);

ssl.starthandshake ();

InputStream IS = SSL.GETINPUTSTREAM ();

Outputstream OS = ssl.getOutputStream ();

The default method does not include customer authentication, user certificates, and other specific connections that may be needed.

The traditional method of establishing an SSL server connection from the server side is slightly troublesome, you need to add some types of conversions. Because these exceeded the scope of this article, I will no longer introduce, but tell the default method for supporting the SSL server connection.

Creating a default SSL server socket also includes a few shortcomings:

Create a server socket factory. Create and bind the server socket. Accept the incoming connection. Start shaking hands. Derived stream. Communication.

Although it seems to be similar to the client's steps, pay attention to a lot of security options, such as customer verification.

Listing 11 Description These steps:

Listing 11. Creating a secure server socket

SSLSERVERSOCKETFAACTORY SSLSSF =

SSLServersocketFactory) SSLServersocketFactory.getDefault ();

SSLSERVERSOCKET SSLSS = (SSLSERVERSOCKET) SSLSSF.CREATESERVERSOCKET (Port);

SSLSocket SSLS = (SSLSocket) sslss.accept ();

Ssls.starthandshake ();

InputStream IS = SSLS.GETINPUTSTREAM ();

Outputstream OS = SSLS.GetOutputStream ();

Creating a secure non-blocking connection To achieve secure non-blocking connections, you also need to see from the client and server.

Non-blocking connection from the client to establish a secure to establish a secure:

Create and connect to the Socket object. Add the socket object to the analog layer. Communication through the simulation layer.

Listing 12 describes these steps:

Listing 12. Creating a secure client connection

/ * CREATE The factory, THE Secure Socket * /

SSLSocketFactory SSLFactory =

SSLSocketFactory) sslsocketfactory.getDefault ();

Sslsocket SSL = (SSLSocket) SSLFactory.createsSocket (Host, Port);

/ * Start the handshake. SHOULD BE DONE BEFORE DERIVING CHANNELS * /

ssl.starthandshake ();

/ * Put it into the emulation layer and create separate channels * /

Nbchannel Socketchannel = New Nbchannel (SSL);

ReadableBytechannel RBC = (ReadableBytechannel) SocketChannel;

WritableBytechannel WBC = (WritableBytechannel) SocketChannel

Non-blocking security connections can be achieved using the analog layers given previously. Because the security socket channel cannot be opened using the SocketChannel class, and the Java API has not completed the class, a simulation class is created. The simulation class can achieve non-blocking communication, whether using a safety socket connection or a non-secure socket connection. The steps listed include the default security settings. For more advanced security, such as user certificates and customer verification, the reference part provides an article that explains how to implement.

Setting the socket from the server side needs to be set slightly for the default security. But once the socket is received and routed, the setting must be exactly the same as the client setting, as shown in Listing 13:

Listing 13. Creating a secure non-block server socket

/ * CREATE The factory, THE SOCKET, AND PUT IT INTO LISTENING MODE * /

SSLSERVERSOCKETFAACTORY SSLSSF =

SSLServersocketFactory) SSLServersocketFactory.getDefault ();

SSLSERVERSOCKET SSLSS = (SSLSERVERSOCKET) SSLSSF.CREATESERVERSOCKET (Port);

SSLSocket SSLS = (SSLSocket) sslss.accept ();

/ * Start the handshake on the new socket * /

Ssls.starthandshake ();

/ * Put it into the emulation layer and create separate channels * /

Nbchannel Socketchannel = New Nbchannel (SSLS);

ReadableBytechannel RBC = (ReadableBytechannel) SocketChannel;

WritableBytechannel WBC = (WritableBytechannel) SocketChannel

Similarly, remember that these steps are used by default security settings.

Integrated secure and non-secure clients Connect Most Internet client applications, whether using Java languages ​​or other languages, you need to provide security and non-secure connections. The Java Secure Socket Extensions library makes this work very easy, I recently used this method when writing an HTTP customer library.

The SSLSocket class is derived from socket. You may have guessed what I have to do. The required only one socket pointer of the object. If the socket connection does not use SSL, you can create a socket as usual. If you want to use SSL, you will be a little bit a little, but the code after this is simple. Listing 14 gives an example:

Listing 14. Integrated security and non-secure client connections

Socket S;

ReadableBytechannel RBC;

WritableBytechannel WBC;

Nbchannel Socketchannel;

IF (! users) s = new socket (Host, Port);

Else

{

SSLSocketFactory SSLSF = SSLSocketFactory.getDefault ();

SSLSocket SSLS = (SSLSocket) SSLSocketFactory.createsSocket (Host, Port);

Ssls.starthandshake ();

S = SSLS;

}

SocketChannel = New nbchannel (s);

RBC = (ReadableBytechannel) SocketChannel;

WBC = (WritableBytechannel) SocketChannel; ...

s.close ();

After creating the channel, if the socket uses SSL, it is secure communication, otherwise it is ordinary communication. If SSL is used, the closing socket will cause the handshake.

One of this setting may use two separate classes. A class is responsible for processing all communication through a socket along a connection with a non-secure socket. A separate class should be responsible for creating a secure connection, including all the necessary settings for secure connection, whether or not it is default. Safety classes should be inserted directly into the communication class, which is only called when using a secure connection.

The simplest integrated method This paper is the simplest method I know to integrate JSSE and NIO into the same code to provide non-blocking security communication. Although there are other methods, it is necessary to prepare for programmers who implement this process to spend a lot of time and effort.

One possibility is to implement its own SSL layer on NIO using Java Cryptography Extensions. Another method is to modify the existing custom SSL layer called Espressl (previously referred to as JSSL), change it to the NIO library. I recommend that these two methods are only used when you have a bad time.

The downloadable ZIP files for the reference data provides sample code to help you practice the techniques described in this article, including:

The source code of the analog layer described in NbChannel, Listing 7. Connect to the VeriSign's Web site and download the sample HTTPS client. A simple non-blocking security server (Secure Daytime Server). Integrated security and non-secure clients.

转载请注明原文地址:https://www.9cbs.com/read-122478.html

New Post(0)