nio server:
package nio.study.serverclient;
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;
public class EchoSelectorServer {
//cache size
private static final int BUFSIZE = 256;
//overtime time
private static final int TIMEOUT = 3000;
//port
private static final int PORT = 8888;
public static void main(String[] args) throws IOException {
Selector selector = Selector.open();
ServerSocketChannel listnChannel = ServerSocketChannel.open();
listnChannel.socket().bind(new InetSocketAddress(PORT));
// Only non-blocking channels can register selectors, so they need to be configured in the appropriate state
listnChannel.configureBlocking(false);
// Indicate that the channel can be "accepted" during the registration process
listnChannel.register(selector, SelectionKey.OP_ACCEPT);
Protocol protocol = new EchoProtocol(BUFSIZE);
while (true) {
if (selector.select(TIMEOUT) == 0) {
continue;
}
Iterator<SelectionKey> keyIter =
selector.selectedKeys().iterator();
while (keyIter.hasNext()) {
SelectionKey key = keyIter.next();
System.out.println("isAcceptable:"+key.isAcceptable());
if (key.isAcceptable()) {
protocol.handleAccept(key);
}
/*if(!key.isConnectable()){
System.out.println("cancel.......");
key.cancel();
}*/
System.out.println("isReadable: "+key.isReadable());
if (key.isReadable()) {
protocol.handleRead(key);
}
// System.out.println("isWritable: "+key.isWritable()
// +";isValid="+key.isValid());
try{
if (key.isWritable() && key.isValid()) {
protocol.handleWrite(key);
}
}catch(Exception e){
e.printStackTrace ();
key.cancel();
if(null != key.channel() && key.channel().isOpen()){
key.channel();
}
}
// Since the select() operation just adds elements to the set of keys associated with the Selector
// So without removing every processed key,
// it will remain in the collection the next time the select() method is called
// And there may be useless operations to call it.
keyIter.remove();
}
}
}
}
package nio.study.serverclient;
import java.io.IOException;
import java.nio.channels.SelectionKey;
public interface Protocol {
public void handleAccept(SelectionKey key) throws IOException;
public void handleRead(SelectionKey key) throws IOException;
public void handleWrite(SelectionKey key) throws IOException;
}
package nio.study.serverclient;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
public class EchoProtocol implements Protocol {
private int bufsize;// buffer size created for each client channel
public EchoProtocol(int bufsize) {
this.bufsize = bufsize;
}
public void handleAccept(SelectionKey key) throws IOException {
// The channel() method returns the Channel created during registration, which is a ServerSocketChannel,
// Because this is the only channel we've registered that supports the accept operation,
// The accept() method returns a SocketChannel instance for the incoming connection.
SocketChannel channel = ((ServerSocketChannel) key.channel()).accept();
// Blocking channels cannot be registered here, they must be non-blocking
channel.configureBlocking(false);
// The corresponding Selector can be obtained through the selector() method of the SelectionKey class.
// We create a new ByteBuffer instance with the specified size,
// and pass it as a parameter to the register() method. It will be attached as an attachment, as returned by the register() method
// Associated with the SelectionKey instance.
channel.register(key.selector(), SelectionKey.OP_READ, ByteBuffer
.allocateDirect(bufsize));
}
public void handleRead(SelectionKey key) throws IOException {
// According to its support for data read operations, this is a SocketChannel.
SocketChannel channel = (SocketChannel) key.channel();
// After the connection is established, a ByteBuffer attachment is added to the SelectionKey instance, and the content of this attachment will be
// Will be used when sending, attachments are always attached to this long connection
ByteBuffer buf = (ByteBuffer) key.attachment();
long bytesRead = channel.read(buf);
// System.out.println("data::"+ new
// String (buf.array (), 0, (int) bytesRead));
// If the read() method returns -1, it means that the underlying connection has been closed, and the channel needs to be closed at this time.
// When a channel is closed, the key associated with that channel is removed from the selector's various collections.
if (bytesRead == -1) {
channel.close();
} else if (bytesRead> 0) {
// Set the current limit of the buffer to position=0 for subsequent read operations on the buffer
buf.flip();
// Create a byte array based on the number of readable bytes in the buffer //buf.remaining() can read the length
byte[] bytes = new byte[buf.remaining()];
// Copy the buffer readable byte array to the newly created array
buf.get(bytes);
String expression = new String(bytes, "UTF-8");
System.out.println("Server received message: " + expression);
// Data processing
buf.clear();
// The readable operation of the channel is still preserved here, although there may be no space left in the buffer,
key.interestOps(SelectionKey.OP_WRITE);
}
}
public void handleWrite(SelectionKey key) throws IOException {
System.out.println("======write---");
// The ByteBuffer attached to the SelectionKey contains the data previously read from the channel.
// Read the client's data begin
//ByteBuffer buf = (ByteBuffer) key.attachment();
// This method is used to modify the internal state of the buffer to indicate where the write operation gets data from and how much data is left
// buf.flip();
//////// end
String back = "99999server1234567890123456789123456789=99999999999999999999=qwertyuioplkjhgfdsazxcvbnmend";
back =back+back+back;
// encode the message as a byte array
byte[] bytes = back.getBytes();
// Create ByteBuffer based on array capacity
ByteBuffer buf2 = ByteBuffer.allocate(bytes.length);
buf2.clear();
// copy byte array to buffer
buf2.put(bytes);
// flip operation, start writing from the 0 position of the buffer
buf2.flip();
System.out.println("======write---2");
System.out.println("write:" + new String(bytes));
SocketChannel channel = (SocketChannel) key.channel();// 获取信道
if(buf2.hasRemaining()){
int len =channel.write(buf2);//Write data to the channel
System.out.println("len:"+len);
}
if(null !=channel){
channel.close();
}
}
}
Client:
package nio.study.serverclient;
import java.net.InetSocketAddress;
import java.net.SocketException;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
public class TCPEchoClientNoblocking {
public void send(int i) throws Exception{
String server = "127.0.0.1";
String mgs = i+"1234567890qwertyuiopasdfghjklmnbvcxzqwertyuiopasdfghjklmnbvcxz";
byte[] data = mgs.getBytes();
int servPort = 8888;
SocketChannel clntChan =SocketChannel.open();
clntChan.configureBlocking(false);
//We "poll" the connection status by continuously calling the finishConnect() method before the connection is successfully established
// Always return false. The print operation shows that the program can perform other tasks while waiting for the connection to be established
if (!clntChan.connect(new InetSocketAddress(server,servPort))) {
while (!clntChan.finishConnect())
}
}
ByteBuffer writeBuf =ByteBuffer.wrap(data);
ByteBuffer readBuf =ByteBuffer.allocate(data.length);
int bytesRcvd = 0;
int topNum =0;
StringBuffer sb = new StringBuffer(64);
while (bytesRcvd >= topNum) {
if (writeBuf.hasRemaining()) {
clntChan.write(writeBuf);
}
topNum = bytesRcvd;
bytesRcvd = clntChan.read (readBuf);
//
readBuf.flip();
if(bytesRcvd >0){
sb.append(new String(readBuf.array(), 0,readBuf.limit()));
System.out.println("len;;;"+bytesRcvd +readBuf.hasRemaining());
}
readBuf.clear();
}
System.out.println("rev::"+sb.toString());
clntChan.close();
}
public static void main(String[] args) throws Exception {
for(int i=0;i<300;i++){
TCPEchoClientNoblocking t = new TCPEchoClientNoblocking();
t.send(i);
}
}
}
log:
Server:
isAcceptable:true
isReadable: false
isAcceptable: false
isReadable: true
Server received message: 295ABCDEFGHIJKLMNOPQRSTUVWXYZ789564559
isAcceptable: false
isReadable: false
======write---
======write---2
write:99999server1234567890123456789123456789=99999999999999999999=qwertyuioplkjhgfdsazxcvbnmend99999server1234567890123456789123456789=99999999999999999999=qwertyuioplkjhgfdsazxcvbnmend99999server1234567890123456789123456789=99999999999999999999=qwertyuioplkjhgfdsazxcvbnmend
len: 270
isAcceptable:true
isReadable: false
isAcceptable: false
isReadable: true
Server received message: 296ABCDEFGHIJKLMNOPQRSTUVWXYZ789564559
isAcceptable: false
isReadable: false
======write---
======write---2
write:99999server1234567890123456789123456789=99999999999999999999=qwertyuioplkjhgfdsazxcvbnmend99999server1234567890123456789123456789=99999999999999999999=qwertyuioplkjhgfdsazxcvbnmend99999server1234567890123456789123456789=99999999999999999999=qwertyuioplkjhgfdsazxcvbnmend
len: 270
Client:
len ;;; 38true
len ;;; 38true
len ;;; 38true
len ;;; 38true
len ;;; 38true
len ;;; 38true
len ;;; 38true
len ;;; 4true
rev::99999server1234567890123456789123456789=99999999999999999999=qwertyuioplkjhgfdsazxcvbnmend99999server1234567890123456789123456789=99999999999999999999=qwertyuioplkjhgfdsazxcvbnmend99999server1234567890123456789123456789=99999999999999999999=qwertyuioplkjhgfdsazxcvbnmend