2017-09-04 4 views
0

J'essaye d'utiliser Netty et Protocol Buffers (et le chiffrement mais cela n'affecte pas ce problème). Le serveur est écrit en Java en utilisant Netty et les clients sont censés être écrits en C et en Java. Voici le code du serveur Java.Netty + Protocol Buffers Java <-> Problème de communication C

classe Application:

@SpringBootApplication 
public class Application { 

public static void main(String[] args) throws InterruptedException { 
    ConfigurableApplicationContext context = SpringApplication.run(Application.class, args); 
    TcpServer tcpServer = context.getBean(TcpServer.class); 
    tcpServer.start(); 
} 

@Autowired 
private SomethingChannelInitializer somethingChannelInitializer; 

@SuppressWarnings({ "unchecked", "rawtypes" }) 
@Bean 
public ServerBootstrap bootstrap() { 
    ServerBootstrap b = new ServerBootstrap(); 
    b.group(bossGroup(), workerGroup()).channel(NioServerSocketChannel.class) 
      .handler(new LoggingHandler(LogLevel.DEBUG)).childHandler(somethingChannelInitializer); 
    Map<ChannelOption<?>, Object> tcpChannelOptions = tcpChannelOptions(); 
    Set<ChannelOption<?>> keySet = tcpChannelOptions.keySet(); 
    for (ChannelOption option : keySet) { 
     b.option(option, tcpChannelOptions.get(option)); 
    } 
    return b; 
} 

@Bean(name = "tcpChannelOptions") 
public Map<ChannelOption<?>, Object> tcpChannelOptions() { 
    Map<ChannelOption<?>, Object> options = new HashMap<ChannelOption<?>, Object>(); 
    options.put(ChannelOption.SO_KEEPALIVE, true); 
    options.put(ChannelOption.SO_BACKLOG, 3); 
    return options; 
} 

@Bean(destroyMethod = "shutdownGracefully") 
public NioEventLoopGroup bossGroup() { 
    return new NioEventLoopGroup(2); 
} 

@Bean(destroyMethod = "shutdownGracefully") 
public NioEventLoopGroup workerGroup() { 
    return new NioEventLoopGroup(2); 
} 

@Bean 
public InetSocketAddress tcpPort() { 
    return new InetSocketAddress(12888); 
} 
} 

classe SomethingChannelInitializer:

@Component 
public class SomethingChannelInitializer extends ChannelInitializer<SocketChannel> { 

@Autowired 
private ChannelInboundHandlerAdapter somethingServerHandler; 

@Override 
protected void initChannel(SocketChannel socketChannel) throws Exception { 
    ChannelPipeline pipeline = socketChannel.pipeline(); 

    // SSL stuff 

    pipeline.addLast(new ProtobufVarint32FrameDecoder()); 
    pipeline.addLast(new ProtobufDecoder(ProtocolMessage.OneRequest.getDefaultInstance())); 

    pipeline.addLast(new ProtobufVarint32LengthFieldPrepender()); 
    pipeline.addLast(new ProtobufEncoder()); 

    pipeline.addLast(somethingServerHandler); 
} 

} 

classe SomethingServerHandler:

@Component 
@Sharable 
public class SomethingServerHandler extends ChannelInboundHandlerAdapter { 

private static Logger logger = LoggerFactory.getLogger(SomethingServerHandler.class); 

@Override 
public void channelActive(ChannelHandlerContext ctx) throws Exception { 

} 

@Override 
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { 
    logger.debug("read ..."); 
    ProtocolMessage.OneRequest req = (ProtocolMessage.OneRequest) msg; 
    switch (req.getType()) { 
    case LOGIN: 
     logger.debug("{}, {}", req.getLoginRequest().getLogin(), req.getLoginRequest().getPassword()); 
     break; 
    case REGISTER: 
     logger.debug("{}, {}", req.getRegistrationRequest().getEmail(), req.getRegistrationRequest().getPassword()); 
     break; 
    default: 
     break; 
    } 

    ProtocolMessage.RegistrationResponse registrationResponse = ProtocolMessage.RegistrationResponse.newBuilder().setStatus("got it").build(); 
    ProtocolMessage.OneResponse rsp = ProtocolMessage.OneResponse.newBuilder().setRegistrationResponse(registrationResponse).build(); 
    ctx.writeAndFlush(rsp); 
} 

@Override 
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { 
    logger.error(cause.getMessage(), cause); 
    //ctx.close(); 
} 

@Override 
public void channelInactive(ChannelHandlerContext ctx){ 

} 
} 

ProtocolMessage.proto:

package com.company.model; 

message LoginRequest { 
    required string login = 1; 
    required string password = 2; 
} 

message RegistrationRequest { 
    required string login = 1; 
    required string email = 2; 
    required string password = 3; 
} 

message RegistrationResponse { 
    required string status = 1; 
} 

message OneRequest { 
    enum Type { LOGIN = 1; REGISTER = 2; } 

    required Type type = 1; 
    oneof request { 
    LoginRequest loginRequest = 2; 
    RegistrationRequest registrationRequest = 3; 
    } 
} 

message OneResponse { 
    oneof response { 
    RegistrationResponse registrationResponse = 1; 
    } 
} 

client C:

#include <stdio.h> 
#include <sys/types.h> 
#include <sys/socket.h> 
#include <netinet/in.h> 
#include <netdb.h> 
#include <unistd.h> 
#include <string.h> 
#include <openssl/ssl.h> 
#include <openssl/err.h> 

#include "ProtocolMessage.pb-c.h" 

#define HERR(source) (fprintf(stderr,"%s(%d) at %s:%d\n",source,h_errno,__FILE__,__LINE__),\ 
     exit(EXIT_FAILURE)) 

