netty4已经发布有段时间了,今天因为压测 写了一个netty4的客户端(版本4.0.6.Final)现在分享出来给大家:
netty4配置类
package nettyClient4; import io.netty.bootstrap.Bootstrap; import io.netty.buffer.ByteBuf; import io.netty.buffer.PooledByteBufAllocator; import io.netty.channel.Channel; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelOption; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioSocketChannel; import org.apache.log4j.xml.DOMConfigurator; import java.io.File; import java.io.FileInputStream; import java.io.InputStream; import java.util.Properties; /** * @author : 陈磊 <br/> * Date: 13-3-11<br/> * Time: 下午4:08<br/> * connectMethod:[email protected]<br/> */ public class clientImpl implements Runnable { private String host=""; private short port; public static void main(String[]args){ try { DOMConfigurator.configure("res/log4j.xml"); Properties properties=getProPertis("res/client.properties"); int clientNum= Integer.valueOf(properties.getProperty("num")); String host= properties.getProperty("host"); short port=Short.valueOf(properties.getProperty("port")); for (int i=0;i!=clientNum;++i){ clientImpl client=new clientImpl(); client.setHost(host); client.setPort(port); Thread thread=new Thread(client); thread.start(); } } catch (Exception e){ //do nothing } } public static Properties getProPertis(String filePath) { InputStream fileInputStream = null; try { fileInputStream = new FileInputStream(new File(filePath)); Properties serverSettings = new Properties(); serverSettings.load(fileInputStream); fileInputStream.close(); return serverSettings; } catch (Exception e) { e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. return null; } } public void start() throws Exception { EventLoopGroup workerGroup = new NioEventLoopGroup(); try { Bootstrap bootstrap = new Bootstrap(); bootstrap.group( workerGroup).channel(NioSocketChannel.class) ; // NioSocketChannel is being used to create a client-side Channel. //Note that we do not use childOption() here unlike we did with // ServerBootstrap because the client-side SocketChannel does not have a parent. bootstrap.option(ChannelOption.SO_KEEPALIVE, true) ; bootstrap.handler(new ClientChannelInitializer()); // Bind and start to accept incoming connections. ChannelFuture channelFuture = bootstrap.connect(this.host,this.port); // Wait until the server socket is closed. // In this server, this does not happen, but you can do that to gracefully // shut down your CLIENT. Channel channel=channelFuture.channel(); while (true){ ByteBuf buffer= PooledByteBufAllocator.DEFAULT.heapBuffer(10); buffer.writeShort(Short.MIN_VALUE);//包长占2字节 buffer.writeByte(1); buffer.writeByte(0); buffer.setShort(0,buffer.writerIndex()-0x2); channel.writeAndFlush(buffer) ; Thread.sleep(200); } }finally { workerGroup.shutdownGracefully(); } } public short getPort() { return port; } public void setPort(short port) { this.port = port; } public String getHost() { return host; } public void setHost(String host) { this.host = host; } private ByteBuf getWriteBuffer(int arg1,int arg2,ByteBuf buffer,Object...paras){ if (buffer==null){ buffer=PooledByteBufAllocator.DEFAULT.heapBuffer(10); } buffer.writeShort(Short.MIN_VALUE);//包长占2字节 buffer.writeByte(arg1); if (arg2!=0)buffer.writeByte(arg2); for (Object para:paras){ if (para instanceof Byte){ buffer.writeByte((Byte) para); // 占1字节 }else if ((para instanceof String)){ buffer.writeBytes(((String) para).getBytes()); } else if (para instanceof Integer){ buffer.writeInt((Integer)para); //占4字节 }else if (para instanceof Short){ buffer.writeShort((Short) para); //占2字节 } } /**包长占2字节,setShort()*/ buffer.setShort(0,buffer.writerIndex()-0x2); return buffer; } @Override public void run() { try { start(); } catch (Exception e) { e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. } } }
ChannelInitializer 初始化类:
package nettyClient4; import Server.ExtComponents.utilsKit.ThreadUtils.PriorityThreadFactory; import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelPipeline; import io.netty.channel.socket.SocketChannel; import io.netty.handler.logging.LoggingHandler; import io.netty.util.concurrent.DefaultEventExecutorGroup; import io.netty.util.concurrent.EventExecutorGroup; /** * @author : 石头哥哥 * Project : LandlordsServer * Date: 13-8-7 * Time: 上午9:53 * Connect: [email protected] * packageName: nettyClient4 */ @ChannelHandler.Sharable public class ClientChannelInitializer extends ChannelInitializer<SocketChannel> { private static final LoggingHandler LOGGING_HANDLER=new LoggingHandler(); private static final EventExecutorGroup EVENT_EXECUTORS=new DefaultEventExecutorGroup(3,new PriorityThreadFactory("executionLogicHandlerThread+#", Thread.NORM_PRIORITY )); /** * This method will be called once the {@link io.netty.channel.Channel} was registered. After the method returns this instance * will be removed from the {@link io.netty.channel.ChannelPipeline} of the {@link io.netty.channel.Channel}. * * @param ch the {@link io.netty.channel.Channel} which was registered. * @throws Exception is thrown if an error occurs. In that case the {@link io.netty.channel.Channel} will be closed. */ @Override protected void initChannel(SocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); pipeline.addLast("LOGGING_HANDLER",LOGGING_HANDLER); pipeline.addLast("decoder",new clientDecoder(20000,0,2 ,0,2)); pipeline.addLast("handler",new clientHandler()); pipeline.addLast("encoder",new clientEncoder()); } }
package nettyClient4; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.ByteToMessageDecoder; import io.netty.handler.codec.CorruptedFrameException; import io.netty.handler.codec.TooLongFrameException; import java.nio.ByteOrder; import java.util.List; /** * @author : 石头哥哥 * Project : LandlordsServer * Date: 13-8-7 * Time: 上午9:52 * Connect: [email protected] * packageName: nettyClient4 */ public class clientDecoder extends ByteToMessageDecoder { private final ByteOrder byteOrder; private final int maxFrameLength; private final int lengthFieldOffset; private final int lengthFieldLength; private final int lengthFieldEndOffset; private final int lengthAdjustment; private final int initialBytesToStrip; private final boolean failFast; private boolean discardingTooLongFrame; private long tooLongFrameLength; private long bytesToDiscard; /** * * @param maxFrameLength * @param lengthFieldOffset * @param lengthFieldLength * @param lengthAdjustment * @param initialBytesToStrip */ public clientDecoder( int maxFrameLength, int lengthFieldOffset, int lengthFieldLength, int lengthAdjustment, int initialBytesToStrip) { this( maxFrameLength, lengthFieldOffset, lengthFieldLength, lengthAdjustment, initialBytesToStrip, true); } /** * * @param maxFrameLength * @param lengthFieldOffset * @param lengthFieldLength * @param lengthAdjustment * @param initialBytesToStrip * @param failFast */ public clientDecoder( int maxFrameLength, int lengthFieldOffset, int lengthFieldLength, int lengthAdjustment, int initialBytesToStrip, boolean failFast) { this( ByteOrder.BIG_ENDIAN, maxFrameLength, lengthFieldOffset, lengthFieldLength, lengthAdjustment, initialBytesToStrip, failFast); } /** * * @param byteOrder * @param maxFrameLength * @param lengthFieldOffset * @param lengthFieldLength * @param lengthAdjustment * @param initialBytesToStrip * @param failFast */ public clientDecoder( ByteOrder byteOrder, int maxFrameLength, int lengthFieldOffset, int lengthFieldLength, int lengthAdjustment, int initialBytesToStrip, boolean failFast) { if (byteOrder == null) { throw new NullPointerException("byteOrder"); } if (maxFrameLength <= 0) { throw new IllegalArgumentException( "maxFrameLength must be a positive integer: " + maxFrameLength); } if (lengthFieldOffset < 0) { throw new IllegalArgumentException( "lengthFieldOffset must be a non-negative integer: " + lengthFieldOffset); } if (initialBytesToStrip < 0) { throw new IllegalArgumentException( "initialBytesToStrip must be a non-negative integer: " + initialBytesToStrip); } if (lengthFieldLength != 1 && lengthFieldLength != 2 && lengthFieldLength != 3 && lengthFieldLength != 4 && lengthFieldLength != 8) { throw new IllegalArgumentException( "lengthFieldLength must be either 1, 2, 3, 4, or 8: " + lengthFieldLength); } if (lengthFieldOffset > maxFrameLength - lengthFieldLength) { throw new IllegalArgumentException( "maxFrameLength (" + maxFrameLength + ") " + "must be equal to or greater than " + "lengthFieldOffset (" + lengthFieldOffset + ") + " + "lengthFieldLength (" + lengthFieldLength + ")."); } this.byteOrder = byteOrder; this.maxFrameLength = maxFrameLength; this.lengthFieldOffset = lengthFieldOffset; this.lengthFieldLength = lengthFieldLength; this.lengthAdjustment = lengthAdjustment; lengthFieldEndOffset = lengthFieldOffset + lengthFieldLength; this.initialBytesToStrip = initialBytesToStrip; this.failFast = failFast; } /** * decode message will be added the MessageList<Object> out queue! * @param ctx * @param in * @param out * @throws Exception * 针对每一个channel 都会有一个相应的OutputMessageBuf消息缓存队列 */ @Override protected final void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { ByteBuf byteBuf = decode(ctx, in); if (byteBuf != null) { out.add(byteBuf); } } /** * return the date of ByteBuf * @param ctx * @param in * @return * @throws Exception */ private ByteBuf decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception { if (discardingTooLongFrame) { long bytesToDiscard = this.bytesToDiscard; int localBytesToDiscard = (int) Math.min(bytesToDiscard, in.readableBytes()); in.skipBytes(localBytesToDiscard); bytesToDiscard-= localBytesToDiscard; this.bytesToDiscard = bytesToDiscard; failIfNecessary(ctx, false); return null; } if (in.readableBytes() < lengthFieldEndOffset) { return null; } int actualLengthFieldOffset = in.readerIndex() + lengthFieldOffset; /**获取数据包长*/ // long frameLength = (in.order(byteOrder)).getUnsignedByte(actualLengthFieldOffset); long frameLength = (in.order(byteOrder)).getUnsignedShort(actualLengthFieldOffset); if (frameLength < 0) { in.skipBytes(lengthFieldEndOffset); throw new CorruptedFrameException( "negative pre-adjustment length field: " + frameLength); } frameLength += lengthAdjustment + lengthFieldEndOffset; if (frameLength < lengthFieldEndOffset) { in.skipBytes(lengthFieldEndOffset); throw new CorruptedFrameException( "Adjusted frame length (" + frameLength + ") is less " + "than lengthFieldEndOffset: " + lengthFieldEndOffset); } if (frameLength > maxFrameLength) { // Enter the discard mode and discard everything received so far. discardingTooLongFrame = true; tooLongFrameLength = frameLength; bytesToDiscard = frameLength - in.readableBytes(); in.skipBytes(in.readableBytes()); failIfNecessary(ctx, true); return null; } // never overflows because it's less than maxFrameLength int frameLengthInt = (int) frameLength; if (in.readableBytes() < frameLengthInt) { return null; } if (initialBytesToStrip > frameLengthInt) { in.skipBytes(frameLengthInt); throw new CorruptedFrameException( "Adjusted frame length (" + frameLength + ") is less " + "than initialBytesToStrip: " + initialBytesToStrip); } in.skipBytes(initialBytesToStrip); // extract frame int readerIndex = in.readerIndex(); int actualFrameLength = frameLengthInt - initialBytesToStrip; ByteBuf frame = extractFrame(in, readerIndex, actualFrameLength,ctx); in.readerIndex(readerIndex + actualFrameLength); return frame; } /** * 返回字节长度 byte short * return the length of pack * @param in * @param actualLengthFieldOffset * @return */ @Deprecated private long getFrameLength(ByteBuf in, int actualLengthFieldOffset) { in = in.order(byteOrder); return in.getUnsignedShort(actualLengthFieldOffset);//return the length } /** * * @param ctx * @param firstDetectionOfTooLongFrame */ private void failIfNecessary(ChannelHandlerContext ctx, boolean firstDetectionOfTooLongFrame) { if (bytesToDiscard == 0) { // Reset to the initial state and tell the handlers that // the frame was too large. long tooLongFrameLength = this.tooLongFrameLength; this.tooLongFrameLength = 0; discardingTooLongFrame = false; if (!failFast || failFast && firstDetectionOfTooLongFrame) { fail(tooLongFrameLength); } } else { // Keep discarding and notify handlers if necessary. if (failFast && firstDetectionOfTooLongFrame) { fail(tooLongFrameLength); } } } /** * Extract the sub-region of the specified buffer. * <p> * If you are sure that the frame and its content are not accessed after * the current {@link #decode(io.netty.channel.ChannelHandlerContext, io.netty.buffer.ByteBuf)} * call returns, you can even avoid memory copy by returning the sliced * sub-region (i.e. <tt>return buffer.slice(index, length)</tt>). * It's often useful when you convert the extracted frame into an object. * Refer to the source code of {@link io.netty.handler.codec.serialization.ObjectDecoder} to see how this method * is overridden to avoid memory copy. */ protected ByteBuf extractFrame(ByteBuf buffer, int index, int length) { ByteBuf frame = Unpooled.buffer(length); frame.writeBytes(buffer, index, length); return frame; } /** * is overridden to avoid memory copy. * 使用Unpooled ByteBufs会造成沉重的分配与再分配问题, * 使用ChannelHandlerContext.alloc()或Channel.alloc() * 来获取ByteBufAllocator分配ByteBuf,从而减轻GC执行; * @param buffer * @param index * @param length * @param ctx ChannelHandlerContext * @return */ protected ByteBuf extractFrame(ByteBuf buffer, int index,int length,ChannelHandlerContext ctx) { ByteBuf frame =ctx.alloc().buffer(length); frame.writeBytes(buffer, index, length); return frame; } /** * * 解析数据,返回pack[]数组数据包 * @param buffer * @param index * @param length * @return byte[] */ private byte[] extractFrameByteArray(ByteBuf buffer, int index, int length) { byte[] pack=new byte[length]; buffer.readBytes(pack,index,length); return pack; } //logger fail private void fail(long frameLength) { if (frameLength > 0) { throw new TooLongFrameException( "Adjusted frame length exceeds " + maxFrameLength + ": " + frameLength + " - discarded"); } else { throw new TooLongFrameException( "Adjusted frame length exceeds " + maxFrameLength + " - discarding"); } } }encoder类:
package nettyClient4; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.MessageToByteEncoder; /** * @author : 石头哥哥 * Project : LandlordsServer * Date: 13-8-7 * Time: 上午9:52 * Connect: [email protected] * packageName: nettyClient4 */ @ChannelHandler.Sharable public class clientEncoder extends MessageToByteEncoder<ByteBuf> { public clientEncoder(){ super(false); } /** * Encode a message into a {@link io.netty.buffer.ByteBuf}. This method will be called for each written message that can be handled * by this encoder. * * @param ctx the {@link io.netty.channel.ChannelHandlerContext} which this {@link io.netty.handler.codec.MessageToByteEncoder} belongs to * @param msg the message to encode * @param out the {@link io.netty.buffer.ByteBuf} into which the encoded message will be written * @throws Exception is thrown if an error accour */ @Override protected void encode(ChannelHandlerContext ctx, ByteBuf msg, ByteBuf out) throws Exception { out.writeBytes(msg, msg.readerIndex(), msg.readableBytes()); } }
逻辑处理类handler:
package nettyClient4; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; /** * @author : 石头哥哥 * Project : LandlordsServer * Date: 13-8-7 * Time: 上午9:52 * Connect: [email protected] * packageName: nettyClient4 */ public class clientHandler extends ChannelInboundHandlerAdapter { @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { ByteBuf byteBuf= (ByteBuf)msg; try { byte firstType=byteBuf.readByte(); //类型一 if (firstType>0){ byte secondType=byteBuf.readByte(); //类型二 }else { } } catch (Exception e) { } byteBuf.release(); ctx.fireChannelReadComplete(); } @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { } }以上就是netty4的客户端代码,注意配置类里面的参数设置(如果要用的话稍微改改);有什么问题可以留言