现在只写到客户端发一句话,服务器收到在发回给客户端,先客户端得到要发送的字节大小,先发给服务器,在发送实际数据。服务器先收到字节大小,然后准备一个对应大小的ByteBuffer来接收后面的数据,在把收到的字节大小跟数据发给客户端。客户端也跟服务器一样先接收字节大小,准备ByteBuffer接收,然后显示出来。现在是服务器接收没有问题,但客户端接收有问题
//这里是客户端发送数据
                           String s = enter.getText();
byte[] bs = s.getBytes();
int i = bs.length;
len.clear();
len.put(Parse.intToByte(i));
len.flip();
write = ByteBuffer.allocate(i);
write.clear();
write.put(s.getBytes());
write.flip();
try 
{
socket.write(len);
socket.write(write);

catch (IOException e1) 
{
e1.printStackTrace();
}
enter.setText("");
write = null;//服务器接收和发送数据
socket = (SocketChannel)key.channel();
len.clear();
socket.read(len);
len.flip();
int i = Parse.byteToInt(len.array());
read = ByteBuffer.allocate(i);
read.clear();
socket.read(read);
read.flip();
socket.write(len);
socket.write(read);
read = null;//客户端接收数据,就这里出java.lang.OutOfMemoryError。有时候出有时候不出
readSocket = (SocketChannel)reader.attachment();
len.clear();
readSocket.read(len);
len.flip();
int i = Parse.byteToInt(len.array());
                                                       //不知道怎么回事他把len读了两次,
                                                       //第二次i的值就会很大,下面这句就报错,而且用debug跟就
                                                       //不报错。
read = ByteBuffer.allocate(i);
read.clear();
readSocket.read(read);
read.flip();
String s = new String(read.array());
show.append(s + "\n");
read = null;
是不是我写的有问题???下面是全部的代码serverimport java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;public class Server 
{
private Selector sel;
private ServerSocketChannel server;
private int port;
private ByteBuffer len = ByteBuffer.allocate(4);
private ByteBuffer read;

public static void main(String[] args)
{
Server s = new Server(9999);
}

public Server(int port)
{
this.port = port;
try 
{
sel = Selector.open();
server = ServerSocketChannel.open();
server.configureBlocking(false);
server.socket().bind(new InetSocketAddress(this.port));
server.register(sel, SelectionKey.OP_ACCEPT);
System.out.println("服务器启动!");

while(sel.select() > 0)
{
Set<SelectionKey> keys = sel.selectedKeys();
Iterator<SelectionKey> its = keys.iterator();
while(its.hasNext())
{
SelectionKey key = its.next();
its.remove();
SocketChannel socket = null;

if(key.isAcceptable())
{
ServerSocketChannel serverSocket = (ServerSocketChannel)key.channel();
socket = serverSocket.accept();
System.out.println("有一个用户连接!");
socket.configureBlocking(false);
SelectionKey sk = socket.register(sel, SelectionKey.OP_READ);
}
else if(key.isReadable())
{
socket = (SocketChannel)key.channel();
len.clear();
socket.read(len);
len.flip();
int i = Parse.byteToInt(len.array());
read = ByteBuffer.allocate(i);
read.clear();
socket.read(read);
read.flip();
socket.write(len);
socket.write(read);
read = null;
}

}
}

catch (ClosedChannelException e) 
{
e.printStackTrace();

catch (IOException e) 
{
e.printStackTrace();
}
}

public void finalize()
{

try 
{
if(sel != null)
{
sel.close();
sel = null;
}
if(server != null)
{
server.close();
server = null;
}

catch (IOException e) 
{
e.printStackTrace();
}
}
}clientimport java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
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;
import java.util.Set;import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.border.LineBorder;public class Client extends JFrame 
{

JTextField enter;
JTextArea show;
JTextArea user;
JLabel l;

SocketChannel socket;
Selector sel;
ByteBuffer len = ByteBuffer.allocate(4);
ByteBuffer write;
ByteBuffer read;
SelectionKey reader;
boolean b = false;

public static void main(String[] args) 
{
Client c = new Client();
c.setVisible(true);
c.init();
c.read();

}

public Client()
{
show = new JTextArea();
show.setEditable(false);
show.setBounds(0, 0, 560, 500);
show.setBorder(new LineBorder(new Color(234, 201, 222)));
l = new JLabel("输入内容");
l.setBounds(0, 510, 60, 30);
enter = new JTextField();
enter.setBounds(60, 510, 500, 30);
user = new JTextArea();
user.setEditable(false);
user.setBounds(562, 2, 128, 540);
user.setBorder(new LineBorder(new Color(188, 230, 235)));
this.setBounds(100, 50, 700, 570);
this.setLayout(null);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
enter.addActionListener(new Monitor());
this.add(show);
this.add(l);
this.add(enter);
this.add(user);
this.setResizable(false);
}

public void init()
{
try 
{
sel = Selector.open();
socket = SocketChannel.open(new InetSocketAddress("127.0.0.1", 9999));
socket.configureBlocking(false);
reader = socket.register(sel, SelectionKey.OP_READ);
reader.attach(socket);
b = true;
}
catch (IOException e) 
{
e.printStackTrace();
}
}

public void read()
{
Set<SelectionKey> keys = null;

try 
{
while(b)
{
sel.select();
keys = sel.selectedKeys();
Iterator<SelectionKey> its = keys.iterator();
while(its.hasNext())
{
SelectionKey key = its.next();
SocketChannel readSocket = null;
if(key.isReadable())
{
readSocket = (SocketChannel)reader.attachment();
len.clear();
readSocket.read(len);
len.flip();
int i = Parse.byteToInt(len.array());
read = ByteBuffer.allocate(i);
read.clear();
readSocket.read(read);
read.flip();
String s = new String(read.array());
show.append(s + "\n");
read = null;
}
}
}

catch (IOException e) 
{
e.printStackTrace();
}
} private class Monitor implements ActionListener
{ @Override
public void actionPerformed(ActionEvent e) 
{
String s = enter.getText();
byte[] bs = s.getBytes();
int i = bs.length;
len.clear();
len.put(Parse.intToByte(i));
len.flip();
write = ByteBuffer.allocate(i);
write.clear();
write.put(s.getBytes());
write.flip();
try 
{
socket.write(len);
socket.write(write);

catch (IOException e1) 
{
e1.printStackTrace();
}
enter.setText("");
write = null;
}

}
}

解决方案 »

  1.   

    楼主既然用的是定长传输协议,就应该每次读足长度,否则后面就会错位。代码如下:while(len.hasRemaining()) readSocket.read(len);
    while(read.hasRemaining()) readSocket.read(read);
      

  2.   

    //read(len)试图读4个字节,但可能因为网络原因读不到4个就返回了
    while(len.hasRemaining()) readSocket.read(len); //如果不足4个(缓冲不满),就再读,直至读满
      

  3.   

    原来如此.如果我不先说明要发的数据大小,而直接用一个大点的ByteBuffer来接收数据,如果第二次发的数据比第一次的小,那么第一次多出来的数据就会跟在第二次的后面应该怎么办?
    比如:
    第一次发:大家好
    第二次发:你好
    第二次就会发:你好好
    我怎么清空buffer里面的数据?
      

  4.   

    read前clear,
    write前flip,
    应该就可以了。
      

  5.   

    这样好像不行,flip还是会把原来的数据也算到里面。