int main(int argc, char **argv) { 
// SSL initialization, making new connection etc. 

Com__Company__Model__LoginRequest login = COM__COMPANY__MODEL__LOGIN_REQUEST__INIT; 
login.login="sample_login"; 
login.password="secret_password"; 
Com__Company__Model__OneRequest req = COM__COMPANY__MODEL__ONE_REQUEST__INIT; 
req.loginrequest=&login; 
req.type=COM__COMPANY__MODEL__ONE_REQUEST__TYPE__LOGIN; 

unsigned len = com__company__model__one_request__get_packed_size(&req); 
void *buf = malloc(len); 
com__company__model__one_request__pack(&req, buf); 

SSL_write(clientssl, buf, len); 
printf("SSL server sent %d\n", len); 
SSL_shutdown(clientssl); 
close(clientsocketfd); 
SSL_free(clientssl); 
SSL_CTX_free(ssl_client_ctx); 
return 0; 
} 

journal du serveur:

2017-09-04 18:14:37.209 DEBUG 63166 --- [ntLoopGroup-3-1] io.netty.handler.ssl.SslHandler   : [id: 0x445a7c98, L:/127.0.0.1:12888 - R:/127.0.0.1:50688] HANDSHAKEN: TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 
2017-09-04 18:14:37.218 ERROR 63166 --- [ntLoopGroup-3-1] p.o.g.handlers.SomethingServerHandler : com.google.protobuf.InvalidProtocolBufferException: Protocol message contained an invalid tag (zero). 

io.netty.handler.codec.DecoderException: com.google.protobuf.InvalidProtocolBufferException: Protocol message contained an invalid tag (zero). 
    at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:98) ~[netty-all-4.1.13.Final.jar!/:4.1.13.Final] 
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362) [netty-all-4.1.13.Final.jar!/:4.1.13.Final] 
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348) [netty-all-4.1.13.Final.jar!/:4.1.13.Final] 
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340) [netty-all-4.1.13.Final.jar!/:4.1.13.Final] 
    at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:310) [netty-all-4.1.13.Final.jar!/:4.1.13.Final] 
    at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:297) [netty-all-4.1.13.Final.jar!/:4.1.13.Final] 
    at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:413) [netty-all-4.1.13.Final.jar!/:4.1.13.Final] 
    at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:265) [netty-all-4.1.13.Final.jar!/:4.1.13.Final] 
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362) [netty-all-4.1.13.Final.jar!/:4.1.13.Final] 
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348) [netty-all-4.1.13.Final.jar!/:4.1.13.Final] 
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340) [netty-all-4.1.13.Final.jar!/:4.1.13.Final] 
    at io.netty.handler.ssl.SslHandler.unwrap(SslHandler.java:1273) [netty-all-4.1.13.Final.jar!/:4.1.13.Final] 
    at io.netty.handler.ssl.SslHandler.decode(SslHandler.java:1084) [netty-all-4.1.13.Final.jar!/:4.1.13.Final] 
    at io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:489) [netty-all-4.1.13.Final.jar!/:4.1.13.Final] 
    at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:428) [netty-all-4.1.13.Final.jar!/:4.1.13.Final] 
    at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:265) [netty-all-4.1.13.Final.jar!/:4.1.13.Final] 
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362) [netty-all-4.1.13.Final.jar!/:4.1.13.Final] 
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348) [netty-all-4.1.13.Final.jar!/:4.1.13.Final] 
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340) [netty-all-4.1.13.Final.jar!/:4.1.13.Final] 
    at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1334) [netty-all-4.1.13.Final.jar!/:4.1.13.Final] 
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362) [netty-all-4.1.13.Final.jar!/:4.1.13.Final] 
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348) [netty-all-4.1.13.Final.jar!/:4.1.13.Final] 
    at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:926) [netty-all-4.1.13.Final.jar!/:4.1.13.Final] 
    at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:134) [netty-all-4.1.13.Final.jar!/:4.1.13.Final] 
    at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:644) [netty-all-4.1.13.Final.jar!/:4.1.13.Final] 
    at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:579) [netty-all-4.1.13.Final.jar!/:4.1.13.Final] 
    at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:496) [netty-all-4.1.13.Final.jar!/:4.1.13.Final] 
    at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:458) [netty-all-4.1.13.Final.jar!/:4.1.13.Final] 
    at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:858) [netty-all-4.1.13.Final.jar!/:4.1.13.Final] 
    at io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:138) [netty-all-4.1.13.Final.jar!/:4.1.13.Final] 
    at java.lang.Thread.run(Thread.java:745) [na:1.8.0_91] 

