message CryptogramWrapper { bytes registration = 1; } message Wrapper { Utility utility = 1; CryptogramWrapper cryptogramWrapper = 2; }
if(wrapper.hasCryptogramWrapper()) { if(wrapper.getCryptogramWrapper().hasField(registration_cw)) { byte[] cryptogram = wrapper.getCryptogramWrapper().getRegistration().toByteArray(); byte[] original = cryptography.Decrypt(cryptogram, cryptography.getSecretKey()); RegModels.Registration registration = RegModels.Registration.parseFrom(original); new Registration().saveUser(ctx, registration); } else if (wrapper.getCryptogramWrapper().hasField(login_cw)) {} }
public class ServerInitializer extends ChannelInitializer<SocketChannel> { @Override protected void initChannel(SocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); /* */ //pipeline.addLast(new LoggingHandler(LogLevel.INFO)); /* */ // Decoders protobuf pipeline.addLast(new ProtobufVarint32FrameDecoder()); pipeline.addLast(new ProtobufDecoder(MessageModels.Wrapper.getDefaultInstance())); /* */ // Encoder protobuf pipeline.addLast(new ProtobufVarint32LengthFieldPrepender()); pipeline.addLast(new ProtobufEncoder()); /* 30 */ pipeline.addLast(new IdleStateHandler(30, 0, 0)); /* */ pipeline.addLast(new EncryptHandler()); /* */ pipeline.addLast(new DecryptHandler()); } }
PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
PCHUsage = PCHUsageMode.UseSharedPCHs;
PCHUsage = PCHUsageMode.NoSharedPCHs;
PCHUsage = PCHUsageMode.Default;
using UnrealBuildTool; public class Spiky_Client : ModuleRules { public Spiky_Client(ReadOnlyTargetRules Target) : base(Target) { PCHUsage = PCHUsageMode.Default; PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore" }); PrivateDependencyModuleNames.AddRange(new string[] { }); } }
PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "Networking", "Sockets" });
// Copyright (c) 2017, Vadim Petrov - MIT License #pragma once #include "CoreMinimal.h" #include "UObject/NoExportTypes.h" #include "Networking.h" #include "SocketSubsystem.h" #include "SocketObject.generated.h" /** * , , - . */ UCLASS() class SPIKY_CLIENT_API USocketObject : public UObject { GENERATED_BODY() ~USocketObject(); public: // tcp static FSocket* tcp_socket; // tcp static TSharedPtr<FInternetAddr> tcp_address; // static bool bIsConnection; // static void Reconnect(); // static bool Alive(); // udp static FSocket* udp_socket; // udp static TSharedPtr<FInternetAddr> udp_address; // UDP , unreal FUdpSocketReceiver, - static FUdpSocketReceiver* UDPReceiver; static void Recv(const FArrayReaderPtr& ArrayReaderPtr, const FIPv4Endpoint& EndPt); static void RunUdpSocketReceiver(); static int32 tcp_local_port; static int32 udp_local_port; // , GameInstance static void InitSocket(FString serverAddress, int32 tcp_local_p, int32 tcp_server_port, int32 udp_local_p, int32 udp_server_port); };
tcp_socket = FTcpSocketBuilder("TCP_SOCKET") .AsNonBlocking() .AsReusable() .WithReceiveBufferSize(BufferSize) .WithSendBufferSize(BufferSize) .Build();
tcp_socket = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->CreateSocket(NAME_Stream, TEXT("TCP_SOCKET"), false);
void USocketObject::InitSocket(FString serverAddress, int32 tcp_local_p, int32 tcp_server_port, int32 udp_local_p, int32 udp_server_port) { int32 BufferSize = 2 * 1024 * 1024; tcp_local_port = tcp_local_p; udp_local_port = udp_local_p; // tcp /* FTcpSocketBuilder tcp_socket = FTcpSocketBuilder("TCP_SOCKET") .AsNonBlocking() // Socket connect always success. Non blocking you say socket connect dont wait for response (Don?t block) so it will return true. .AsReusable() .WithReceiveBufferSize(BufferSize) .WithSendBufferSize(BufferSize) .Build(); */ tcp_socket = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->CreateSocket(NAME_Stream, TEXT("TCP_SOCKET"), false); tcp_address = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->CreateInternetAddr(); FIPv4Address serverIP; FIPv4Address::Parse(serverAddress, serverIP); tcp_address->SetIp(serverIP.Value); tcp_address->SetPort(tcp_server_port); tcp_socket->Connect(*tcp_address); bIsConnection = Alive(); // udp udp_address = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->CreateInternetAddr(); FIPv4Address::Parse(serverAddress, serverIP); udp_address->SetIp(serverIP.Value); udp_address->SetPort(udp_server_port); udp_socket = FUdpSocketBuilder("UDP_SOCKET") .AsReusable() .BoundToPort(udp_local_port) .WithBroadcast() .WithReceiveBufferSize(BufferSize) .WithSendBufferSize(BufferSize) .Build(); }
if (tcp_socket != nullptr || udp_socket != nullptr) { tcp_socket->Close(); delete tcp_socket; delete udp_socket; }
// Copyright (c) 2017, Vadim Petrov - MIT License #include "Spiky_Client.h" #include "SocketObject.h" FSocket* USocketObject::tcp_socket = nullptr; TSharedPtr<FInternetAddr> USocketObject::tcp_address = nullptr; bool USocketObject::bIsConnection = false; FSocket* USocketObject::udp_socket = nullptr; TSharedPtr<FInternetAddr> USocketObject::udp_address = nullptr; FUdpSocketReceiver* USocketObject::UDPReceiver = nullptr; int32 USocketObject::tcp_local_port = 0; int32 USocketObject::udp_local_port = 0; USocketObject::~USocketObject() { if (tcp_socket != nullptr || udp_socket != nullptr) { tcp_socket->Close(); delete tcp_socket; delete udp_socket; } } void USocketObject::InitSocket(FString serverAddress, int32 tcp_local_p, int32 tcp_server_port, int32 udp_local_p, int32 udp_server_port) { int32 BufferSize = 2 * 1024 * 1024; tcp_local_port = tcp_local_p; udp_local_port = udp_local_p; /* tcp_socket = FTcpSocketBuilder("TCP_SOCKET") .AsNonBlocking() // Socket connect always success. Non blocking you say socket connect dont wait for response (Don?t block) so it will return true. .AsReusable() .WithReceiveBufferSize(BufferSize) .WithSendBufferSize(BufferSize) .Build(); */ // tcp tcp_socket = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->CreateSocket(NAME_Stream, TEXT("TCP_SOCKET"), false); // create a proper FInternetAddr representation tcp_address = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->CreateInternetAddr(); // parse server address FIPv4Address serverIP; FIPv4Address::Parse(serverAddress, serverIP); // and set tcp_address->SetIp(serverIP.Value); tcp_address->SetPort(tcp_server_port); tcp_socket->Connect(*tcp_address); // set the initial connection state bIsConnection = Alive(); // udp udp_address = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->CreateInternetAddr(); FIPv4Address::Parse(serverAddress, serverIP); udp_address->SetIp(serverIP.Value); udp_address->SetPort(udp_server_port); udp_socket = FUdpSocketBuilder("UDP_SOCKET") .AsReusable() .BoundToPort(udp_local_port) .WithBroadcast() .WithReceiveBufferSize(BufferSize) .WithSendBufferSize(BufferSize) .Build(); } void USocketObject::RunUdpSocketReceiver() { } void USocketObject::Recv(const FArrayReaderPtr& ArrayReaderPtr, const FIPv4Endpoint& EndPt) { } void USocketObject::Reconnect() { } bool USocketObject::Alive() { return false; }
<groupId>com.spiky.server</groupId> <artifactId>Spiky server</artifactId>
<dependencies> <dependency> <groupId>io.netty</groupId> <artifactId>netty-all</artifactId> <version>4.1.8.Final</version> </dependency> </dependencies>
syntax = "proto3"; message Player { string player_name = 1; string team = 2; int32 health = 3; PlayerPosition playerPosition = 4; } message PlayerPosition {}
./protoc --cpp_out=. --java_out=. GameModels.proto
<dependency> <groupId>com.google.protobuf</groupId> <artifactId>protobuf-java</artifactId> <version>3.0.0-beta-4</version> </dependency>
APP_OPTIM := release
APP_ABI := armeabi-v7a #x86 x86_64
APP_STL := gnustl_static
NDK_TOOLCHAIN_VERSION := clang
APP_CPPFLAGS += -D GOOGLE_PROTOBUF_NO_RTTI=1
APP_CPPFLAGS += -D __ANDROID__=1
APP_CPPFLAGS += -D HAVE_PTHREAD=1
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := libprotobuf
LOCAL_SRC_FILES :=\
src/google/protobuf/arena.cc \
src/google/protobuf/arenastring.cc \
src/google/protobuf/extension_set.cc \
src/google/protobuf/generated_message_util.cc \
src/google/protobuf/io/coded_stream.cc \
src/google/protobuf/io/zero_copy_stream.cc \
src/google/protobuf/io/zero_copy_stream_impl_lite.cc \
src/google/protobuf/message_lite.cc \
src/google/protobuf/repeated_field.cc \
src/google/protobuf/stubs/bytestream.cc \
src/google/protobuf/stubs/common.cc \
src/google/protobuf/stubs/int128.cc \
src/google/protobuf/stubs/once.cc \
src/google/protobuf/stubs/status.cc \
src/google/protobuf/stubs/statusor.cc \
src/google/protobuf/stubs/stringpiece.cc \
src/google/protobuf/stubs/stringprintf.cc \
src/google/protobuf/stubs/structurally_valid.cc \
src/google/protobuf/stubs/strutil.cc \
src/google/protobuf/stubs/time.cc \
src/google/protobuf/wire_format_lite.cc \
src/google/protobuf/any.cc \
src/google/protobuf/any.pb.cc \
src/google/protobuf/api.pb.cc \
src/google/protobuf/compiler/importer.cc \
src/google/protobuf/compiler/parser.cc \
src/google/protobuf/descriptor.cc \
src/google/protobuf/descriptor.pb.cc \
src/google/protobuf/descriptor_database.cc \
src/google/protobuf/duration.pb.cc \
src/google/protobuf/dynamic_message.cc \
src/google/protobuf/empty.pb.cc \
src/google/protobuf/extension_set_heavy.cc \
src/google/protobuf/field_mask.pb.cc \
src/google/protobuf/generated_message_reflection.cc \
src/google/protobuf/io/gzip_stream.cc \
src/google/protobuf/io/printer.cc \
src/google/protobuf/io/strtod.cc \
src/google/protobuf/io/tokenizer.cc \
src/google/protobuf/io/zero_copy_stream_impl.cc \
src/google/protobuf/map_field.cc \
src/google/protobuf/message.cc \
src/google/protobuf/reflection_ops.cc \
src/google/protobuf/service.cc \
src/google/protobuf/source_context.pb.cc \
src/google/protobuf/struct.pb.cc \
src/google/protobuf/stubs/mathlimits.cc \
src/google/protobuf/stubs/substitute.cc \
src/google/protobuf/text_format.cc \
src/google/protobuf/timestamp.pb.cc \
src/google/protobuf/type.pb.cc \
src/google/protobuf/unknown_field_set.cc \
src/google/protobuf/util/field_comparator.cc \
src/google/protobuf/util/field_mask_util.cc \
src/google/protobuf/util/internal/datapiece.cc \
src/google/protobuf/util/internal/default_value_objectwriter.cc \
src/google/protobuf/util/internal/error_listener.cc \
src/google/protobuf/util/internal/field_mask_utility.cc \
src/google/protobuf/util/internal/json_escaping.cc \
src/google/protobuf/util/internal/json_objectwriter.cc \
src/google/protobuf/util/internal/json_stream_parser.cc \
src/google/protobuf/util/internal/object_writer.cc \
src/google/protobuf/util/internal/proto_writer.cc \
src/google/protobuf/util/internal/protostream_objectsource.cc \
src/google/protobuf/util/internal/protostream_objectwriter.cc \
src/google/protobuf/util/internal/type_info.cc \
src/google/protobuf/util/internal/type_info_test_helper.cc \
src/google/protobuf/util/internal/utility.cc \
src/google/protobuf/util/json_util.cc \
src/google/protobuf/util/message_differencer.cc \
src/google/protobuf/util/time_util.cc \
src/google/protobuf/util/type_resolver_util.cc \
src/google/protobuf/wire_format.cc \
src/google/protobuf/wrappers.pb.cc
LOCAL_CPPFLAGS := -std=c++11
LOCAL_LDLIBS := -llog
ifeq ($(TARGET_ARCH),x86)
LOCAL_SRC_FILES := $(LOCAL_SRC_FILES) \
src/google/protobuf/stubs/atomicops_internals_x86_gcc.cc
endif
ifeq ($(TARGET_ARCH),x86_64)
LOCAL_SRC_FILES := $(LOCAL_SRC_FILES) \
src/google/protobuf/stubs/atomicops_internals_x86_gcc.cc
endif
LOCAL_C_INCLUDES = $(LOCAL_PATH)/src
include $(BUILD_SHARED_LIBRARY)
ThirdParty/Protobuf/Includes\google/protobuf/arena.h(635,25) : error: cannot use typeid with -fno-rtti
#define GOOGLE_PROTOBUF_NO_RTTI
error: "error C3861: 'check': identifier not found
, check (AssertionMacros.h), check (type_traits.h), check , check check_UnrealFix, , #undef check. unreal answers — Error C3861 (identifier not found) when including protocol buffers . template<typename B, typename D> struct is_base_of { typedef char (&yes)[1]; typedef char (&no)[2]; // BEGIN GOOGLE LOCAL MODIFICATION -- check is a #define on Mac. #undef check // END GOOGLE LOCAL MODIFICATION static yes check(const B*); static no check(const void*); enum { value = sizeof(check(static_cast<const D*>(NULL))) == sizeof(yes), }; };
template<typename B, typename D> struct is_base_of { typedef char (&yes)[1]; typedef char (&no)[2]; // BEGIN GOOGLE LOCAL MODIFICATION -- check is a #define on Mac. //#undef check // END GOOGLE LOCAL MODIFICATION static yes check_UnrealFix(const B*); static no check_UnrealFix(const void*); enum { value = sizeof(check_UnrealFix(static_cast<const D*>(NULL))) == sizeof(yes), }; };
openssl fatal error LNK1112: module machine type 'x64' conflicts with target machine type 'X86'
- open Developer Command Prompt for VS2015, go to E: \ Program Files (x86) \ Microsoft Visual Studio 14.0 \ VC and run vcvarsall.bat x64 ( source )openssl/ossl_typ.h(172): error C2365: 'UI': redefinition; previous definition was 'namespace'
public class Spiky_Client : ModuleRules { private string ModulePath { get { return ModuleDirectory; } } private string ThirdPartyPath { get { return Path.GetFullPath(Path.Combine(ModulePath, "../../ThirdParty/")); } } ... }
// Copyright (c) 2017, Vadim Petrov - MIT License using UnrealBuildTool; using System.IO; using System; public class Spiky_Client : ModuleRules { private string ModulePath { get { return ModuleDirectory; } } private string ThirdPartyPath { get { return Path.GetFullPath(Path.Combine(ModulePath, "../../ThirdParty/")); } } public Spiky_Client(ReadOnlyTargetRules Target) : base(Target) { PCHUsage = PCHUsageMode.Default; PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "Networking", "Sockets" }); PrivateDependencyModuleNames.AddRange(new string[] { "UMG", "Slate", "SlateCore" }); string IncludesPath = Path.Combine(ThirdPartyPath, "Protobuf", "Includes"); PublicIncludePaths.Add(IncludesPath); IncludesPath = Path.Combine(ThirdPartyPath, "OpenSSL", "Includes"); PublicIncludePaths.Add(IncludesPath); if ((Target.Platform == UnrealTargetPlatform.Win64)) { string LibrariesPath = Path.Combine(ThirdPartyPath, "Protobuf", "Libs"); PublicAdditionalLibraries.Add(Path.Combine(LibrariesPath, "libprotobuf.lib")); LibrariesPath = Path.Combine(ThirdPartyPath, "OpenSSL", "Libs"); PublicAdditionalLibraries.Add(Path.Combine(LibrariesPath, "libeay32.lib")); } if (Target.Platform == UnrealTargetPlatform.Android) { string BuildPath = Utils.MakePathRelativeTo(ModuleDirectory, BuildConfiguration.RelativeEnginePath); AdditionalPropertiesForReceipt.Add(new ReceiptProperty("AndroidPlugin", Path.Combine(BuildPath, "APL.xml"))); PublicAdditionalLibraries.Add(BuildPath + "/armv7/libprotobuf.so"); PublicAdditionalLibraries.Add(BuildPath + "/armv7/libcrypto_1_0_0.so"); } } }
<?xml version="1.0" encoding="utf-8"?> <root xmlns:android="http://schemas.android.com/apk/res/android"> <resourceCopies> <isArch arch="armeabi-v7a"> <copyFile src="$S(PluginDir)/armv7/libcrypto_1_0_0.so" dst="$S(BuildDir)/libs/armeabi-v7a/libcrypto_1_0_0.so" /> <copyFile src="$S(PluginDir)/armv7/libprotobuf.so" dst="$S(BuildDir)/libs/armeabi-v7a/libprotobuf.so" /> </isArch> </resourceCopies> </root>
// OpenSSL tests #include <openssl/evp.h> #include <sstream> #include <iomanip> void ADebugHUD::DrawHUD() { Super::DrawHUD(); FString hashTest = "Hash test (sha256): " + GetSHA256_s("test", strlen("test")); DrawText(hashTest, FColor::White, 50, 50, HUDFont); } FString ADebugHUD::GetSHA256_s(const void * data, size_t data_len) { EVP_MD_CTX mdctx; unsigned char md_value[EVP_MAX_MD_SIZE]; unsigned int md_len; EVP_DigestInit(&mdctx, EVP_sha256()); EVP_DigestUpdate(&mdctx, data, (size_t)data_len); EVP_DigestFinal_ex(&mdctx, md_value, &md_len); EVP_MD_CTX_cleanup(&mdctx); std::stringstream s; s.fill('0'); for (size_t i = 0; i < md_len; ++i) s << std::setw(2) << std::hex << (unsigned short)md_value[i]; return s.str().c_str(); }
./protoc --cpp_out=. --java_out=. DisableWarnings.proto
then compile the resulting header DisableWarnings.pb.h suppress warnings, we will include DisableWarnings in each proto file. There are only three lines in DisableWarnings.proto, the protobuff version, the name of the java package, and the name of the generated class.#define PROTOBUF_INLINE_NOT_IN_HEADERS 0
#pragma warning(disable:4100)
#pragma warning(disable:4127)
#pragma warning(disable:4125)
#pragma warning(disable:4267)
#pragma warning(disable:4389)
syntax = "proto3";
option java_package = "com.spiky.server.protomodels";
option java_outer_classname = "DisableWarnings";
// Generated by the protocol buffer compiler. DO NOT EDIT! // source: DisableWarnings.proto #define PROTOBUF_INLINE_NOT_IN_HEADERS 0 #pragma warning(disable:4100) #pragma warning(disable:4127) #pragma warning(disable:4125) #pragma warning(disable:4267) #pragma warning(disable:4389) #ifndef PROTOBUF_DisableWarnings_2eproto__INCLUDED #define PROTOBUF_DisableWarnings_2eproto__INCLUDED #include <string> #include <google/protobuf/stubs/common.h> #if GOOGLE_PROTOBUF_VERSION < 3000000 #error This file was generated by a newer version of protoc which is #error incompatible with your Protocol Buffer headers. Please update #error your headers. #endif #if 3000000 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION #error This file was generated by an older version of protoc which is #error incompatible with your Protocol Buffer headers. Please #error regenerate this file with a newer version of protoc. #endif #include <google/protobuf/arena.h> #include <google/protobuf/arenastring.h> #include <google/protobuf/generated_message_util.h> #include <google/protobuf/metadata.h> #include <google/protobuf/repeated_field.h> #include <google/protobuf/extension_set.h> // @@protoc_insertion_point(includes) // Internal implementation detail -- do not call these. void protobuf_AddDesc_DisableWarnings_2eproto(); void protobuf_AssignDesc_DisableWarnings_2eproto(); void protobuf_ShutdownFile_DisableWarnings_2eproto(); // =================================================================== // =================================================================== // =================================================================== #if !PROTOBUF_INLINE_NOT_IN_HEADERS #endif // !PROTOBUF_INLINE_NOT_IN_HEADERS // @@protoc_insertion_point(namespace_scope) // @@protoc_insertion_point(global_scope) #endif // PROTOBUF_DisableWarnings_2eproto__INCLUDED
/* */ private static final ResourceBundle configurationBundle = ResourceBundle.getBundle("configuration", Locale.ENGLISH); /* */ private static final int tcpPort = Integer.valueOf(configurationBundle.getString("tcpPort")); private static final int udpPort = Integer.valueOf(configurationBundle.getString("udpPort")); private static void run_tcp() { EventLoopGroup bossGroup = new NioEventLoopGroup(); // 1 EventLoopGroup workerGroup = new NioEventLoopGroup(); try { ServerBootstrap b = new ServerBootstrap(); // 2 b.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) // 3 .childHandler(new com.spiky.server.tcp.ServerInitializer()) // 4 .childOption(ChannelOption.SO_KEEPALIVE, true) .childOption(ChannelOption.TCP_NODELAY, true); ChannelFuture f = b.bind(tcpPort).sync(); // 5 f.channel().closeFuture().sync(); // 6 } catch (InterruptedException e) { e.printStackTrace(); } finally { workerGroup.shutdownGracefully(); bossGroup.shutdownGracefully(); } }
/* * Copyright (c) 2017, Vadim Petrov - MIT License */ package com.spiky.server; import io.netty.bootstrap.Bootstrap; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelOption; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioDatagramChannel; import io.netty.channel.socket.nio.NioServerSocketChannel; import java.util.Locale; import java.util.ResourceBundle; public class ServerMain { /* */ private static final ResourceBundle configurationBundle = ResourceBundle.getBundle("configuration", Locale.ENGLISH); /* */ private static final int tcpPort = Integer.valueOf(configurationBundle.getString("tcpPort")); private static final int udpPort = Integer.valueOf(configurationBundle.getString("udpPort")); private static void run_tcp() { EventLoopGroup bossGroup = new NioEventLoopGroup(); EventLoopGroup workerGroup = new NioEventLoopGroup(); try { ServerBootstrap b = new ServerBootstrap(); b.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) .childHandler(new com.spiky.server.tcp.ServerInitializer()) .childOption(ChannelOption.SO_KEEPALIVE, true) .childOption(ChannelOption.TCP_NODELAY, true); ChannelFuture f = b.bind(tcpPort).sync(); f.channel().closeFuture().sync(); } catch (InterruptedException e) { e.printStackTrace(); } finally { workerGroup.shutdownGracefully(); bossGroup.shutdownGracefully(); } } private static void run_udp() { final NioEventLoopGroup group = new NioEventLoopGroup(); try { Bootstrap bootstrap = new Bootstrap(); bootstrap.group(group).channel(NioDatagramChannel.class) .handler(new com.spiky.server.udp.ServerInitializer()); bootstrap.bind(udpPort).sync(); } catch (InterruptedException e) { e.printStackTrace(); } } public static void main(String[] args) { new Thread(ServerMain::run_tcp).start(); new Thread(ServerMain::run_udp).start(); } }
/* UDP TCP*/ public class ServerInitializer extends ChannelInitializer<NioDatagramChannel> public class ServerInitializer extends ChannelInitializer<SocketChannel>
com.spiky.server.tcp
and com.spiky.server.udp
in each of them we will create a ServerInitializer class (with excellent NioDatagramChannel / SocketChannel) with the following contents: package com.spiky.server.tcp; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelPipeline; import io.netty.channel.socket.SocketChannel; public class ServerInitializer extends ChannelInitializer<SocketChannel> { @Override protected void initChannel(SocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); } }
... ChannelPipeline pipeline = ch.pipeline(); /* */ pipeline.addLast(new LoggingHandler(LogLevel.INFO)); ...
message Wrapper { Utility utility = 1; InputChecking inputChecking = 2; Registration registration = 3; Login login = 4; CryptogramWrapper cryptogramWrapper = 5; }
syntax = "proto3";
option java_package = "com.spiky.server.protomodels";
option java_outer_classname = "DisableWarnings";
syntax = "proto3"; option java_package = "com.spiky.server.protomodels"; option java_outer_classname = "MessageModels"; import "UtilityModels.proto"; import "RegLogModels.proto"; import "DisableWarnings.proto"; message CryptogramWrapper { bytes registration = 1; bytes login = 2; bytes initialState = 3; bytes room = 4; bytes mainMenu = 5; bytes gameModels = 6; } message Wrapper { Utility utility = 1; InputChecking inputChecking = 2; Registration registration = 3; Login login = 4; CryptogramWrapper cryptogramWrapper = 5; }
syntax = "proto3"; option java_package = "com.spiky.server.protomodels"; option java_outer_classname = "UtilityModels"; import "DisableWarnings.proto"; message Utility { bool alive = 1; }
syntax = "proto3"; option java_package = "com.spiky.server.protomodels"; option java_outer_classname = "RegistrationLoginModels"; import "DisableWarnings.proto"; import "GameRoomModels.proto"; message InputChecking { string login = 1; string mail = 2; string captcha = 3; bool getCaptcha = 4; bytes captchaData = 5; oneof v1 { bool loginCheckStatus = 6; bool mailCheckStatus = 7; bool captchaCheckStatus = 8; } } message Login { string mail = 1; string hash = 2; string publicKey = 3; oneof v1 { int32 stateCode = 4; } } message Registration { string login = 1; string hash = 2; string mail = 3; string captcha = 4; string publicKey = 5; oneof v1 { int32 stateCode = 6; } } message InitialState { string sessionId = 1; string login = 2; repeated CreateRoom createRoom = 3; }
syntax = "proto3"; option java_package = "com.spiky.server.protomodels"; option java_outer_classname = "MainMenuModels"; import "DisableWarnings.proto"; message ChatMessage { int64 time = 1; string name = 2; string text = 3; } message Chat { int64 time = 1; string name = 2; string text = 3; oneof v1 { bool subscribe = 4; } repeated ChatMessage messages = 5; } message MainMenu { Chat chat = 1; }
syntax = "proto3"; option java_package = "com.spiky.server.protomodels"; option java_outer_classname = "GameRoomModels"; import "DisableWarnings.proto"; import "MainMenuModels.proto"; message Room { CreateRoom createRoom = 1; RoomsListUpdate roomsListUpdate = 2; SubscribeRoom subscribeRoom = 3; RoomUpdate roomUpdate = 4; bool startGame = 5; string roomName = 6; } message CreateRoom { string roomName = 1; string mapName = 2; string gameTime = 3; string maxPlayers = 4; string creator = 5; } message RoomsListUpdate { bool deleteRoom = 1; bool addRoom = 2; string roomName = 3; string roomOwner = 4; } message SubscribeRoom { oneof v1 { bool subscribe = 1; } string roomName = 2; int32 stateCode = 3; RoomDescribe roomDescribe = 4; string player = 5; string team = 6; } message RoomDescribe { repeated TeamPlayer team1 = 1; repeated TeamPlayer team2 = 2; repeated TeamPlayer undistributed = 3; string roomName = 4; string mapName = 5; string gameTime = 6; string maxPlayers = 7; string creator = 8; Chat chat = 9; } message TeamPlayer { string player_name = 1; } message RoomUpdate { RoomDescribe roomDescribe = 1; string targetTeam = 2; string roomName = 3; }
syntax = "proto3"; option java_package = "com.spiky.server.protomodels"; option java_outer_classname = "GameModels"; import "DisableWarnings.proto"; message GameInitialState { bool startGame = 1; repeated Player player = 2; } message Player { string player_name = 1; string team = 2; int32 health = 3; PlayerPosition playerPosition = 4; } message PlayerPosition { Location loc = 1; Rotation rot = 2; message Location { int32 X = 1; int32 Y = 2; int32 Z = 3; } message Rotation { int32 Pitch = 1; int32 Roll = 2; int32 Yaw = 3; } string playerName = 3; int64 timeStamp = 4; } message Ping { int64 time = 1; } message Shot { Start start = 1; End end = 2; PlayerPosition playerPosition = 3; message Start { int32 X = 1; int32 Y = 2; int32 Z = 3; } message End { int32 X = 1; int32 Y = 2; int32 Z = 3; } int64 timeStamp = 4; string requestFrom = 5; string requestTo = 6; string roomOwner = 7; oneof v1 { bool result_hitState = 8; } string result_bonename = 9; } message GameData { GameInitialState gameInitialState = 1; PlayerPosition playerPosition = 2; Ping ping = 3; Shot shot = 4; }
// java
if(wrapper.getCryptogramWrapper().hasField(registration_cw)) // -
// cpp
if (wrapper->cryptogramwrapper().GetReflection()->HasField(wrapper->cryptogramwrapper(), Descriptors::registration_cw)) // -
// Copyright (c) 2017, Vadim Petrov - MIT License package com.spiky.server.utils; import com.spiky.server.protomodels.*; /** * * */ public class Descriptors { public static com.google.protobuf.Descriptors.FieldDescriptor registration_cw = MessageModels.CryptogramWrapper.getDefaultInstance().getDescriptorForType().findFieldByName("registration"); public static com.google.protobuf.Descriptors.FieldDescriptor login_cw = MessageModels.CryptogramWrapper.getDefaultInstance().getDescriptorForType().findFieldByName("login"); public static com.google.protobuf.Descriptors.FieldDescriptor initialState_cw = MessageModels.CryptogramWrapper.getDefaultInstance().getDescriptorForType().findFieldByName("initialState"); public static com.google.protobuf.Descriptors.FieldDescriptor room_cw = MessageModels.CryptogramWrapper.getDefaultInstance().getDescriptorForType().findFieldByName("room"); public static com.google.protobuf.Descriptors.FieldDescriptor mainMenu_cw = MessageModels.CryptogramWrapper.getDefaultInstance().getDescriptorForType().findFieldByName("mainMenu"); public static com.google.protobuf.Descriptors.FieldDescriptor gameModels_cw = MessageModels.CryptogramWrapper.getDefaultInstance().getDescriptorForType().findFieldByName("gameModels"); public static com.google.protobuf.Descriptors.FieldDescriptor getCaptcha_ich = RegistrationLoginModels.InputChecking.getDefaultInstance().getDescriptorForType().findFieldByName("getCaptcha"); public static com.google.protobuf.Descriptors.FieldDescriptor login_ich = RegistrationLoginModels.InputChecking.getDefaultInstance().getDescriptorForType().findFieldByName("login"); public static com.google.protobuf.Descriptors.FieldDescriptor mail_ich = RegistrationLoginModels.InputChecking.getDefaultInstance().getDescriptorForType().findFieldByName("mail"); public static com.google.protobuf.Descriptors.FieldDescriptor captcha_ich = RegistrationLoginModels.InputChecking.getDefaultInstance().getDescriptorForType().findFieldByName("captcha"); public static com.google.protobuf.Descriptors.FieldDescriptor login_reg = RegistrationLoginModels.Registration.getDefaultInstance().getDescriptorForType().findFieldByName("login"); public static com.google.protobuf.Descriptors.FieldDescriptor mail_reg = RegistrationLoginModels.Registration.getDefaultInstance().getDescriptorForType().findFieldByName("mail"); public static com.google.protobuf.Descriptors.FieldDescriptor captcha_reg = RegistrationLoginModels.Registration.getDefaultInstance().getDescriptorForType().findFieldByName("captcha"); public static com.google.protobuf.Descriptors.FieldDescriptor publicKey_reg = RegistrationLoginModels.Registration.getDefaultInstance().getDescriptorForType().findFieldByName("publicKey"); public static com.google.protobuf.Descriptors.FieldDescriptor publicKey_log = RegistrationLoginModels.Login.getDefaultInstance().getDescriptorForType().findFieldByName("publicKey"); public static com.google.protobuf.Descriptors.FieldDescriptor subscribe_chat = MainMenuModels.Chat.getDefaultInstance().getDescriptorForType().findFieldByName("subscribe"); public static com.google.protobuf.Descriptors.FieldDescriptor chat_mm = MainMenuModels.MainMenu.getDefaultInstance().getDescriptorForType().findFieldByName("chat"); public static com.google.protobuf.Descriptors.FieldDescriptor deleteRoom_room = GameRoomModels.RoomsListUpdate.getDefaultInstance().getDescriptorForType().findFieldByName("deleteRoom"); public static com.google.protobuf.Descriptors.FieldDescriptor startGame_room = GameRoomModels.Room.getDefaultInstance().getDescriptorForType().findFieldByName("startGame"); public static com.google.protobuf.Descriptors.FieldDescriptor requestTo_shot_gd = GameModels.Shot.getDefaultInstance().getDescriptorForType().findFieldByName("requestTo"); }
// Copyright (c) 2017, Vadim Petrov - MIT License #pragma once #include <google/protobuf/descriptor.h> class Descriptors { public: static const google::protobuf::FieldDescriptor* captchaDataField_ich; static const google::protobuf::FieldDescriptor* loginCheckStatus_ich; static const google::protobuf::FieldDescriptor* mailCheckStatus_ich; static const google::protobuf::FieldDescriptor* captchaCheckStatus_ich; static const google::protobuf::FieldDescriptor* publicKey_reg; static const google::protobuf::FieldDescriptor* stateCode_reg; static const google::protobuf::FieldDescriptor* publicKey_log; static const google::protobuf::FieldDescriptor* stateCode_log; static const google::protobuf::FieldDescriptor* registration_cw; static const google::protobuf::FieldDescriptor* login_cw; static const google::protobuf::FieldDescriptor* initialState_cw; static const google::protobuf::FieldDescriptor* room_cw; static const google::protobuf::FieldDescriptor* mainMenu_cw; static const google::protobuf::FieldDescriptor* gameModels_cw; static const google::protobuf::FieldDescriptor* chat_mm; static const google::protobuf::FieldDescriptor* nameField_chat; static const google::protobuf::FieldDescriptor* player_sub; static const google::protobuf::FieldDescriptor* player_team; static const google::protobuf::FieldDescriptor* chat_room; }; // Copyright (c) 2017, Vadim Petrov - MIT License #include "Spiky_Client.h" #include "Descriptors.h" #include "Protobufs/RegLogModels.pb.h" #include "Protobufs/MessageModels.pb.h" #include "Protobufs/MainMenuModels.pb.h" const google::protobuf::FieldDescriptor* Descriptors::captchaDataField_ich = InputChecking::default_instance().descriptor()->FindFieldByName("captchaData"); const google::protobuf::FieldDescriptor* Descriptors::loginCheckStatus_ich = InputChecking::default_instance().descriptor()->FindFieldByName("loginCheckStatus"); const google::protobuf::FieldDescriptor* Descriptors::mailCheckStatus_ich = InputChecking::default_instance().descriptor()->FindFieldByName("mailCheckStatus"); const google::protobuf::FieldDescriptor* Descriptors::captchaCheckStatus_ich = InputChecking::default_instance().descriptor()->FindFieldByName("captchaCheckStatus"); const google::protobuf::FieldDescriptor* Descriptors::publicKey_reg = Registration::default_instance().descriptor()->FindFieldByName("publicKey"); const google::protobuf::FieldDescriptor* Descriptors::stateCode_reg = Registration::default_instance().descriptor()->FindFieldByName("stateCode"); const google::protobuf::FieldDescriptor* Descriptors::publicKey_log = Login::default_instance().descriptor()->FindFieldByName("publicKey"); const google::protobuf::FieldDescriptor* Descriptors::stateCode_log = Login::default_instance().descriptor()->FindFieldByName("stateCode"); const google::protobuf::FieldDescriptor* Descriptors::registration_cw = CryptogramWrapper::default_instance().descriptor()->FindFieldByName("registration"); const google::protobuf::FieldDescriptor* Descriptors::login_cw = CryptogramWrapper::default_instance().descriptor()->FindFieldByName("login"); const google::protobuf::FieldDescriptor* Descriptors::initialState_cw = CryptogramWrapper::default_instance().descriptor()->FindFieldByName("initialState"); const google::protobuf::FieldDescriptor* Descriptors::room_cw = CryptogramWrapper::default_instance().descriptor()->FindFieldByName("room"); const google::protobuf::FieldDescriptor* Descriptors::mainMenu_cw = CryptogramWrapper::default_instance().descriptor()->FindFieldByName("mainMenu"); const google::protobuf::FieldDescriptor* Descriptors::gameModels_cw = CryptogramWrapper::default_instance().descriptor()->FindFieldByName("gameModels"); const google::protobuf::FieldDescriptor* Descriptors::chat_mm = MainMenu::default_instance().descriptor()->FindFieldByName("chat"); const google::protobuf::FieldDescriptor* Descriptors::nameField_chat = Chat::default_instance().descriptor()->FindFieldByName("name"); const google::protobuf::FieldDescriptor* Descriptors::player_sub = SubscribeRoom::default_instance().descriptor()->FindFieldByName("player"); const google::protobuf::FieldDescriptor* Descriptors::player_team = SubscribeRoom::default_instance().descriptor()->FindFieldByName("team"); const google::protobuf::FieldDescriptor* Descriptors::chat_room = RoomDescribe::default_instance().descriptor()->FindFieldByName("chat");
./protoc --cpp_out=c:/Spiky/Spiky_Client/Source/Spiky_Client/Protobufs --java_out=c:/Spiky/Spiky_Server/src/main/java *.proto
@Override protected void channelRead0(ChannelHandlerContext ctx, MessageModels.Wrapper wrapper) throws Exception { }
public class ServerInitializer extends ChannelInitializer<NioDatagramChannel> { @Override protected void initChannel(NioDatagramChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); /* */ pipeline.addLast(new LoggingHandler(LogLevel.INFO)); /* proto */ pipeline.addLast(new ProtoDecoderHandler()); /* */ pipeline.addLast(new PackageHandler()); }
/* * Copyright (c) 2017, Vadim Petrov - MIT License */ package com.spiky.server.udp.handlers; import com.spiky.server.protomodels.MessageModels; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; import io.netty.channel.socket.DatagramPacket; import java.io.ByteArrayInputStream; public class ProtoDecoderHandler extends SimpleChannelInboundHandler<DatagramPacket> { @Override protected void channelRead0(ChannelHandlerContext ctx, DatagramPacket datagramPacket) throws Exception { ByteBuf buf = datagramPacket.content(); byte[] bytes = new byte[buf.readableBytes()]; int readerIndex = buf.readerIndex(); buf.getBytes(readerIndex, bytes); ByteArrayInputStream input = new ByteArrayInputStream(bytes); MessageModels.Wrapper wrapper = MessageModels.Wrapper.parseDelimitedFrom(input); System.out.println("udp: "); System.out.println(wrapper.toString()); System.out.println(datagramPacket.sender().getAddress() + " " + datagramPacket.sender().getPort()); // () ctx.write(new DatagramPacket(Unpooled.copiedBuffer(datagramPacket.content()), datagramPacket.sender())); } @Override public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { ctx.flush(); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { cause.printStackTrace(); ctx.close(); } }
#include "Spiky_Client.h" #include "SocketObject.h" #include "Protobufs/MessageModels.pb.h" #include <google/protobuf/message.h> #include <google/protobuf/io/zero_copy_stream_impl_lite.h> #include <google/protobuf/io/coded_stream.h> FSocket* USocketObject::tcp_socket = nullptr; TSharedPtr<FInternetAddr> USocketObject::tcp_address = nullptr; bool USocketObject::bIsConnection = false; FSocket* USocketObject::udp_socket = nullptr; TSharedPtr<FInternetAddr> USocketObject::udp_address = nullptr; FUdpSocketReceiver* USocketObject::UDPReceiver = nullptr; int32 USocketObject::tcp_local_port = 0; int32 USocketObject::udp_local_port = 0; USocketObject::~USocketObject() { if (tcp_socket != nullptr || udp_socket != nullptr) { tcp_socket->Close(); delete tcp_socket; delete udp_socket; } } void USocketObject::InitSocket(FString serverAddress, int32 tcp_local_p, int32 tcp_server_port, int32 udp_local_p, int32 udp_server_port) { int32 BufferSize = 2 * 1024 * 1024; tcp_local_port = tcp_local_p; udp_local_port = udp_local_p; // tcp tcp_socket = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->CreateSocket(NAME_Stream, TEXT("TCP_SOCKET"), false); // create a proper FInternetAddr representation tcp_address = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->CreateInternetAddr(); // parse server address FIPv4Address serverIP; FIPv4Address::Parse(serverAddress, serverIP); // and set tcp_address->SetIp(serverIP.Value); tcp_address->SetPort(tcp_server_port); tcp_socket->Connect(*tcp_address); // set the initial connection state bIsConnection = Alive(); // udp udp_address = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->CreateInternetAddr(); FIPv4Address::Parse(serverAddress, serverIP); udp_address->SetIp(serverIP.Value); udp_address->SetPort(udp_server_port); udp_socket = FUdpSocketBuilder("UDP_SOCKET") .AsReusable() .BoundToPort(udp_local_port) .WithBroadcast() .WithReceiveBufferSize(BufferSize) .WithSendBufferSize(BufferSize) .Build(); } void USocketObject::RunUdpSocketReceiver() { FTimespan ThreadWaitTime = FTimespan::FromMilliseconds(30); UDPReceiver = new FUdpSocketReceiver(udp_socket, ThreadWaitTime, TEXT("UDP_RECEIVER")); UDPReceiver->OnDataReceived().BindStatic(&USocketObject::Recv); UDPReceiver->Start(); } void USocketObject::Recv(const FArrayReaderPtr& ArrayReaderPtr, const FIPv4Endpoint& EndPt) { GLog->Log("Reveived UDP data"); uint8_t * buffer = ArrayReaderPtr->GetData(); size_t size = ArrayReaderPtr->Num(); GLog->Log("Size of incoming data: " + FString::FromInt(size)); google::protobuf::io::ArrayInputStream arr(buffer, size); google::protobuf::io::CodedInputStream input(&arr); std::shared_ptr<Wrapper> wrapper(new Wrapper); ReadDelimitedFrom(&input, wrapper.get()); std::string msg; wrapper->SerializeToString(&msg); GLog->Log(msg.c_str()); } bool USocketObject::SendByUDP(google::protobuf::Message * message) { Wrapper wrapper; if (message->GetTypeName() == "Utility") { Utility * mes = static_cast<Utility*>(message); wrapper.set_allocated_utility(mes); } size_t size = wrapper.ByteSize() + 5; // include size, varint32 never takes more than 5 bytes uint8_t * buffer = new uint8_t[size]; google::protobuf::io::ArrayOutputStream arr(buffer, size); google::protobuf::io::CodedOutputStream output(&arr); output.WriteVarint32(wrapper.ByteSize()); wrapper.SerializeToCodedStream(&output); if (wrapper.has_utility()) { wrapper.release_utility(); } int32 bytesSent = 0; bool sentState = false; sentState = udp_socket->SendTo(buffer, output.ByteCount(), bytesSent, *udp_address); delete[] buffer; return sentState; } bool USocketObject::ReadDelimitedFrom(google::protobuf::io::CodedInputStream * input, google::protobuf::MessageLite * message) { // Read the size. uint32_t size; if (!input->ReadVarint32(&size)) return false; // Tell the stream not to read beyond that size. google::protobuf::io::CodedInputStream::Limit limit = input->PushLimit(size); // Parse the message. if (!message->MergeFromCodedStream(input)) return false; if (!input->ConsumedEntireMessage()) return false; // Release the limit. input->PopLimit(limit); return true; } void USocketObject::Reconnect() { } bool USocketObject::Alive() { return false; }
virtual void BeginPlay() override; virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override; void TestSendUPDMessage();
EnableInput(GetWorld()->GetFirstPlayerController()); InputComponent->BindAction("Q", IE_Pressed, this, &ASpikyGameMode::TestSendUPDMessage);
void ASpikyGameMode::TestSendUPDMessage() { GLog->Log("send ->>>"); std::shared_ptr<Utility> utility(new Utility); utility->set_alive(true); USocketObject::SendByUDP(utility.get()); }
// Copyright (c) 2017, Vadim Petrov - MIT License #include "Spiky_Client.h" #include "SpikyGameMode.h" #include "SocketObject.h" #include "Runtime/Engine/Classes/Engine/World.h" #include "Protobufs/UtilityModels.pb.h" void ASpikyGameMode::BeginPlay() { Super::BeginPlay(); GLog->Log("AClientGameMode::BeginPlay()"); EnableInput(GetWorld()->GetFirstPlayerController()); InputComponent->BindAction("Q", IE_Pressed, this, &ASpikyGameMode::TestSendUPDMessage); } void ASpikyGameMode::EndPlay(const EEndPlayReason::Type EndPlayReason) { Super::EndPlay(EndPlayReason); GLog->Log("AClientGameMode::EndPlay()"); } void ASpikyGameMode::TestSendUPDMessage() { GLog->Log("send ->>>"); std::shared_ptr<Utility> utility(new Utility); utility->set_alive(true); USocketObject::SendByUDP(utility.get()); }
virtual void Init() override; virtual void Shutdown() override;
// .h // Copyright (c) 2017, Vadim Petrov - MIT License #pragma once #include <string> class Config { public: static std::string address; static size_t tcp_local_port; static size_t tcp_server_port; static size_t udp_local_port; static size_t udp_server_port; static bool bEnableCrypt; }; // .cpp // Copyright (c) 2017, Vadim Petrov - MIT License #include "Spiky_Client.h" #include "Config.h" bool Config::bEnableCrypt = true; std::string Config::address = "127.0.0.1"; size_t Config::tcp_local_port = 7678; size_t Config::tcp_server_port = 7680; size_t Config::udp_local_port = 7679; size_t Config::udp_server_port = 7681;
void USpikyGameInstance::Init() { GLog->Log("UClientGameInstance::Init()"); USocketObject::InitSocket(Config::address.c_str(), Config::tcp_local_port, Config::tcp_server_port, Config::udp_local_port, Config::udp_server_port); // udp USocketObject::RunUdpSocketReceiver(); }
udp:
utility {
alive: true
}
/127.0.0.1 7679
10, 2017 4:42:30 PM io.netty.handler.logging.LoggingHandler channelRead
INFO: [id: 0x89373e1f, L:/0:0:0:0:0:0:0:0:7681] RECEIVED: DatagramPacket(/127.0.0.1:7679 => /0:0:0:0:0:0:0:0:7681, PooledUnsafeDirectByteBuf(ridx: 0, widx: 5, cap: 2048)), 5B
+-------------------------------------------------+
| 0 1 2 3 4 5 6 7 8 9 abcdef |
+--------+-------------------------------------------------+----------------+
|00000000| 04 0a 02 08 01 |..... |
+--------+-------------------------------------------------+----------------+
10, 2017 4:42:30 PM io.netty.handler.logging.LoggingHandler write
INFO: [id: 0x89373e1f, L:/0:0:0:0:0:0:0:0:7681] WRITE: DatagramPacket(=> /127.0.0.1:7679, UnpooledUnsafeHeapByteBuf(ridx: 0, widx: 5, cap: 5)), 5B
+-------------------------------------------------+
| 0 1 2 3 4 5 6 7 8 9 abcdef |
+--------+-------------------------------------------------+----------------+
|00000000| 04 0a 02 08 01 |..... |
+--------+-------------------------------------------------+----------------+
10, 2017 4:42:30 PM io.netty.handler.logging.LoggingHandler flush
INFO: [id: 0x89373e1f, L:/0:0:0:0:0:0:0:0:7681] FLUSH
Reveived UDP data
Size of incoming data: 5
ServerMain
//new Thread(ServerMain::run_udp).start();
SpikyGameInstance
// udp
//USocketObject::RunUdpSocketReceiver();
// Copyright (c) 2017, Vadim Petrov - MIT License #include "Spiky_Client.h" #include "SocketObject.h" #include "Protobufs/MessageModels.pb.h" FSocket* USocketObject::tcp_socket = nullptr; TSharedPtr<FInternetAddr> USocketObject::tcp_address = nullptr; bool USocketObject::bIsConnection = false; FSocket* USocketObject::udp_socket = nullptr; TSharedPtr<FInternetAddr> USocketObject::udp_address = nullptr; FUdpSocketReceiver* USocketObject::UDPReceiver = nullptr; int32 USocketObject::tcp_local_port = 0; int32 USocketObject::udp_local_port = 0; USocketObject::~USocketObject() { GLog->Log("USocketObject::~USocketObject()"); if (tcp_socket != nullptr || udp_socket != nullptr) { tcp_socket->Close(); //UDPReceiver->Stop(); delete tcp_socket; delete udp_socket; } } void USocketObject::InitSocket(FString serverAddress, int32 tcp_local_p, int32 tcp_server_port, int32 udp_local_p, int32 udp_server_port) { int32 BufferSize = 2 * 1024 * 1024; tcp_local_port = tcp_local_p; udp_local_port = udp_local_p; /* tcp_socket = FTcpSocketBuilder("TCP_SOCKET") .AsNonBlocking() // Socket connect always success. Non blocking you say socket connect dont wait for response (Don?t block) so it will return true. .AsReusable() .WithReceiveBufferSize(BufferSize) .WithSendBufferSize(BufferSize) .Build(); */ // tcp tcp_socket = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->CreateSocket(NAME_Stream, TEXT("TCP_SOCKET"), false); // create a proper FInternetAddr representation tcp_address = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->CreateInternetAddr(); // parse server address FIPv4Address serverIP; FIPv4Address::Parse(serverAddress, serverIP); // and set tcp_address->SetIp(serverIP.Value); tcp_address->SetPort(tcp_server_port); tcp_socket->Connect(*tcp_address); // set the initial connection state bIsConnection = Alive(); // udp udp_address = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->CreateInternetAddr(); FIPv4Address::Parse(serverAddress, serverIP); udp_address->SetIp(serverIP.Value); udp_address->SetPort(udp_server_port); /* udp_socket = FUdpSocketBuilder("UDP_SOCKET") .AsReusable() .BoundToPort(udp_local_port) .WithBroadcast() .WithReceiveBufferSize(BufferSize) .WithSendBufferSize(BufferSize) .Build(); */ } void USocketObject::RunUdpSocketReceiver() { FTimespan ThreadWaitTime = FTimespan::FromMilliseconds(100); UDPReceiver = new FUdpSocketReceiver(udp_socket, ThreadWaitTime, TEXT("UDP_RECEIVER")); UDPReceiver->OnDataReceived().BindStatic(&USocketObject::Recv); UDPReceiver->Start(); } void USocketObject::Recv(const FArrayReaderPtr& ArrayReaderPtr, const FIPv4Endpoint& EndPt) { GLog->Log("Reveived UDP data"); uint8_t * buffer = ArrayReaderPtr->GetData(); size_t size = ArrayReaderPtr->Num(); GLog->Log("Size of incoming data: " + FString::FromInt(size)); google::protobuf::io::ArrayInputStream arr(buffer, size); google::protobuf::io::CodedInputStream input(&arr); std::shared_ptr<Wrapper> wrapper(new Wrapper); ReadDelimitedFrom(&input, wrapper.get()); std::string msg; wrapper->SerializeToString(&msg); GLog->Log(msg.c_str()); } bool USocketObject::SendByUDP(google::protobuf::Message * message) { Wrapper wrapper; if (message->GetTypeName() == "Utility") { Utility * mes = static_cast<Utility*>(message); wrapper.set_allocated_utility(mes); } size_t size = wrapper.ByteSize() + 5; // include size, varint32 never takes more than 5 bytes uint8_t * buffer = new uint8_t[size]; google::protobuf::io::ArrayOutputStream arr(buffer, size); google::protobuf::io::CodedOutputStream output(&arr); output.WriteVarint32(wrapper.ByteSize()); wrapper.SerializeToCodedStream(&output); if (wrapper.has_utility()) { wrapper.release_utility(); } int32 bytesSent = 0; bool sentState = false; sentState = udp_socket->SendTo(buffer, output.ByteCount(), bytesSent, *udp_address); delete[] buffer; return sentState; } void USocketObject::Reconnect() { } bool USocketObject::Alive() { return false; } bool USocketObject::ReadDelimitedFrom(google::protobuf::io::CodedInputStream * input, google::protobuf::MessageLite * message) { // Read the size. uint32_t size; if (!input->ReadVarint32(&size)) return false; // Tell the stream not to read beyond that size. google::protobuf::io::CodedInputStream::Limit limit = input->PushLimit(size); // Parse the message. if (!message->MergeFromCodedStream(input)) return false; if (!input->ConsumedEntireMessage()) return false; // Release the limit. input->PopLimit(limit); return true; }
// Decoders protobuf pipeline.addLast(new ProtobufVarint32FrameDecoder()); pipeline.addLast(new ProtobufDecoder(MessageModels.Wrapper.getDefaultInstance())); // Encoder protobuf pipeline.addLast(new ProtobufVarint32LengthFieldPrepender()); pipeline.addLast(new ProtobufEncoder());
/* */ pipeline.addLast(new DecryptHandler());
ctx.writeAndFlush(wrapper);
// Copyright (c) 2017, Vadim Petrov - MIT License #pragma once #include "Runtime/Core/Public/HAL/Runnable.h" #include "Runtime/Core/Public/HAL/RunnableThread.h" class SPIKY_CLIENT_API FServerStatusCheckingTh : public FRunnable { // Singleton instance, can access the thread any time via static accessor, if it is active! static FServerStatusCheckingTh* Runnable; // Thread to run the worker FRunnable on FRunnableThread* Thread; // The way to stop static bool bThreadRun; public: FServerStatusCheckingTh(); ~FServerStatusCheckingTh(); // FRunnable interface virtual bool Init(); virtual uint32 Run(); // Logics static FServerStatusCheckingTh* RunServerChecking(); // Shuts down the thread. Static so it can easily be called from outside the thread context static void Shutdown(); }; // Copyright (c) 2017, Vadim Petrov - MIT License #include "Spiky_Client.h" #include "ServerStatusCheckingTh.h" #include "SocketObject.h" FServerStatusCheckingTh* FServerStatusCheckingTh::Runnable = nullptr; bool FServerStatusCheckingTh::bThreadRun = false; FServerStatusCheckingTh::FServerStatusCheckingTh() { Thread = FRunnableThread::Create(this, TEXT("ServerStatusChecking"), 0, TPri_BelowNormal); } FServerStatusCheckingTh::~FServerStatusCheckingTh() { delete Thread; Thread = nullptr; } bool FServerStatusCheckingTh::Init() { bThreadRun = true; return true; } uint32 FServerStatusCheckingTh::Run() { while (bThreadRun) { FPlatformProcess::Sleep(1.f); // if (!USocketObject::bIsConnection) // , { USocketObject::Reconnect(); } else { USocketObject::bIsConnection = USocketObject::Alive(); // , } // //GLog->Log("Connect state (bIsConnection) = " + FString::FromInt((int32)USocketObject::bIsConnection) + " | FServerStatusCheckingTh::CheckServer"); } return 0; } FServerStatusCheckingTh* FServerStatusCheckingTh::RunServerChecking() { if (!Runnable && FPlatformProcess::SupportsMultithreading()) { Runnable = new FServerStatusCheckingTh(); } return Runnable; } void FServerStatusCheckingTh::Shutdown() { bThreadRun = false; GLog->Log("FServerStatusCheckingTh::Shutdown()"); if (Runnable) { delete Runnable; Runnable = nullptr; } }
void USocketObject::Reconnect() { tcp_socket->Close(); uint32 OutIP; tcp_address->GetIp(OutIP); FString ip = FString::Printf(TEXT("%d.%d.%d.%d"), 0xff & (OutIP >> 24), 0xff & (OutIP >> 16), 0xff & (OutIP >> 8), 0xff & OutIP); InitSocket(ip, tcp_local_port, tcp_address->GetPort(), udp_local_port, udp_address->GetPort()); } bool USocketObject::Alive() { std::shared_ptr<Utility> utility(new Utility); utility->set_alive(true); // Send , : , ? tcp? return UMessageEncoder::Send(utility.get(), false, true); }
// Copyright (c) 2017, Vadim Petrov - MIT License #pragma once #include "Runtime/Core/Public/HAL/Runnable.h" #include "Runtime/Core/Public/HAL/RunnableThread.h" class SPIKY_CLIENT_API FTCPSocketListeningTh : public FRunnable { FRunnableThread* Thread; static FTCPSocketListeningTh* Runnable; static bool bThreadRun; public: FTCPSocketListeningTh(); ~FTCPSocketListeningTh(); virtual bool Init(); virtual uint32 Run(); static FTCPSocketListeningTh* RunSocketListening(); static void Shutdown(); }; #include "Spiky_Client.h" #include "TCPSocketListeningTh.h" #include "SocketObject.h" #include "MessageDecoder.h" #include <google/protobuf/io/zero_copy_stream_impl_lite.h> #include <google/protobuf/io/coded_stream.h> #include "Protobufs/MessageModels.pb.h" #include "Async.h" FTCPSocketListeningTh* FTCPSocketListeningTh::Runnable = nullptr; bool FTCPSocketListeningTh::bThreadRun = false; FTCPSocketListeningTh::FTCPSocketListeningTh() { Thread = FRunnableThread::Create(this, TEXT("TCP_RECEIVER"), 0, TPri_BelowNormal); } FTCPSocketListeningTh::~FTCPSocketListeningTh() { delete Thread; Thread = nullptr; } bool FTCPSocketListeningTh::Init() { bThreadRun = true; return true; } uint32 FTCPSocketListeningTh::Run() { while (bThreadRun) { // if (USocketObject::bIsConnection == false) // { FPlatformProcess::Sleep(1.f); // , } else { FPlatformProcess::Sleep(0.03f); if (!USocketObject::tcp_socket) return 0; //Binary Array! TArray<uint8> ReceivedData; uint32 Size; while (USocketObject::tcp_socket->HasPendingData(Size)) // { ReceivedData.Init(FMath::Min(Size, 65507u), Size); int32 Read = 0; USocketObject::tcp_socket->Recv(ReceivedData.GetData(), ReceivedData.Num(), Read); } if (ReceivedData.Num() > 0) { GLog->Log(FString::Printf(TEXT("Data Read! %d"), ReceivedData.Num()) + " | FTCPSocketListeningTh::Run"); // protobuf uint8_t * buffer = ReceivedData.GetData(); size_t size = ReceivedData.Num(); google::protobuf::io::ArrayInputStream arr(buffer, size); google::protobuf::io::CodedInputStream input(&arr); bool protosize = true; /* , tcp */ while (protosize) { std::shared_ptr<Wrapper> wrapper(new Wrapper); protosize = USocketObject::ReadDelimitedFrom(&input, wrapper.get()); /* , */ AsyncTask(ENamedThreads::GameThread, [wrapper]() { UMessageDecoder * Handler = NewObject<UMessageDecoder>(UMessageDecoder::StaticClass()); Handler->SendProtoToDecoder(wrapper.get()); }); } } } } return 0; } FTCPSocketListeningTh* FTCPSocketListeningTh::RunSocketListening() { if (!Runnable && FPlatformProcess::SupportsMultithreading()) { Runnable = new FTCPSocketListeningTh(); } return Runnable; } void FTCPSocketListeningTh::Shutdown() { bThreadRun = false; GLog->Log("FTCPSocketListeningTh::Shutdown()"); if (Runnable) { delete Runnable; Runnable = nullptr; } }
... #include "ServerStatusCheckingTh.h" #include "TCPSocketListeningTh.h" ... // USpikyGameInstance::Init() // FServerStatusCheckingTh::RunServerChecking(); // tcp FTCPSocketListeningTh::RunSocketListening(); // USpikyGameInstance::Shutdown() // FServerStatusCheckingTh::Shutdown(); // tcp FTCPSocketListeningTh::Shutdown();
// Copyright (c) 2017, Vadim Petrov - MIT License #include "Spiky_Client.h" #include "MessageEncoder.h" #include "SocketObject.h" #include "Protobufs/MessageModels.pb.h" #include <google/protobuf/io/zero_copy_stream_impl_lite.h> #include <google/protobuf/io/coded_stream.h> bool UMessageEncoder::Send(google::protobuf::Message * message, bool bCrypt, bool bTCP) { Wrapper wrapper; // if (bCrypt) { } else { if (message->GetTypeName() == "Utility") { Utility * mes = static_cast<Utility*>(message); wrapper.set_allocated_utility(mes); } } size_t size = wrapper.ByteSize() + 5; // include size, varint32 never takes more than 5 bytes uint8_t * buffer = new uint8_t[size]; google::protobuf::io::ArrayOutputStream arr(buffer, size); google::protobuf::io::CodedOutputStream output(&arr); // buffer output.WriteVarint32(wrapper.ByteSize()); wrapper.SerializeToCodedStream(&output); // utility if (wrapper.has_utility()) { wrapper.release_utility(); } int32 bytesSent = 0; bool sentState = false; if (bTCP) { //send by tcp sentState = USocketObject::tcp_socket->Send(buffer, output.ByteCount(), bytesSent); } else { //send by udp sentState = USocketObject::udp_socket->SendTo(buffer, output.ByteCount(), bytesSent, *USocketObject::udp_address); } delete[] buffer; return sentState; }
utility { alive: true }
Connect state (bIsConnection) = 1 | FServerStatusCheckingTh::CheckServer
Data Read! 5 | FTCPSocketListeningTh::Run
Source: https://habr.com/ru/post/333788/
All Articles