2

这是我尝试过的:

服务器:

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);
4

2 回答 2

3

Buffer.flip()方法将 Buffer 从写入模式切换到读取模式。调用flip()位置设置回 0,并将限制设置为位置刚刚的位置。
位置现在标记读取位置,限制 标记有多少字节,字符等写入缓冲区 - 可以读取多少字节,字符等的限制

如果您在文档中看到Buffer.flip()它指出:

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

并且进一步指出:

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

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

ByteBuffer's compact()方法保持:

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

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

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

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

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 );
    }
}

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

于 2013-02-25T20:39:25.520 回答
0

您需要在 read() 和 decode() 之间翻转()缓冲区。

于 2013-02-25T22:08:18.977 回答