netty SimpleChannelInboundHandler <string> channelRead0仅偶尔被调用

时间:2016-08-24 19:21:49

标签: sockets netty

我知道有几个类似的问题要么得到回答,要么仍然很突出,但对于我的生活......

稍后编辑2016-08-25 10:05 CST - 实际上,我问了错误的问题。

问题如下:鉴于我同时拥有一个netty服务器(取自DiscardServer示例)和一个netty客户端 - (见上文),我必须做些什么来强制DiscardServer立即向客户端发送请求?

我已将OutboundHandler添加到服务器和客户端。

在查看DiscardServer和PingPongServer示例后,会发生外部事件以启动所有操作。在丢弃服务器的情况下,它最初在等待telnet连接,然后将telnet msg中的任何内容传输到客户端。

对于PingPongServer, SERVER 正在等待客户端启动操作。

我想要的是服务器在与客户端连接后立即开始传输。 netty的所有例子都没有这样做。

如果我错过了某些东西,并且有人可以指出它,那就是很好的业力。

我的客户:

public final class P4Listener {
static final Logger LOG;
static final String HOST;
static final int PORT;
static final Boolean SSL = Boolean.FALSE;
public static Dto DTO;

static {
    LOG = LoggerFactory.getLogger(P4Listener.class);
    HOST = P4ListenerProperties.getP4ServerAddress();
    PORT = Integer.valueOf(P4ListenerProperties.getListenerPort());
    DTO = new Dto();
}


public static String getId() { return DTO.getId(); }

public static void main(String[] args) throws Exception {
    final SslContext sslCtx;
    if (SSL) {
        LOG.info("{} creating SslContext", getId());
        sslCtx = SslContextBuilder.forClient().trustManager(InsecureTrustManagerFactory.INSTANCE).build();
    } else {
        sslCtx = null;
    }

    EventLoopGroup group = new NioEventLoopGroup();
    try {
        Bootstrap b = new Bootstrap();
        b.group(group).channel(NioSocketChannel.class)
        .handler(new LoggingHandler(LogLevel.INFO))
        .handler(new P4ListenerInitializer(sslCtx));

        // Start the connection attempt.
        LOG.debug(" {} starting connection attempt...", getId());
        Channel ch = b.connect(HOST, PORT).sync().channel();
//            ChannelFuture localWriteFuture = ch.writeAndFlush("ready\n");
//            localWriteFuture.sync();

    } finally {
        group.shutdownGracefully();
    }
}

}

public class P4ListenerHandler extends SimpleChannelInboundHandler<String> {
static final Logger LOG = LoggerFactory.getLogger(P4ListenerHandler.class);
static final DateTimeFormatter DTFormatter = DateTimeFormatter.ofPattern("yyyyMMdd-HHMMss.SSS");
static final String EndSOT;
static final String StartSOT;
static final String EOL = "\n";
static final ClassPathXmlApplicationContext AppContext;
static {
    EndSOT = P4ListenerProperties.getEndSOT();
    StartSOT = P4ListenerProperties.getStartSOT();
    AppContext = new ClassPathXmlApplicationContext(new String[] { "applicationContext.xml" });
}
private final RequestValidator rv = new RequestValidator();
private JAXBContext jaxbContext = null;
private Unmarshaller jaxbUnmarshaller = null;
private boolean initialized = false;
private Dto dto;
public P4ListenerHandler() {
    dto = new Dto();
}
public Dto getDto() { return dto; }
public String getId() { return getDto().getId(); }
Message convertXmlToMessage(String xml) {
    if (xml == null)
        throw new IllegalArgumentException("xml message is null!");
    try {
        jaxbContext = JAXBContext.newInstance(p4.model.xml.request.Message.class, p4.model.xml.request.Header.class,
                p4.model.xml.request.Claims.class, p4.model.xml.request.Insurance.class,
                p4.model.xml.request.Body.class, p4.model.xml.request.Prescriber.class,
                p4.model.xml.request.PriorAuthorization.class,
                p4.model.xml.request.PriorAuthorizationSupportingDocumentation.class);
        jaxbUnmarshaller = jaxbContext.createUnmarshaller();
        StringReader strReader = new StringReader(xml);
        Message m = (Message) jaxbUnmarshaller.unmarshal(strReader);
        return m;
    } catch (JAXBException jaxbe) {
        String error = StacktraceUtil.getCustomStackTrace(jaxbe);
        LOG.error(error);
        throw new P4XMLUnmarshalException("Problems when attempting to unmarshal transmission string: \n" + xml,
                jaxbe);
    }
}
@Override
public void channelActive(ChannelHandlerContext ctx) {
    LOG.debug("{} let server know we are ready", getId());
    ctx.writeAndFlush("Ready...\n");
}
/**
 * Important - this method will be renamed to
 * <code><b>messageReceived(ChannelHandlerContext, I)</b></code> in netty 5.0
 * 
 * @param ctx
 * @param msg
 */
@Override
protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
    ChannelFuture lastWriteFuture = null;
    LOG.debug("{} -- received message: {}", getId(), msg);
    Channel channel = ctx.channel();
    Message m = null;
    try {
        if (msg instanceof String && msg.length() > 0) {
            m = convertXmlToMessage(msg);
            m.setMessageStr(msg);
            dto.setRequestMsg(m);
            LOG.info("{}: received TIMESTAMP: {}", dto.getId(), LocalDateTime.now().format(DTFormatter));
            LOG.debug("{}: received from server: {}", dto.getId(), msg);

            /*
             * theoretically we have a complete P4(XML) request
             */
            final List<RequestFieldError> errorList = rv.validateMessage(m);
            if (!errorList.isEmpty()) {
                for (RequestFieldError fe : errorList) {
                    lastWriteFuture = channel.writeAndFlush(fe.toString().concat(EOL));
                }
            }

            /*
             * Create DBHandler with message, messageStr, clientIp to get
             * dbResponse
             */
            InetSocketAddress socketAddress = (InetSocketAddress) channel.remoteAddress();
            InetAddress inetaddress = socketAddress.getAddress();
            String clientIp = inetaddress.getHostAddress();

            /*
             * I know - bad form to ask the ApplicationContext for the
             * bean... BUT ...lack of time turns angels into demons
             */
            final P4DbRequestHandler dbHandler = (P4DbRequestHandler) AppContext.getBean("dbRequestHandler");
            // must set the requestDTO for the dbHandler!
            dbHandler.setClientIp(clientIp);
            dbHandler.setRequestDTO(dto);
            //
            // build database request and receive response (string)

            String dbResponse = dbHandler.submitDbRequest();

            /*
             * create ResponseHandler and get back response string
             */
            P4ResponseHandler responseHandler = new P4ResponseHandler(dto, dbHandler);
            String responseStr = responseHandler.decodeDbServiceResponse(dbResponse);
            /*
             * write response string to output and repeat exercise
             */
            LOG.debug("{} -- response to be written back to server:\n {}", dto.getId(), responseStr);
            lastWriteFuture = channel.writeAndFlush(responseStr.concat(EOL));
            //
            LOG.info("{}: response sent TIMESTAMP: {}", dto.getId(), LocalDateTime.now().format(DTFormatter));

        } else {
            throw new P4EventException(dto.getId() + " -- Message received is not a String");
        }
        processWriteFutures(lastWriteFuture);
    } catch (Throwable t) {
        String tError = StacktraceUtil.getCustomStackTrace(t);
        LOG.error(tError);
    } finally {
        if (lastWriteFuture != null) {
            lastWriteFuture.sync();
        }
    }
}
private void processWriteFutures(ChannelFuture writeFuture) throws InterruptedException {
    // Wait until all messages are flushed before closing the channel.
    if (writeFuture != null) {
        writeFuture.sync();
    }
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
    cause.printStackTrace();
    ctx.close();
}
}

