java nio2 iocp_基于JDK7 NIO2的高性能web服务器实践之二

该博客探讨了如何使用Java NIO2在Windows环境下实现高性能的Web服务器,尤其是通过WindowsMultiAcceptSupport类增强并发连接数。文章详细介绍了如何利用JDK7的NIO2特性,包括AsynchronousServerSocketChannel和I/O完成端口(IOCP)来提升服务器的并发处理能力,并展示了相关代码实现。
摘要由CSDN通过智能技术生成

/****/packagesun.nio.ch;importjava.io.IOException;importjava.lang.reflect.Field;importjava.lang.reflect.Method;importjava.net.InetAddress;importjava.net.InetSocketAddress;importjava.nio.channels.AcceptPendingException;importjava.nio.channels.AsynchronousCloseException;importjava.nio.channels.AsynchronousServerSocketChannel;importjava.nio.channels.AsynchronousSocketChannel;importjava.nio.channels.ClosedChannelException;importjava.nio.channels.CompletionHandler;importjava.nio.channels.NotYetBoundException;importjava.nio.channels.ShutdownChannelGroupException;importjava.security.AccessControlContext;importjava.security.AccessController;importjava.security.PrivilegedAction;importjava.util.Queue;importjava.util.concurrent.ConcurrentLinkedQueue;importjava.util.concurrent.Future;importjava.util.concurrent.atomic.AtomicBoolean;importjava.util.concurrent.atomic.AtomicInteger;importsun.misc.Unsafe;/*** This class enable multiple 'AcceptEx' post on the completion port, hence improve the concurrent connection number.

*@authorYvon

**/publicclassWindowsMultiAcceptSupport {

WindowsAsynchronousServerSocketChannelImpl schannel;privatestaticfinalUnsafe unsafe=Unsafe.getUnsafe();//2 * (sizeof(SOCKET_ADDRESS) + 16)privatestaticfinalintONE_DATA_BUFFER_SIZE=88;privatelonghandle;privateIocp iocp;//typically there will be zero, or one I/O operations pending. In rare//cases there may be more. These rare cases arise when a sequence of accept//operations complete immediately and handled by the initiating thread.//The corresponding OVERLAPPED cannot be reused/released until the completion//event has been posted.privatePendingIoCache ioCache;privateQueuedataBuffers;//the data buffer to receive the local/remote socket address//private final long dataBuffer;privateAtomicInteger pendingAccept;privateintmaxPending;

Method updateAcceptContextM;

Method acceptM;

WindowsMultiAcceptSupport() {//dummy for JNI code.}publicvoidclose()throwsIOException {

schannel.close();for(inti=0; i

}

}/****/publicWindowsMultiAcceptSupport(AsynchronousServerSocketChannel ch,intmaxPost) {if(maxPost<=0||maxPost>1024)thrownewIllegalStateException("maxPost can't less than 1 and greater than 1024");this.schannel=(WindowsAsynchronousServerSocketChannelImpl) ch;

maxPending=maxPost;

dataBuffers=newConcurrentLinkedQueue();for(inti=0; i

dataBuffers.add(unsafe.allocateMemory(ONE_DATA_BUFFER_SIZE));

}

pendingAccept=newAtomicInteger(0);try{

Field f=WindowsAsynchronousServerSocketChannelImpl.class.getDeclaredField("handle");

f.setAccessible(true);

handle=f.getLong(schannel);

f=WindowsAsynchronousServerSocketChannelImpl.class.getDeclaredField("iocp");

f.setAccessible(true);

iocp=(Iocp) f.get(schannel);

f=WindowsAsynchronousServerSocketChannelImpl.class.getDeclaredField("ioCache");

f.setAccessible(true);

ioCache=(PendingIoCache) f.get(schannel);

f=WindowsAsynchronousServerSocketChannelImpl.class.getDeclaredField("accepting");

f.setAccessible(true);

AtomicBoolean accepting=(AtomicBoolean) f.get(schannel);

accepting.set(true);//disable accepting by origin channel.}catch(Exception e) {

e.printStackTrace();

}

}

@SuppressWarnings("unchecked")publicfinalvoidaccept(A attachment,

CompletionHandlerhandler) {if(handler==null)thrownewNullPointerException("'handler' is null");

implAccept(attachment, (CompletionHandler) handler);

}/*** Task to initiate accept operation and to handle result.*/privateclassAcceptTaskimplementsRunnable, Iocp.ResultHandler {privatefinalWindowsAsynchronousSocketChannelImpl channel;privatefinalAccessControlContext acc;privatefinalPendingFutureresult;privatefinallongdataBuffer;

AcceptTask(WindowsAsynchronousSocketChannelImpl channel, AccessControlContext acc,longdataBuffer, PendingFutureresult) {this.channel=channel;this.acc=acc;this.result=result;this.dataBuffer=dataBuffer;

}voidenableAccept() {

pendingAccept.decrementAndGet();

dataBuffers.add(dataBuffer);

}voidcloseChildChannel() {try{

channel.close();

}catch(IOException ignore) {

}

}//caller must have acquired read lock for the listener and child channel.voidfinishAccept()throwsIOException {/*** JDK7 use 4 calls to getsockname  to setup

* local& remote address, this is very inefficient.

*

* I change this to use GetAcceptExSockaddrs*/InetAddress[] socks=newInetAddress[2];int[] ports=newint[2];

updateAcceptContext(handle, channel.handle(), socks, ports, dataBuffer);

InetSocketAddress local=newInetSocketAddress(socks[0], ports[0]);finalInetSocketAddress remote=newInetSocketAddress(socks[1], ports[1]);

channel.setConnected(local, remote);//permission check (in context of initiating thread)if(acc!=null) {

AccessController.doPrivileged(newPrivilegedAction() {publicVoid run() {

SecurityManager sm=System.getSecurityManager();

sm.checkAccept(remote.getAddress().getHostAddress(), remote.getPort());returnnull;

}

}, acc);

}

}/*** Initiates the accept operation.*/@Overridepublicvoidrun() {longoverlapped=0L;try{//begin usage of listener socketschannel.begin();try{//begin usage of child socket (as it is registered with//completion port and so may be closed in the event that//the group is forcefully closed).channel.begin();synchronized(result) {

overlapped=ioCache.add(result);intn=accept0(handle, channel.handle(), overlapped, dataBuffer);//Be careful for the buffer addressif(n==IOStatus.UNAVAILABLE) {return;

}//connection accepted immediatelyfinishAccept();//allow another accept before the result is setenableAccept();

result.setResult(channel);

}

}finally{//end usage on child socketchannel.end();

}

}catch(Throwable x) {//failed to initiate accept so release resourcesif(overlapped!=0L)

ioCache.remove(overlapped);

closeChildChannel();if(xinstanceofClosedChannelException)

x=newAsynchronousCloseException();if(!(xinstanceofIOException)&&!(xinstanceofSecurityException))

x=newIOException(x);

enableAccept();

result.setFailure(x);

}finally{//end of usage of listener socketschannel.end();

}//accept completed immediately but may not have executed on//initiating thread in which case the operation may have been//cancelled.if(result.isCancelled()) {

