Java TCP/IP socket programming (16)

Source: Internet
Author: User
Chapter 5 NiO
5.1 why do we need NiO

Synchronous access to the shared state in a multi-threaded environment increases the overhead of System Scheduling and context switching, which cannot be controlled by programmers.

Blocking wait.

We need a set of clients that can be polling at a time to find the clients that need services. In NiO, a channel represents an I/O target that can be polling, and the channel can register a selector instance. Selector's SELECT statement can be used to find "which channel needs to serve the current channel ".

Buffer provides more efficient and predictable I/O than stream abstraction. The good aspect of stream abstraction is that it hides the limitations of the underlying buffer and provides the illusion of a container that can accommodate any length of data, or it will produce a large amount of memory overhead, or a large number of context switches will be introduced. In the process of using a thread, these overhead are hidden in the specific implementation, and their controllability and predictability are also lost. This method makes programming easier, but it is difficult to adjust their performance. Unfortunately, using the socket abstraction of Java makes the stream the only choice.

Buffer abstraction represents a limited data container, which is essentially an array with pointers indicating where data is stored and where data is read. Buffer has two advantages: first, the system overhead associated with read/write buffer data is exposed to programmers, second, some special buffer ing for Java objects can directly operate on underlying platform resources, which saves the overhead of copying data in different address spaces.

5.2 Use channel with buffer

The channel uses a buffer instead of a stream to send or read data. The buffer class or any of its subclass instances can be considered as a sequence of elements of a fixed-length Java basic data type. Different from the stream, the buffer zone is composed of a fixed and limited capacity, and the internal status records the amount of data to put in or out, just like a queue with a limited capacity. The buffer used in the channel is generally created by calling the allocate () method instead of the constructor:

Bytebuffer buffer = bytebuffer. Allocate (capacity)

Or you can use a package of existing data to achieve this.

Bytebuffer buffer = bytebuffer. Wrap (bytearray)

NIO's strength comes from the non-blocking feature of channel.

The following is a non-blocking client with a character echo

