本人新手,请教关于nio数据接受不全的问题

熊孩纸有一颗平常心 2014-11-11 10:09:10
本人写了一个C/S模式的通讯程序。但是考虑想测试大数据时是否能通。但是出现了问题。数据接受不完全。
下面是代码,求帮忙!
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Server2 {
private final int PORT = 12347;
private ExecutorService pool;
private ServerSocketChannel ssc;
private Selector selector;
private static Charset charset = Charset.forName("utf-8");
private int n;
int clientCount;

public static void main(String[] args) throws IOException {
Server server = new Server();
server.doService();
}

public Server2() throws IOException {
// pool = Executors.newFixedThreadPool(5);
pool = Executors.newCachedThreadPool();
ssc = ServerSocketChannel.open();
ssc.configureBlocking(false);
ServerSocket ss = ssc.socket();
ss.bind(new InetSocketAddress(PORT));
selector = Selector.open();
ssc.register(selector, SelectionKey.OP_ACCEPT);
System.out.println("Server started...");
}

public void doService() {
while (true) {
try {
n = selector.select();
} catch (IOException e) {
throw new RuntimeException("Selector.select()异常!");
}
if (n == 0)
continue;
Set<SelectionKey> keys = selector.selectedKeys();
Iterator<SelectionKey> iter = keys.iterator();
while (iter.hasNext()) {
SelectionKey key = iter.next();
iter.remove();
if (key.isAcceptable()) {
SocketChannel sc = null;
try {
sc = ((ServerSocketChannel) key.channel()).accept();
clientCount++;
sc.configureBlocking(false);
System.out.println("第" + clientCount + "个客户端:"
+ sc.socket().getInetAddress().getHostAddress()
+ "已连接");
SelectionKey k = sc.register(selector,
SelectionKey.OP_READ);
ByteBuffer buf = ByteBuffer.allocate(102400);
k.attach(buf);
} catch (Exception e) {
try {
sc.close();
} catch (Exception ex) {
}
}
} else if (key.isReadable()) {
key.interestOps(key.interestOps() & (~SelectionKey.OP_READ));
pool.execute(new Worker(key));
}else if(key.isWritable()) {
SocketChannel chan = (SocketChannel) key.channel();
String date="";
int i=0;
while(i<25000)
{
date=date+String.valueOf(i)+ ":This is just a reply to confirm my UDP communication\n";
i++;


}
System.out.println(date);
ByteBuffer buf = ByteBuffer.wrap(date.getBytes());
buf.position(buf.limit());
buf.flip();
while(buf.hasRemaining()) {
try {
chan.write(buf);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
buf.clear();

if(key.isValid()) {
key.interestOps(SelectionKey.OP_READ);
}
}
}
}
}

public static class Worker implements Runnable {
private SelectionKey key;

public Worker(SelectionKey key) {
this.key = key;
}

@Override
public void run() {
long starttime = System.currentTimeMillis();
SocketChannel sc = (SocketChannel) key.channel();

ByteBuffer buf = (ByteBuffer) key.attachment();
buf.clear();
int len = 0;

try {

while ((len = sc.read(buf)) > 0) {// 非阻塞,立刻读取缓冲区可用字节

buf.flip();
System.out.println("客户端:"
+ charset.decode(buf).toString());
buf.clear();

}
if (len == -1) {
System.out.println("客户端断开!");
sc.close();


}
// 没有可用字节,继续监听OP_READ
key.interestOps(SelectionKey.OP_WRITE);
key.selector().wakeup();
} catch (Exception e) {
try {
sc.close();
} catch (IOException e1) {
}
}
long endtime = System.currentTimeMillis();
System.out.println("处理耗时:"
+ (endtime - starttime));
}
}
}


之后是client端的代码(也是nio);
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;

public class NioClient {
//管道管理器
private Selector selector;

public NioClient init(String serverIp, int port) throws IOException{
//获取socket通道
SocketChannel channel = SocketChannel.open();

channel.configureBlocking(false);
//获得通道管理器
selector=Selector.open();

//客户端连接服务器,需要调用channel.finishConnect();才能实际完成连接。
channel.connect(new InetSocketAddress(serverIp, port));
//为该通道注册SelectionKey.OP_CONNECT事件
channel.register(selector, SelectionKey.OP_CONNECT);
return this;
}

public void listen() throws IOException{
System.out.println("客户端启动");
//轮询访问selector
while(true){
//选择注册过的io操作的事件(第一次为SelectionKey.OP_CONNECT)
selector.select();
Iterator<SelectionKey> ite = selector.selectedKeys().iterator();
while(ite.hasNext()){
SelectionKey key = ite.next();
//删除已选的key,防止重复处理
ite.remove();
if(key.isConnectable()){
SocketChannel channel=(SocketChannel)key.channel();

//如果正在连接,则完成连接
if(channel.isConnectionPending()){
channel.finishConnect();
}

channel.configureBlocking(false);
//向服务器发送消息
String date="";
int i=0;
while(i<25000){
date=date+String.valueOf(i)+":this is a test to confirm my UDP communication\n";
i++;
}
channel.write(ByteBuffer.wrap(date.getBytes()));

//连接成功后,注册接收服务器消息的事件
channel.register(selector, SelectionKey.OP_READ);
System.out.println("客户端连接成功");
}else if(key.isReadable()){ //有可读数据事件。
SocketChannel channel = (SocketChannel)key.channel();

ByteBuffer buffer = ByteBuffer.allocate(10240);
channel.read(buffer);
byte[] data = buffer.array();
String message = new String(data);

System.out.println("recevie message from server:, size:" + buffer.position() + " msg: " + message);
// ByteBuffer outbuffer = ByteBuffer.wrap(("client.".concat(msg)).getBytes());
// channel.write(outbuffer);
}
}
}
}

public static void main(String[] args) throws IOException {
new NioClient().init("127.0.0.1", 12345).listen();
}
}
...全文
717 5 打赏 收藏 转发到动态 举报
写回复
用AI写文章
5 条回复
切换为时间正序
请发表友善的回复…
发表回复
  • 打赏
  • 举报
回复
大神们给我讲解下NIO啊,本人对NIO理解还不是很透彻,现在是根据网上的程序自己写的
  • 打赏
  • 举报
回复
谢谢大家,本人已经解决这个问题。是客户端发送数据问题不对
qingyuan18 2014-11-19
  • 打赏
  • 举报
回复
另外你的程序逻辑搞得过于复杂了,selector是服务端的代码,客户端一般不需要涉及到,ByteBuffer直接在客户端和服务端读写数据用即可,没必要做为SelectorKey的attachment附件,那个主要是为channel管道和Selector关联关系的附加信息作用的
qingyuan18 2014-11-19
  • 打赏
  • 举报
回复
测试了一下,client连接上后服务端发送test数据,客户端收到test数据后返回reply数据,都是全的,没啥问题啊:




你看到数据接收不全是否是因为你的测试数据太长(你原来的程序里面是25000条的字符串,为方便debug我改成5条字符串),你的服务端处理ByteBuffer buf = ByteBuffer.allocate(102400);,25000条字符串超过102400字节了,会分成多个缓冲区片段输出,你看到的就像接收不全了
wyc_ 2014-11-18
  • 打赏
  • 举报
回复
nio还没接触,数据接收不全如果是最后发送的数据接收不全,考虑是不是没有flush或者close,导致数据停留在了缓冲区

50,545

社区成员

发帖
与我相关
我的任务
社区描述
Java相关技术讨论
javaspring bootspring cloud 技术论坛(原bbs)
社区管理员
  • Java相关社区
  • 小虚竹
  • 谙忆
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