版权声明:本文为博主原创文章,未经博主允许不得转载。 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();
}
}