实现NIO多线程服务器后出现的接收数据包不全的问题
小弟看了<<基于事件的NIO多线程服务器>>一文后,动手做了个类似的服务器端。
读取数据包的类如下:
package com.bestleader.comm.nio;
import java.util.List;
import java.util.LinkedList;
import java.nio.channels.SocketChannel;
import java.nio.channels.SelectionKey;
import java.nio.ByteBuffer;
import java.io.IOException;
import com.bestleader.comm.logs.Logs;
/**
* <p>Title: 读线程</p>
* <p>Description: 该线程用于读取客户端数据</p>
* @author starboy
* @version 1.0
*/
public class Reader extends Thread {
private static int BUFFER_SIZE = 1024;
private static List pool = new LinkedList();
private static Notifier notifier = Notifier.getNotifier();
public Reader() {
}
public void run() {
while (true) {
try {
SelectionKey key;
synchronized (pool) {
while (pool.isEmpty()) {
pool.wait();
}
key = (SelectionKey) pool.remove(0);
}
// 读取数据
read(key);
}
catch (Exception e) {
continue;
}
}
}
/**
* 读取客户端发出请求数据
* @param sc 套接通道
*/
public static byte[] readRequest(SocketChannel sc) throws IOException {
ByteBuffer buffer = ByteBuffer.allocate(BUFFER_SIZE);
int off = 0;
int r = 0;
byte[] data = new byte[BUFFER_SIZE * 10];
while ( true ) {
buffer.clear();
r = sc.read(buffer);
if (r == -1|| r == 0) break;
//问题出在这里:加了这部分代码才能收完数据包
if (r == 12){
try{
//Logs是自己写的一个输出到文本框的输出类
Logs.println("12");
}
catch(Exception ex){ }
}//以上是问题所在的代码
if ( (off + r) > data.length) {
data = grow(data, BUFFER_SIZE * 10);
}
byte[] buf = buffer.array();
System.arraycopy(buf, 0, data, off, r);
off += r;
}
byte[] req = new byte[off];
System.arraycopy(data, 0, req, 0, off);
return req;
}
/**
* 处理连接数据读取
* @param key SelectionKey
*/
public void read(SelectionKey key) {
try {
// 读取客户端数据
SocketChannel sc = (SocketChannel) key.channel();
byte[] clientData = readRequest(sc);
Request request = (Request)key.attachment();
request.setDataInput(clientData);
// 触发onRead
notifier.fireOnRead(request);
// 提交主控线程进行写处理
Server.processWriteRequest(key);
}
catch (Exception e) {
notifier.fireOnError("Error occured in Reader: " + e.getMessage());
}
}
/**
* 处理客户请求,管理用户的联结池,并唤醒队列中的线程进行处理
*/
public static void processRequest(SelectionKey key) {
synchronized (pool) {
pool.add(pool.size(), key);
pool.notifyAll();
}
}
/**
* 数组扩容
* @param src byte[] 源数组数据
* @param size int 扩容的增加量
* @return byte[] 扩容后的数组
*/
public static byte[] grow(byte[] src, int size) {
byte[] tmp = new byte[src.length + size];
System.arraycopy(src, 0, tmp, 0, src.length);
return tmp;
}
}
客户端有两种,一个是用C++写的网关程序,一个是用JAVA写的业务处理程序,它们之间传递的数据包都是XML格式,但会在数据包前面加上12位的byte来记录数据包的长度。现在的问题是,用C++写的网关程序,在传递数据包的时候,经常出现只收到包头(也就是只有12位长,记录数据包长度的byte),后面的数据包内容收不到;而如果单步调试这部分代码,就会分成两次接收(能够全部收完)。用JAVA写的程序传过来的数据则没有这个问题。给我的感觉是:C++传过来的包分成了两部分(正常情况下应该是一个整体),如果不加输出的代码,就不能收全数据。加wait()延时也没用,用System.out.print()输出也没用,目前只发现用自己写的输出类才能把分成的两部分数据全接收。各位大侠,这会是什么问题啊?