Files
redkale/src/org/redkale/net/ProtocolServer.java
Redkale 903c58b239
2016-10-10 20:28:04 +08:00

185 lines
6.2 KiB
Java

/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.net;
import java.io.IOException;
import java.net.*;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.*;
import java.util.concurrent.*;
/**
*
* <p> 详情见: https://redkale.org
* @author zhangjx
*/
public abstract class ProtocolServer {
public abstract void open() throws IOException;
public abstract void bind(SocketAddress local, int backlog) throws IOException;
public abstract <T> Set<SocketOption<?>> supportedOptions();
public abstract <T> void setOption(SocketOption<T> name, T value) throws IOException;
public abstract void accept();
public abstract void close() throws IOException;
public abstract AsynchronousChannelGroup getChannelGroup();
//---------------------------------------------------------------------
public static ProtocolServer create(String protocol, Context context) {
if ("TCP".equalsIgnoreCase(protocol)) return new ProtocolTCPServer(context);
if ("UDP".equalsIgnoreCase(protocol)) return new ProtocolUDPServer(context);
throw new RuntimeException("ProtocolServer not support protocol " + protocol);
}
private static final class ProtocolUDPServer extends ProtocolServer {
private boolean running;
private final Context context;
private DatagramChannel serverChannel;
public ProtocolUDPServer(Context context) {
this.context = context;
}
@Override
public void open() throws IOException {
DatagramChannel ch = DatagramChannel.open();
ch.configureBlocking(true);
this.serverChannel = ch;
}
@Override
public void bind(SocketAddress local, int backlog) throws IOException {
this.serverChannel.bind(local);
}
@Override
public <T> void setOption(SocketOption<T> name, T value) throws IOException {
this.serverChannel.setOption(name, value);
}
@Override
public <T> Set<SocketOption<?>> supportedOptions() {
return this.serverChannel.supportedOptions();
}
@Override
public void accept() {
final DatagramChannel serchannel = this.serverChannel;
final int readTimeoutSecond = this.context.readTimeoutSecond;
final int writeTimeoutSecond = this.context.writeTimeoutSecond;
final CountDownLatch cdl = new CountDownLatch(1);
this.running = true;
new Thread() {
@Override
public void run() {
cdl.countDown();
while (running) {
final ByteBuffer buffer = context.pollBuffer();
try {
SocketAddress address = serchannel.receive(buffer);
buffer.flip();
AsyncConnection conn = AsyncConnection.create(serchannel, address, false, readTimeoutSecond, writeTimeoutSecond);
context.submit(new PrepareRunner(context, conn, buffer));
} catch (Exception e) {
context.offerBuffer(buffer);
}
}
}
}.start();
try {
cdl.await();
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void close() throws IOException {
this.running = false;
this.serverChannel.close();
}
@Override
public AsynchronousChannelGroup getChannelGroup() {
return null;
}
}
private static final class ProtocolTCPServer extends ProtocolServer {
private final Context context;
private AsynchronousChannelGroup group;
private AsynchronousServerSocketChannel serverChannel;
public ProtocolTCPServer(Context context) {
this.context = context;
}
@Override
public void open() throws IOException {
group = AsynchronousChannelGroup.withCachedThreadPool(context.executor, 1);
this.serverChannel = AsynchronousServerSocketChannel.open(group);
}
@Override
public void bind(SocketAddress local, int backlog) throws IOException {
this.serverChannel.bind(local, backlog);
}
@Override
public <T> void setOption(SocketOption<T> name, T value) throws IOException {
this.serverChannel.setOption(name, value);
}
@Override
public <T> Set<SocketOption<?>> supportedOptions() {
return this.serverChannel.supportedOptions();
}
@Override
public void accept() {
final AsynchronousServerSocketChannel serchannel = this.serverChannel;
serchannel.accept(null, new CompletionHandler<AsynchronousSocketChannel, Void>() {
@Override
public void completed(final AsynchronousSocketChannel channel, Void attachment) {
serchannel.accept(null, this);
context.submit(new PrepareRunner(context, AsyncConnection.create(channel, null, context.readTimeoutSecond, context.writeTimeoutSecond), null));
}
@Override
public void failed(Throwable exc, Void attachment) {
serchannel.accept(null, this);
//if (exc != null) context.logger.log(Level.FINEST, AsynchronousServerSocketChannel.class.getSimpleName() + " accept erroneous", exc);
}
});
}
@Override
public void close() throws IOException {
this.serverChannel.close();
}
@Override
public AsynchronousChannelGroup getChannelGroup() {
return this.group;
}
}
}