我試圖使用Netty和協議緩衝區(和加密,但這不會影響此問題)。服務器使用Netty以Java編寫,客戶端應該使用C語言和Java語言編寫。這是Java服務器端代碼。Netty +協議緩衝區Java <-> C通信問題
應用類:
@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);
}
}
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);
}
}
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;
}
}
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;
}
服務器日誌:
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
基本上,這是一些示例代碼取自網絡並修改了一下。不要看硬編碼值或其他缺陷。這僅用於學習目的。我可以使用Java客戶端與服務器通信,而不會有任何問題。但是,當我嘗試從C客戶端發送相同的消息時,服務器立即引發異常。我已經閱讀了一些關於分隔的內容,但我不知道如何處理。我也嘗試發送一個消息的長度作爲int首先,然後從C客戶端的實際消息,但它也沒有幫助。加密在這裏不是問題。如果我禁用它,我會得到相同的結果。
我在這裏錯過了什麼?這是否可以與C客戶進行溝通?
你分析過網絡流量嗎?像'wireshark'這樣的工具?只是想知道在哪一邊搜索問題。 – blafasel