通过java.nio通道发送字符串无法正常工作

时间:2013-02-25 19:57:23

标签: java sockets io nio

这是我尝试过的:

服务器:

import java.net.InetSocketAddress;
import java.nio.*;
import java.nio.channels.*;
import java.nio.charset.*;

public class JavaApplication12 {
    public static void main(String[] args) throws Exception{
    Charset charset = Charset.forName("ISO-8859-1");
    ServerSocketChannel s = ServerSocketChannel.open();
    s.configureBlocking(true);
    s.socket().bind(new InetSocketAddress(1024));
    CharBuffer c = CharBuffer.wrap("Hello from server!");
    System.out.println("writing " + c);
    ByteBuffer b = charset.encode(c);
    SocketChannel sc = s.accept();
    sc.configureBlocking(true);
    b.flip();
    int a = sc.write(b);
    sc.close();
    s.close();
    System.out.println("wrote " + a);
}
}

客户端:

import java.net.InetSocketAddress;
import java.nio.*;
import java.nio.channels.*;
import java.nio.charset.*;

public class JavaApplication11 {

    public static void main(String[] args) throws Exception {
    Charset charset = Charset.forName("ISO-8859-1");
    SocketChannel sc = SocketChannel.open(new InetSocketAddress("127.0.0.1", 1024));
    sc.configureBlocking(true);
    ByteBuffer b = ByteBuffer.allocate(32);
    b.flip();
    int a = sc.read(b);
    sc.close();
    b.flip();
    CharBuffer c = charset.decode(b);
    c.flip();
    System.out.println("Got " + c);
    System.out.println("read " + a );
}
}

另一边似乎只是得到一个非常长而空的字符串,我无法弄清楚我做错了什么。

更新:我更新了我的代码,发现服务器正在写0个字节。有些字节要写,那么为什么不sc.write()写任何东西?

更新2 :在Vishal的帮助下,我们终于找到了一个有效的解决方案:

服务器:

Charset charset = Charset.forName("ISO-8859-1");
ServerSocketChannel s = ServerSocketChannel.open();
s.configureBlocking(true);
s.socket().bind(new InetSocketAddress(1024));
CharBuffer c = CharBuffer.wrap("Hello from server!");
ByteBuffer b = charset.encode(c);
SocketChannel sc = s.accept();
sc.configureBlocking(true);
b.compact();
b.flip();
int a = sc.write(b);
sc.close();
s.close();
System.out.println("wrote " + a);

客户端:

Charset charset = Charset.forName("ISO-8859-1");
SocketChannel sc = SocketChannel.open(new InetSocketAddress("127.0.0.1", 1024));
sc.configureBlocking(true);
ByteBuffer b = ByteBuffer.allocate(32);
int a = sc.read(b);
sc.close();
b.flip();
CharBuffer c = charset.decode(b);
System.out.println("Got " + c);

1 个答案:

答案 0 :(得分:3)

  

Buffer.flip() 方法切换缓冲区   模式到阅读模式。致电flip()会将 职位 设置为0,然后   将 限制 设置为位置。
  即 位置 现在标记阅读位置, 限制   标记有多少字节,字符等写入缓冲区 -   限制可以读取多少字节,字符等

如果您看到Buffer.flip()的文档,则说明:

  

在一系列频道阅读或 put操作之后,调用此方法   准备一系列通道写入或相对获取操作。

进一步指出:

  

此方法通常与compact方法结合使用   将数据从一个地方传输到另一个地方。

在您的情况下,put操作不会用于创建ByteBuffer。因此,在调用翻转之前,您必须调用compact方法。

ByteBuffer's compact()方法保留:

  

缓冲区当前位置与其限制之间的字节(如果有)   被复制到缓冲区的开头。也就是索引处的字节   p = position()被复制到索引0,索引p + 1处的字节是   复制到索引1,依此类推,直到索引limit() - 1处的字节   被复制到索引n = limit() - 1 - p。然后缓冲区的位置   设置为n + 1,其限制设置为其容量。标记,如果定义,   被丢弃了。

     

缓冲区的位置设置为复制的字节数   而不是为零,以便可以遵循此方法的调用   立即通过调用另一个相对put方法。   在写入不完整的情况下从缓冲区写入数据后调用此方法。

在服务器端的代码中调用flip()之前,位置本身为0。因此,要将position设置为写入b的数字字节,您必须在调用compact()之前调用b.flip()方法,以便b.flip()设置limit 1}}到前一个position,这是写入ByteBuffer的字节数,并将position设置为0

因此,您的服务器代码应如下所示:

import java.net.InetSocketAddress;
import java.nio.*;
import java.nio.channels.*;
import java.nio.charset.*;

public class JavaApplication12 {
    public static void main(String[] args) throws Exception{
    Charset charset = Charset.forName("ISO-8859-1");
    ServerSocketChannel s = ServerSocketChannel.open();
    s.configureBlocking(true);
    s.socket().bind(new InetSocketAddress(1024));

    CharBuffer c = CharBuffer.wrap("Hello from server!");
    System.out.println("writing " + c);
    ByteBuffer b = charset.encode(c);
    System.out.println(new String(b.array()));
    SocketChannel sc = s.accept();
    //sc.configureBlocking(true);
    b.compact();
    System.out.println(b.capacity() + " "+ b.position() + " " + b.limit());
    b.flip();
    System.out.println(b.capacity() + " "+ b.position() + " " + b.limit());
    int a = 0;
    while (b.hasRemaining())
    {
        a += sc.write(b);
    }

    sc.close();
    s.close();
    System.out.println("wrote " + a);
    }
} 

LikeWise,在客户端,您的代码应该是这样的:

import java.net.InetSocketAddress;
import java.nio.*;
import java.nio.channels.*;
import java.nio.charset.*;

public class JavaApplication11 {
    public static void main(String[] args) throws Exception {
    Charset charset = Charset.forName("ISO-8859-1");
    SocketChannel sc = SocketChannel.open(new InetSocketAddress("127.0.0.1", 1024));
    sc.configureBlocking(true);
    ByteBuffer b = ByteBuffer.allocate(32);
    //b.flip();//Don't flip the ByteBuffer here because it sets the position to 0 and limit to 0 also. Hence no read.
    int a = sc.read(b);
    sc.close();
    b.flip();//sets the Position to 0 and limit to the number of bytes to be read.
    CharBuffer c = charset.decode(b);
    //c.flip();//Don't flip the ChharBuffer. Because it is setting the position to zero and limit to previous position i.e zero
    System.out.println("Got " + c);
    System.out.println("read " + a );
    }
}
  

注意:我已对您犯错的行发表评论。