Caused by: com.google.protobuf.InvalidProtocolBufferException: Protocol message contained an invalid tag (zero). 
    at com.google.protobuf.InvalidProtocolBufferException.invalidTag(InvalidProtocolBufferException.java:89) ~[protobuf-java-2.6.1.jar!/:na] 
    at com.google.protobuf.CodedInputStream.readTag(CodedInputStream.java:158) ~[protobuf-java-2.6.1.jar!/:na] 
    at com.company.model.ProtocolMessage$OneRequest.<init>(ProtocolMessage.java:2037) ~[classes!/:0.0.1-SNAPSHOT] 
    at com.company.model.ProtocolMessage$OneRequest.<init>(ProtocolMessage.java:2000) ~[classes!/:0.0.1-SNAPSHOT] 
    at com.company.model.ProtocolMessage$OneRequest$1.parsePartialFrom(ProtocolMessage.java:2116) ~[classes!/:0.0.1-SNAPSHOT] 
    at com.company.model.ProtocolMessage$OneRequest$1.parsePartialFrom(ProtocolMessage.java:2111) ~[classes!/:0.0.1-SNAPSHOT] 
    at com.google.protobuf.AbstractParser.parsePartialFrom(AbstractParser.java:137) ~[protobuf-java-2.6.1.jar!/:na] 
    at com.google.protobuf.AbstractParser.parseFrom(AbstractParser.java:168) ~[protobuf-java-2.6.1.jar!/:na] 
    at com.google.protobuf.AbstractParser.parseFrom(AbstractParser.java:174) ~[protobuf-java-2.6.1.jar!/:na] 
    at com.google.protobuf.AbstractParser.parseFrom(AbstractParser.java:49) ~[protobuf-java-2.6.1.jar!/:na] 
    at io.netty.handler.codec.protobuf.ProtobufDecoder.decode(ProtobufDecoder.java:121) ~[netty-all-4.1.13.Final.jar!/:4.1.13.Final] 
    at io.netty.handler.codec.protobuf.ProtobufDecoder.decode(ProtobufDecoder.java:64) ~[netty-all-4.1.13.Final.jar!/:4.1.13.Final] 
    at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:88) ~[netty-all-4.1.13.Final.jar!/:4.1.13.Final] 
    ... 30 common frames omitted 

protobuf-java 2.6.1
protobuf-c 1.0.2
libprotoc 2.6.1

En gros, cela est un exemple de code pris sur le net et modifié un peu. Ne regardez pas les valeurs codées en dur ou d'autres imperfections. Ceci est seulement à des fins d'apprentissage. Je peux communiquer avec le serveur en utilisant le client Java sans aucun problème. Toutefois, lorsque j'essaie d'envoyer le même message à partir du client C, le serveur envoie immédiatement une exception. J'ai lu quelque chose à propos de la délimitation, mais je ne suis pas sûr de savoir comment gérer cela. J'ai également essayé d'envoyer la longueur d'un message en tant que int d'abord, puis le message réel du client C mais cela n'aide pas non plus. Le cryptage n'est pas un problème ici. Si je le désactive, j'obtiendrai les mêmes résultats.

Qu'est-ce qui me manque ici? Est-ce possible de communiquer avec les clients C?

+0

Avez-vous analysé le trafic réseau? Avec des outils comme 'wireshark'? Juste pour obtenir un indice de quel côté chercher le problème. – blafasel

Répondre

0

Essayez d'utiliser LengthFieldBasedFrameDecoder au lieu de ProtobufVarint32FrameDecoder, et envoyer package lengh premier:

void *buf = malloc(len); 

// send package len 
buf[0] = (len >> 24) & 0xFF; 
buf[1] = (len >> 16) & 0xFF; 
buf[2] = (len >> 8) & 0xFF; 
buf[3] = len & 0xFF; 
SSL_write(clientssl, buf, 4); 

// send package 
com__company__model__one_request__pack(&req, buf); 
SSL_write(clientssl, buf, len); 

Vous devez spécifier l'ordre octet BIG_ENDIAN ou LITTLE_ENDIAN que vous whant.