Java SocketChannel write()返回时没有错误,但没有实际发送数据

Java SocketChannel write()返回时没有错误,但没有实际发送数据,java,sockets,nio,socketchannel,Java,Sockets,Nio,Socketchannel,我正在使用SocketChannel与远程服务器通信。我使用socketChannel.write()发送数据,没有错误和异常,但是,服务器日志表明没有收到任何数据;客户端tcp流量监视器还显示ByteBuffer中的字符串消息未发送 谁能给我一个提示为什么会这样?谢谢大家! public class Client implements Runnable { SocketChannel socketChannel; Selector selector; Selection

我正在使用SocketChannel与远程服务器通信。我使用socketChannel.write()发送数据,没有错误和异常,但是,服务器日志表明没有收到任何数据;客户端tcp流量监视器还显示ByteBuffer中的字符串消息未发送

谁能给我一个提示为什么会这样?谢谢大家!

public class Client implements Runnable {
    SocketChannel socketChannel;
    Selector selector;
    SelectionKey key;
    ByteBuffer inbuf, outbuf;
    int id;
    @Override
    public void run() {
    try {
        // prepare inbuf and outbuf
        inbuf = ByteBuffer.allocate(10000);
        outbuf = ByteBuffer.allocate(10000);

        // prepare a socket channel for communication
        socketChannel = SocketChannel.open();
        socketChannel.connect(new InetSocketAddress("<remote server ip>", ));
        selector = Selector.open();
        socketChannel.configureBlocking(false);
        key = socketChannel.register(selector, SelectionKey.OP_READ
                | SelectionKey.OP_WRITE);

        while (selector.select() > 0) {

            if (key.isReadable()) {
                // read from channel when server sends data
                read();
            }

            if (key.isWritable()) {
                // write
                Random r = new Random(500);
                write("b", r.nextInt(), r.nextInt());
                for (int i = 0; i < 10; i++) {
                    // write a message to server after 1 second
                    Thread.sleep(1000);
                    write("m", r.nextInt(), r.nextInt());
                }
                write("e", r.nextInt(), r.nextInt());
            }
        }
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

}

private void write(String action, int x, int y) throws IOException {
    String msg = String.format("%s:%d:%d:%d", action, id, x, y);
    int r=outbuf.remaining();

    outbuf.put(msg.getBytes());
    int rBytes = outbuf.remaining();
    boolean connected = socketChannel.isConnected();
    Socket sock = socketChannel.socket();

    if (connected && sock.isConnected() && !sock.isOutputShutdown())
>>>>>>>>>>    socketChannel.write(outbuf);
    else
        System.out.println("Connection broken!");

    System.out.printf("Client %d told server:%s\n", id, msg);
    //outbuf.clear();
}

   ... //read omitted here
公共类客户端实现可运行{
SocketChannel SocketChannel;
选择器;
选择键;
ByteBuffer inbuf,Exputf;
int-id;
@凌驾
公开募捐{
试一试{
//准备inbuf和extuf
inbuf=字节缓冲分配(10000);
exputf=字节缓冲分配(10000);
//为通信准备一个套接字通道
socketChannel=socketChannel.open();
连接(新的InetSocketAddress(“,”);
选择器=selector.open();
socketChannel.configureBlocking(假);
key=socketChannel.register(选择器,SelectionKey.OP_读取
|选择键。操作(写入);
while(selector.select()>0){
if(key.isReadable()){
//服务器发送数据时从通道读取数据
read();
}
if(key.isWritable()){
//写
随机r=新随机数(500);
写(“b”,r.nextInt(),r.nextInt());
对于(int i=0;i<10;i++){
//在1秒后将消息写入服务器
睡眠(1000);
写(“m”,r.nextInt(),r.nextInt());
}
写(“e”,r.nextInt(),r.nextInt());
}
}
}捕获(IOE异常){
//TODO自动生成的捕捉块
e、 printStackTrace();
}捕捉(中断异常e){
//TODO自动生成的捕捉块
e、 printStackTrace();
}
}
私有void write(字符串操作,int x,int y)引发IOException{
String msg=String.format(“%s:%d:%d:%d”,操作,id,x,y);
int r=exputf.remaining();
put(msg.getBytes());
int rBytes=exputf.remaining();
布尔连接=socketChannel.isConnected();
Socket sock=socketChannel.Socket();
if(已连接&&sock.isConnected()&&sock.isOutputShutdown())
>>>>>>>>>>socketChannel.write(extuf);
其他的
System.out.println(“连接中断!”);
System.out.printf(“客户端%d告诉服务器:%s\n”,id,msg);
//exputf.clear();
}
…//此处省略

将内容放入缓冲区或将内容读入缓冲区后,必须翻转缓冲区才能写入或从中获取数据。请检查Buffer类中的
flip()
方法。文档中说

翻转此缓冲区。将限制设置为当前位置,然后将该位置设置为零。如果定义了标记,则将其丢弃。 在一系列通道读取或put操作之后,调用此方法以准备一系列通道写入或相对get操作


因此,在put之后添加buffer.flip()应该可以做到这一点:)

在将内容放入缓冲区或将内容读入缓冲区后,您必须翻转缓冲区以写入或从中获取数据。检查buffer类中的
flip()
方法。文档说

翻转此缓冲区。将限制设置为当前位置,然后将该位置设置为零。如果定义了标记,则将其丢弃。 在一系列通道读取或put操作之后,调用此方法以准备一系列通道写入或相对get操作


因此,在put之后添加一个buffer.flip()应该可以做到这一点:)

您是否翻转了ByteBuffer?编辑:不,您没有……我正在写答案。谢谢!Hi@EJP,你能看一下我问的另一个问题吗?谢谢。你翻了吗编辑:不,你没有……我正在写答案。谢谢!Hi@EJP,你能看一下我问的另一个问题吗?谢谢你。+1并且不要忽略
write()返回的值.
在这种情况下它应该是零,这应该会触发警钟。谢谢@xp500,它可以工作!我确实读到ByteBuffer或Buffer类通常可以在读和写模式之间“翻转”。既然可以工作,这是否意味着我在ByteBuffer中“放入”一些字节后,SocketChannel write()方法将实际读取缓冲区并通过套接字的outputStream写入它?Thanks@EJP,谢谢你的提示!@user798637检查文档中的buffer类。它定义了3个属性:limit、position和capacity。我假设write方法以某种方式迭代缓冲区(可能使用haslaining()方法)然后将其写入流。这就是你要问的吗?@xp500,是的,谢谢。如果你不介意我在这里问另一个相关问题,而不启动新线程,那么这里就是:现在在“翻转”缓冲区后,流量监视器指示我的数据已发送,但服务器似乎确实收到了,因为我的服务器具有非常简单的逻辑,而呃,它得到了一些东西,它只是将它回显到所有其他连接的客户端(广播),我用nc命令测试了我的服务器,它正常工作。所以我想知道这里还有什么问题。+1并且不要忽略
write()返回的值.
在这种情况下它应该是零,这应该会触发警钟。谢谢@xp500,它可以工作!我确实读到ByteBuffer或Buffer类通常可以在读和写模式之间“翻转”。既然可以工作,这是否意味着我在ByteBuffer中“放入”一些字节后,SocketChannel write()方法将实际读取缓冲区并通过套接字的outputStream写入它?Thanks@EJP,谢谢你的提示!@user798637检查文档中的buffer类。它定义了3个属性:limit、position和capacity。我假设write方法以某种方式迭代缓冲区(可能是