Package COM. suifeng. tcpip. chapter5; import Java. io. ioexception; import java.net. inetsocketaddress; import java.net. socketexception; import Java. NIO. bytebuffer; import Java. NIO. channels. socketchannel;/*** non-blocking client ** @ author suifeng **/public class tcpechoclientnonblocking {public static void main (string [] ARGs) throws ioexception {If (ARGs. length <2 | args. length> 3) {Throw new illegalargumentexception ("Parameters: <Server> <word> [<port>]");} string Server = ARGs [0]; byte [] MSG = ARGs [1]. getbytes (); int SERVERPORT = (ARGs. length = 3 )? Integer. parseint (ARGs [2]): 7; socketchannel channel = socketchannel. open (); // set the channel to non-blocking channel. configureblocking (false); If (! Channel. connect (New inetsocketaddress (server, SERVERPORT) {system. out. print ("Trying Connected Server"); // poll the connection status and know how to establish a connection. This is a waste of resources, while (! Channel. finishconnect () {system. out. print (". ") ;}} system. out. println ("\ nclient has connected to server successfully"); // write buffer bytebuffer writebuffer = bytebuffer. wrap (MSG); // read buffer bytebuffer readbuffer = bytebuffer. allocate (MSG. length); int totalbytesreceived = 0; int bytesreceived =-1; system. out. print ("waiting for server response"); While (totalbytesreceived <MSG. length) {// send data if (writebuffer. hasremaining () {channel. write (writebuffer);} // wait for the server to return data if (bytesreceived = channel. read (readbuffer) =-1) {Throw new socketexception ("Connection closed prematurely");} totalbytesreceived + = bytesreceived; system. out. print (". ");} system. out. println (""); system. out. println ("Received:" + new string (readbuffer. array (), 0, totalbytesreceived); channel. close ();}}

Start the server and listen to port 39393

Start the client

View the server again

5.3 Selector

A selector instance can check the I/O status of a group of channels.

The following uses the channel and selector to implement a echo server, and does not apply to multithreading and busy.

Protocol Interface

Package COM. suifeng. tcpip. chapter5; import Java. io. ioexception; import Java. NIO. channels. selectionkey; /*** echo server protocol interface * @ author suifeng **/public interface tcpprotocol {/*** receive Request * @ Param key * @ throws ioexception */void handleaccept (selectionkey key) throws ioexception;/*** read data * @ Param key * @ throws ioexception */void handleread (selectionkey key) throws ioexception; /*** receive data ** @ Param key * @ throws ioexception */void handlewrite (selectionkey key) throws ioexception ;}

Implementation of ECHO Protocol

Package COM. suifeng. tcpip. chapter5; import Java. io. ioexception; import Java. NIO. bytebuffer; import Java. NIO. channels. selectionkey; import Java. NIO. channels. serversocketchannel; import Java. NIO. channels. socketchannel;/*** echo Protocol implemented using selector and channel * @ author administrator **/public class echoselectorprotocol implements tcpprotocol {private int buffersize; Public echoselectorprotocol (INT buffersize) {super (); this. bu Ffersize = buffersize;} @ overridepublic void handleaccept (selectionkey key) throws ioexception {system. out. println ("handle accepting now... "); socketchannel channel = (serversocketchannel) Key. channel ()). accept (); // set to blocking channel. configureblocking (false); // channel readable channel. register (key. selector (), selectionkey. op_read, bytebuffer. allocate (buffersize);} @ overridepublic void handleread (selectionkey key) Throws ioexception {system. out. println ("handle reading now... "); socketchannel channel = (socketchannel) Key. channel (); bytebuffer Buf = (bytebuffer) Key. attachment (); long bytesread = channel. read (BUF); system. out. println ("inserting ing from client:" + channel. socket (). getremotesocketaddress () + "\ nreceived:" + new string (BUF. array (); If (bytesread =-1) {channel. close ();} else if (bytesread> 0) {// channel readable, writable key. Interestops (selectionkey. op_write | selectionkey. op_read) ;}@ overridepublic void handlewrite (selectionkey key) throws ioexception {system. out. println ("handling writing now .... "); bytebuffer Buf = (bytebuffer) Key. attachment (); Buf. flip (); socketchannel channel = (socketchannel) Key. channel (); // write the data channel to the client. write (BUF); If (! Buf. hasremaining () {// channel readable key. interestops (selectionkey. op_read) ;}buf. Compact ();}}

Server

Package COM. suifeng. tcpip. chapter5; import Java. io. ioexception; import java.net. inetsocketaddress; import Java. NIO. channels. selectionkey; import Java. NIO. channels. selector; import Java. NIO. channels. serversocketchannel; import Java. util. iterator;/*** non-blocking processing server ** @ author suifeng **/public class tcpserverselector {Private Static final int buffer_size = 32; Private Static final int timeout = 3000; public static void main (string [] ARGs) throws ioexception {If (ARGs. length <1) {Throw new illegalargumentexception ("parameter (s): <port>... ");} // create selector instance selector = selector. open (); // you can listen to data from multiple channels at the same time and use different ports for (string Arg: ARGs) {// create a serversocketchannel serverchannel = serversocketchannel. open (); // listen to the specified port serverchannel. socket (). BIND (New inetsocketaddress (integer. parseint (ARG); // sets the channel as a non-blocking serverchannel. configureblocking (false); // This channel can perform the accept operation on the serverchannel. register (selector, selectionkey. op_accept);} tcpprotocol protocol = new echoselectorprotocol (buffer_size); system. out. println ("server is running. "); While (true) {// blocking wait until timeout if (selector. select (timeout) = 0) {system. out. println ("Waiting data from client. "); continue;} // gets the iterator <selectionkey> keys = selector under the selector. selectedkeys (). iterator (); While (keys. hasnext () {selectionkey key = keys. next (); If (key. isacceptable () // accept operation {protocol. handleaccept (key);} If (key. isreadable () // read {protocol. handleread (key);} If (key. isvalid () & Key. iswritable () // writable {protocol. handlewrite (key);} Keys. remove ();}}}}

Start the server and listen on ports 39393 and 39395

Start the client and send data at one time using port 39393 and port 39395

View the server again

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.