closeChildChannel();

}//invoke completion handlerInvoker.invokeIndirectly(result);

}/*** Executed when the I/O has completed*/@Overridepublicvoidcompleted(intbytesTransferred,booleancanInvokeDirect) {try{//connection accept after group has shutdownif(iocp.isShutdown()) {thrownewIOException(newShutdownChannelGroupException());

}//finish the accepttry{

schannel.begin();try{

channel.begin();

finishAccept();

}finally{

channel.end();

}

}finally{

schannel.end();

}//allow another accept before the result is setenableAccept();

result.setResult(channel);

}catch(Throwable x) {

enableAccept();

closeChildChannel();if(xinstanceofClosedChannelException)

x=newAsynchronousCloseException();if(!(xinstanceofIOException)&&!(xinstanceofSecurityException))

x=newIOException(x);

result.setFailure(x);

}//if an async cancel has already cancelled the operation then//close the new channel so as to free resourcesif(result.isCancelled()) {

closeChildChannel();

}//invoke handler (but not directly)Invoker.invokeIndirectly(result);

}

@Overridepublicvoidfailed(interror, IOException x) {

enableAccept();

closeChildChannel();//release waitersif(schannel.isOpen()) {

result.setFailure(x);

}else{

result.setFailure(newAsynchronousCloseException());

}

Invoker.invokeIndirectly(result);

}

}

FutureimplAccept(Object attachment,finalCompletionHandlerhandler) {if(!schannel.isOpen()) {

Throwable exc=newClosedChannelException();if(handler==null)returnCompletedFuture.withFailure(exc);

Invoker.invokeIndirectly(schannel, handler, attachment,null, exc);returnnull;

}if(schannel.isAcceptKilled())thrownewRuntimeException("Accept not allowed due to cancellation");//ensure channel is bound to local addressif(schannel.localAddress==null)thrownewNotYetBoundException();//create the socket that will be accepted. The creation of the socket//is enclosed by a begin/end for the listener socket to ensure that//we check that the listener is open and also to prevent the I/O//port from being closed as the new socket is registered.WindowsAsynchronousSocketChannelImpl ch=null;

IOException ioe=null;try{

schannel.begin();

ch=newWindowsAsynchronousSocketChannelImpl(iocp,false);

}catch(IOException x) {

ioe=x;

}finally{

schannel.end();

}if(ioe!=null) {if(handler==null)returnCompletedFuture.withFailure(ioe);

Invoker.invokeIndirectly(this.schannel, handler, attachment,null, ioe);returnnull;

}//need calling context when there is security manager as//permission check may be done in a different thread without//any application call frames on the stackAccessControlContext acc=(System.getSecurityManager()==null)?null: AccessController.getContext();

PendingFutureresult=newPendingFuture(schannel, handler, attachment);//check and set flag to prevent concurrent acceptingif(pendingAccept.get()>=maxPending)thrownewAcceptPendingException();

pendingAccept.incrementAndGet();

AcceptTask task=newAcceptTask(ch, acc, dataBuffers.poll(), result);

result.setContext(task);//initiate I/Oif(Iocp.supportsThreadAgnosticIo()) {

task.run();

}else{

Invoker.invokeOnThreadInThreadPool(this.schannel, task);

}returnresult;

}reimplements for performancestaticnativevoidupdateAcceptContext(longlistenSocket,longacceptSocket,

InetAddress[] addresses,int[] ports,longdataBuffer)throwsIOException;staticnativeintaccept0(longhandle,longhandle2,longoverlapped,longdataBuffer);

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值