/**
 * Creates a newly configured {@link ChannelPipeline} for a new channel.
 */
public class P4ListenerInitializer extends ChannelInitializer<SocketChannel> {
private static final StringDecoder DECODER = new StringDecoder();
private static final StringEncoder ENCODER = new StringEncoder();
private final SslContext sslCtx;
public P4ListenerInitializer(SslContext sslCtx) {
    this.sslCtx = sslCtx;
}
@Override
public void initChannel(SocketChannel ch) {
    P4ListenerHandler lh = null;
    ChannelPipeline pipeline = ch.pipeline();
    if (sslCtx != null) {
        P4Listener.LOG.info("{} -- constructing SslContext new handler ", P4Listener.getId());
        pipeline.addLast(sslCtx.newHandler(ch.alloc(), P4Listener.HOST, P4Listener.PORT));
    } else {
        P4Listener.LOG.info("{} -- SslContext null; bypassing adding sslCtx.newHandler(ch.alloc(), P4Listener.HOST, P4Listener.PORT) ", P4Listener.getId());
    }
    // Add the text line codec combination first,
    pipeline.addLast(new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
    pipeline.addLast(DECODER);
    P4Listener.LOG.debug("{} -- added Decoder ", P4Listener.getId());
    pipeline.addLast(ENCODER);
    P4Listener.LOG.debug("{} -- added Encoder ", P4Listener.getId());
    // and then business logic.
    pipeline.addLast(lh = new P4ListenerHandler());
    P4Listener.LOG.debug("{} -- added P4ListenerHandler: {} ", P4Listener.getId(), lh.getClass().getSimpleName());
}
}

@Sharable
public class P4ListenerOutboundHandler extends ChannelOutboundHandlerAdapter {
static final Logger LOG = LoggerFactory.getLogger(P4ListenerOutboundHandler.class);

private Dto outBoundDTO = new Dto();

public String getId() {return this.outBoundDTO.getId(); }

@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) {
    try {
        ChannelFuture lastWrite = ctx.write(Unpooled.copiedBuffer((String) msg, CharsetUtil.UTF_8));
        try {
            if (lastWrite != null) {
                lastWrite.sync();
                promise.setSuccess();
            }
        } catch (InterruptedException e) {
            promise.setFailure(e);
            e.printStackTrace();
        }
    } finally {
        ReferenceCountUtil.release(msg);
    }

}
}

output from client

1 个答案:

答案 0 :(得分:0)

只需覆盖服务器处理程序上的channelActive(...)并在那里触发写入。