初探JAVA AIO

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u014022405/article/details/82286727

直接上代码吧,代码中有注释

package com.mtl.aio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.AsynchronousChannelGroup;
import java.nio.channels.AsynchronousServerSocketChannel;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executors;

public class AIOMain {
	public static CountDownLatch countDownLatch=new CountDownLatch(1);//只是为了让主线程一直挂起
	public static void main(String[] args) {
		AsynchronousServerSocketChannel serverSocketChannel=null;
		try {
			//申明一个异步ServerSocketChannel,和NIO申明 ServerSocketChannel 唯一不同的是,传入已了个参数
			//这个参数传入一个线程池,作用:应用程序将向操作系统发出IO请求,这个时候应用程序立即返回,当操作系统IO准备就绪的时候,会主动通知应用系统(异步的概念)
			//然后应用程序将调用该线程池的线程,执行相应的回调
			serverSocketChannel=AsynchronousServerSocketChannel
					.open(AsynchronousChannelGroup.withThreadPool(Executors.newFixedThreadPool(10)));
			//绑定端口
			serverSocketChannel.bind(new InetSocketAddress(10086));
			//这个类是我们自己封装的一个类,代表着一个连接,对应一个session,主要保存连接ServerSocketChannel,读写ByteBuffer,用于回调之间传递参数
			MySession session=new MySession();
			session.setServerSocketChannel(serverSocketChannel);
			//该方法和NIO或者BIO一样的作用,用于等待一个连接接入
			//区别在于,BIO会一直阻塞到这里,直到有连接接入。
			//NIO会将ServerSocketChannel注册到一个selector中,selector底层会不断向操作系统发出查询,是否有连接接入,
			//如果有则selector.selectkey()回返回,然后调用accept返回一个SocketChannel
			//AIO 则是调用此方法后,将立即返回,方法传入一个回调,回调实现java.nio.channels.CompletionHandler即可,如果有连接接入,
			//操作系统将通知应用系统,应用则会执行回调,这就是异步
			//该方法第一个参数用于在回调直接传递参数,第二个参数则是有连接接入时的回调类
			serverSocketChannel.accept(session, new AcceptHandler());
		} catch (IOException e) {
			if (serverSocketChannel!=null) {
				try {
					serverSocketChannel.close();
				} catch (IOException e1) {
					e1.printStackTrace();
					countDownLatch.countDown();
				}
			}
			e.printStackTrace();
		}
		try {
			//让主线程一直挂起到这里
			countDownLatch.await();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
}
package com.mtl.aio;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousServerSocketChannel;
import java.nio.channels.AsynchronousSocketChannel;

public class MySession {
	//当前ServerSocketChannel
	private AsynchronousServerSocketChannel serverSocketChannel;
	//当前SocketChannel
	private AsynchronousSocketChannel socketChannel;
	//读取报文头的Buffer
	private ByteBuffer headBuffer=ByteBuffer.allocate(10);
	//读取报文体的Buffer
	private ByteBuffer bodyBuffer;
	//写出报文Buffer
	private ByteBuffer writeBuffer;
	
	public ByteBuffer getWriteBuffer() {
		return writeBuffer;
	}
	public void setWriteBuffer(ByteBuffer writeBuffer) {
		this.writeBuffer = writeBuffer;
	}
	public AsynchronousServerSocketChannel getServerSocketChannel() {
		return serverSocketChannel;
	}
	public void setServerSocketChannel(AsynchronousServerSocketChannel serverSocketChannel) {
		this.serverSocketChannel = serverSocketChannel;
	}
	public AsynchronousSocketChannel getSocketChannel() {
		return socketChannel;
	}
	public void setSocketChannel(AsynchronousSocketChannel socketChannel) {
		this.socketChannel = socketChannel;
	}
	public ByteBuffer getHeadBuffer() {
		return headBuffer;
	}
	public void setHeadBuffer(ByteBuffer headBuffer) {
		this.headBuffer = headBuffer;
	}
	public ByteBuffer getBodyBuffer() {
		return bodyBuffer;
	}
	public void setBodyBuffer(ByteBuffer bodyBuffer) {
		this.bodyBuffer = bodyBuffer;
	}
	public void close() {
		try {
			if (socketChannel!=null) {
				socketChannel.close();
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}
package com.mtl.aio;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousServerSocketChannel;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
import java.util.concurrent.TimeUnit;

import org.apache.log4j.Logger;

public class AcceptHandler implements CompletionHandler<AsynchronousSocketChannel, MySession> {
	private Logger logger=Logger.getLogger(AcceptHandler.class);
	
	
	/**
	 * 该方法第一个参数就是异步的SocketChannel,和NIO中的SocketChannel一样
	 * NIO中accept方法返回一个SocketChannel,AIO中回调中返回一个异步的socketChannel
	 */
	@Override
	public void completed(AsynchronousSocketChannel socketChannel, MySession attachment) {
		try {
			logger.info("有连接接入!IP:"+socketChannel.getRemoteAddress());
		} catch (IOException e) {
			e.printStackTrace();
			try {
				socketChannel.close();
			} catch (IOException e1) {
				e1.printStackTrace();
			}
		}
		//从session中取出AsynchronousServerSocketChannel 准备下一次连接接入
		AsynchronousServerSocketChannel serverSocketChannel=attachment.getServerSocketChannel();
		MySession session=new MySession();
		session.setServerSocketChannel(serverSocketChannel);
		//准备下次连接
		serverSocketChannel.accept(session, this);
		//把异步SocketChannel保存在session中,用于在回调中传递,可以方便的取出来读写数据
		attachment.setSocketChannel(socketChannel);
		//该方法是一个异步读取的方法 read 方法有几个重载的方法
		//read(ByteBuffer dst)返回一个Future 可通过get方法等待结果,但是这样线程就堵塞了,所以我用了下面一个方法
		//第一个参数byteBuffer,用于读取数据,第二个参数和第三个参数表示读取超时时间 30S ,第三个参数当前连接的session,第四个参数是读取完成后的回调类
		//该方法会立即返回,不会堵塞。
		//我简单定义了一个报文协议:报文前10个字节代码报文头,报文头总是以{开头,}结尾,中间8位为报文正文长度,不足8位补空格
		//例如{      12}111111111111这是一个完整的报文,报文头10个字节,其中12代表报文正文一共12个字节
		//这个地方我先读取报文头的类容,所以回调为读取报文头的回调,session里面的headBuffer用于读取报文头
		socketChannel.read(attachment.getHeadBuffer(), 30L, TimeUnit.SECONDS, 
				attachment, new ReadHeadHandler());
	}

	@Override
	public void failed(Throwable exc, MySession attachment) {
		//如果连接异常,服务器还是应该继续等待连接
		logger.error("服务器Accept异常!", exc);
		AsynchronousServerSocketChannel serverSocketChannel=attachment.getServerSocketChannel();
		serverSocketChannel.accept(attachment, this);
	}

}
package com.mtl.aio;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
import java.util.concurrent.TimeUnit;

import org.apache.log4j.Logger;

public class ReadHeadHandler implements CompletionHandler<Integer, MySession> {
	private Logger logger=Logger.getLogger(AcceptHandler.class);
	
	/**
	 * 该方法第一个参数是当前实际读取的值,第二个参数是我们前一个回调传递过来的session
	 */
	@Override
	public void completed(Integer result, MySession attachment) {
		//如果读到的实际大小为-1则客户端关闭连接,我们也关闭对应的连接
		if (-1==result) {
			logger.info("客户端已关闭连接!服务端准备关闭连接关闭连接!");
			attachment.close();
		}
		logger.info("读取数:"+result);
		AsynchronousSocketChannel socketChannel = attachment.getSocketChannel();
		//如果HeadBuffer的position不为10,证明报文头还没有读完,所以继续读取报文头(因为我们的报文头定义的是10位)
		if (attachment.getHeadBuffer().position()!=10) {
			logger.info("再次读取报文体!");
			socketChannel.read(attachment.getHeadBuffer(), 30L, TimeUnit.SECONDS, attachment, this);
		}else {//如果position为10,证明我们读到了完整的报文头,则开始处理报文头,主要获取报文头中的报文正文大小
			ByteBuffer headBuffer = attachment.getHeadBuffer();
			headBuffer.flip();
			String string=null;
			try {
				string = new String(headBuffer.array(),"UTF-8");
				logger.info("报文头读取完成!准备读取报文体!报文头:"+string);
			} catch (UnsupportedEncodingException e) {
				e.printStackTrace();
			}
			String substring = string.substring(1,9);
			int length = 0;
			try {
				length=Integer.parseInt(substring.trim());//获取到报文中的中文大小
			} catch (Exception e) {
				logger.error("报文头异常!", e);
				try {
					attachment.getSocketChannel().close();
					throw new RuntimeException(e);
				} catch (IOException e1) {
					e1.printStackTrace();
				}
			}
			//将读取报文体的Buffer初始化
			attachment.setBodyBuffer(ByteBuffer.allocate(length));
			//异步再读取报问体中的内容,同样超时时间30S,传入读取报问体的回调类
			attachment.getSocketChannel().read(attachment.getBodyBuffer(), 30L, TimeUnit.SECONDS,
					attachment, new ReadBodyHandler());
		}
	}

	@Override
	public void failed(Throwable exc, MySession attachment) {
		//读取报文头是吧,直接关闭连接!
		logger.error("服务端读取报文头失败!", exc);
		AsynchronousSocketChannel socketChannel = attachment.getSocketChannel();
		try {
			socketChannel.close();
		} catch (IOException e) {
			logger.error("服务端关闭连接错误!", e);
		}
	}

}
package com.mtl.aio;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.nio.channels.CompletionHandler;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.TimeUnit;

import org.apache.log4j.Logger;

public class ReadBodyHandler implements CompletionHandler<Integer, MySession> {

	private Logger logger=Logger.getLogger(ReadBodyHandler.class);
	@Override
	public void completed(Integer result, MySession attachment) {
		//同样如果读到的实际大小为-1则客户端关闭连接,我们也关闭对应的连接
		if (-1==result) {
			attachment.close();
		}
		ByteBuffer headBuffer = attachment.getBodyBuffer();
		//因为我们分配的读取报文体的buffer大小和报文体大小一样,所以如果buffer没有读满,则还没读取完,则再次读取
		//真实环境中,可以判断报文大小,超过限制直接丢弃,防止内存溢出
		if (headBuffer.position()!=headBuffer.capacity()) {
			logger.info("再次读取报文体!");
			attachment.getSocketChannel().read(attachment.getBodyBuffer(), 30L, TimeUnit.SECONDS, attachment, new ReadBodyHandler());
		}else{
			//如果读取完了,则处理报文体,如果真实环境,如果处理报文体时间较长,需要访问数据库等操作,可以用另外一个线程池来处理业务逻辑!
			//这里测试,只是将报文类容展示出来,然后回应客服端一段文字
			ByteBuffer bodyBuffer = attachment.getBodyBuffer();
			bodyBuffer.flip();
			try {
				logger.info("##########收到消息:"+new String(bodyBuffer.array(),0,bodyBuffer.limit(),"UTF-8"));
			} catch (UnsupportedEncodingException e2) {
				e2.printStackTrace();
				logger.error("处理接收字符异常!关闭连接", e2);
				try {
					attachment.getSocketChannel().close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			logger.info("报文体读取完成!准备回应客户端!");
			StringBuilder ret=new StringBuilder("我是服务器!我已经收到你的报文了!");
			ret.append(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS").format(new Date()));
			byte[] bs=null;
			try {
				bs = ret.toString().getBytes("UTF-8");
			} catch (UnsupportedEncodingException e) {
				e.printStackTrace();
				try {
					attachment.getSocketChannel().close();
				} catch (IOException e1) {
					e1.printStackTrace();
				}
			}
			ByteBuffer buffer=ByteBuffer.allocate(bs.length);
			buffer.put(bs);
			buffer.flip();
			//将写出Buffer放在session中,用于在回调中传递
			attachment.setWriteBuffer(buffer);
			//同样异步写出,传入超时时间和写出后的回调
			attachment.getSocketChannel().write(buffer, 30L, TimeUnit.SECONDS, attachment, new WriteHandler());
		}
	}

	@Override
	public void failed(Throwable exc, MySession attachment) {
		logger.error("服务端读取异常!", exc);
		try {
			attachment.getSocketChannel().close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

}
package com.mtl.aio;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.CompletionHandler;
import java.util.concurrent.TimeUnit;

import org.apache.log4j.Logger;

public class WriteHandler implements CompletionHandler<Integer, MySession> {

	private Logger logger=Logger.getLogger(WriteHandler.class);
	@Override
	public void completed(Integer result, MySession attachment) {
		ByteBuffer writeBuffer = attachment.getWriteBuffer();
		if (writeBuffer.hasRemaining()) {//如果Buffer没有写完,则再次写出,因为程序不能保证一次性把全部数据写出
			logger.info("再次写出!");
			attachment.getSocketChannel().write(writeBuffer, 30L, TimeUnit.SECONDS, attachment, new WriteHandler());
		}else {//如果写出完成!如果是短连接,那一次交互就完成了,可以关闭连接。
			//try {
				/*attachment.getSocketChannel().close();
				logger.info("写出完成!关闭连接!");
				AIOMain.countAdd();
				AIOMain.print();
				AIOMain.countDownLatch.countDown();*/
			
				//如果是长连接,则将bodyBuffer和WriteBUFFER设置为null,让GC可以回收内存,并准备下一次的报文头读取
				attachment.setBodyBuffer(null);
				attachment.getHeadBuffer().clear();
				attachment.setWriteBuffer(null);
				//这里没有指定读取超时时间
				attachment.getSocketChannel().read(attachment.getHeadBuffer(), attachment, new ReadHeadHandler());
			//} catch (IOException e) {
				//e.printStackTrace();
			//}
		}
	}

	@Override
	public void failed(Throwable exc, MySession attachment) {
		logger.error("写出错误!", exc);
		try {
			attachment.getSocketChannel().close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

}

客户端测试类

package com.mtl.test;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.Socket;

public class ClientTest {

	public static void main(String[] args) {
		Socket socket=null;
		try {
			socket=new Socket("127.0.0.1", 10086);
			OutputStream outputStream = socket.getOutputStream();
			String string=new String("摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!"
					+ "摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!"
					+ "摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!"
					+ "摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!"
					+ "摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!"
					+ "摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!"
					+ "摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!"
					+ "摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!"
					+ "摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!"
					+ "摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!"
					+ "摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!"
					+ "摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!"
					+ "摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!"
					+ "摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!"
					+ "摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!"
					+ "摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!"
					+ "摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!"
					+ "摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!"
					+ "摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!"
					+ "摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!"
					+ "摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!"
					+ "摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!"
					+ "摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!"
					+ "摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!"
					+ "摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!摸摸头!开始了!abcde!213452131!"
					+ "");
			String headBody=doHead(string);
			System.out.println("报文:"+headBody);
			outputStream.write(headBody.getBytes("UTF-8"));
			InputStream inputStream = socket.getInputStream();
			byte[] buf=new byte[1024];
			int read = inputStream.read(buf);
			System.out.println("服务器返回:"+new String(buf,0,read,"UTF-8"));
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			if (socket!=null) {
				try {
					socket.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}
	public static String doHead(String body) throws UnsupportedEncodingException{
		StringBuilder head=new StringBuilder();
		head.append("{");
		Integer length = body.getBytes("UTF-8").length;
		int lengthLength=length.toString().length();
		for(int i=0;i<8-lengthLength;i++){
			head.append(" ");
		}
		head.append(length).append("}");
		return head.append(body).toString();
	}
}

用了一个简单的TCP压测工具测了一下,2000个连接每50毫秒发送一个10k大小的报文

压测工具    下载压测工具

猜你喜欢

转载自blog.csdn.net/u014022405/article/details/82286727