简体   繁体   English

从Netty Nio服务器读取Android(Java)套接字时读取挂起

[英]Android(Java) Socket read hung when reading from a Netty Nio server

I've implement a Netty server with a pipeline like this: 我已经用这样的管道实现了Netty服务器:

 public void initChannel(SocketChannel ch) throws Exception {
     ChannelPipeline p = ch.pipeline();
     p.addLast(new ByteArrayDecoder(), new Byte2MsgHandler()
      , new ByteArrayEncoder(), new Msg2ByteHandler(), new MsgDispatcher());
 }

The business logic is in MsgDispatcher(). 业务逻辑在MsgDispatcher()中。 See below: 见下文:

public void channelRead(ChannelHandlerContext ctx, Object msg)
        throws Exception {
    super.channelRead(ctx, msg);
    Msg message = (Msg) msg;
    switch (message.messageType) {
        case MType.SIGN_UP://sends response to the client
            if (userValidator.validate(message.user)) {
                userReg.signUp(message.user);
            } else {
                Msg error = new Msg.Builder().messageType(MType.ERROR)
                        .errorCode(Constants.USERREG_NULL).build();
                ctx.write(error.toByteArray());// write the response back
                ctx.flush(); //flush the stream
            }
            break;
    }
}

I can succesfully send data to the server with the following code from android: 我可以使用以下来自Android的代码成功将数据发送到服务器:

public void writeAndFlush(Msg msg) throws IOException {
    try {
        bos.write(msg.toByteArray());
        bos.flush();
    } catch (IOException e) {
        throw new IOException("Exception writing and flushing Msg to network.", e);
    }
}

bos is a bufferedOutputstream from the socket. bos是套接字的bufferedOutputstream。

When I close the serversocket after writing I can sucessfully read the data. 写入后关闭服务器插槽时,可以成功读取数据。

Msg error = new Msg.Builder().messageType(MType.ERROR)
                        .errorCode(Constants.USERREG_NULL).build();
                ctx.write(error.toByteArray());// write the response back
                ctx.flush(); //flush the stream
                ctx.close(); //this result in sucessfull read on android socket.

But (without "ctx.close() in the above server code"), it hungs in the while loop(code below): 但是(没有上面的服务器代码中的“ ctx.close()”),它挂在while循环中(下面的代码):

public Msg read() throws IOException {
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    byte[] buffer = new byte[1024];
    int read = 0;
    try {
        while ((read = bis.read(buffer, 0, buffer.length)) != -1) {
            Log.e("com.traderreg", "" + read);
            baos.write(buffer, 0, read);
        }
        baos.flush();
    } catch (IOException e) {
        throw new IOException("error reading bytes from socket", e);
    }
    try {
        return wire.parseFrom(baos.toByteArray(), Msg.class);
    }catch (IOException e){
        throw new IOException("error parsing Msg from socket", e);
    }
}

What is the problem? 问题是什么?

bis.read() will block until there are bytes available, or the stream is closed. bis.read()将阻塞,直到有可用字节或流关闭为止。 This is why closing the socket causes read() to return. 这就是为什么关闭套接字导致read()返回的原因。 If you want to read in a non-blocking manner then you need to take a look at the classes in the java.nio.channels package. 如果要以非阻塞方式阅读,则需要查看java.nio.channels包中的类。 However, you don't really want to be continuously polling for data. 但是,您实际上并不希望连续轮询数据。 The classes in java.nio.channels are really designed for handling multiple sockets within a single thread rather than encouraging polling of the socket (although I'm aware that games sometimes poll a socket as part of their game loop). java.nio.channels中的类实际上是为处理单个线程中的多个套接字而设计的,而不是鼓励对套接字进行轮询(尽管我知道游戏有时会在其游戏循环中轮询套接字)。

Regardless of whether you're working with blocking or non-blocking I/O you need some method of delimiting messages. 无论您是使用阻塞I / O还是非阻塞I / O,都需要某种分隔消息的方法。 The suggestion to prepend each message with a length field is a simple, but effective solution. 建议在每个消息前添加一个length字段,这是一种简单但有效的解决方案。 Then your thread loops continuously reading messages and dispatching them to code that can process them. 然后,您的线程不断循环读取消息并将其分派到可以对其进行处理的代码。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM