我正在尝试在一个Ruby服务器和一个连接到虚幻引擎4的C ++库之间实现一个简单的本地TCP通信。
我已经使用了一些示例代码的Ruby服务器,它使用socket
库和instanciates TCPServer
:
require 'socket' puts "Starting up server..." # establish the server ## Server established to listen for connections on port 2008 server = TCPServer.new(15300) # setup to listen and accept connections while (session = server.accept) #start new thread conversation ## Here we will establish a new thread for a connection client Thread.start do ## I want to be sure to output something on the server side ## to show that there has been a connection puts "log: Connection from #{session.peeraddr[2]} at #{session.peeraddr[3]}" puts "log: got input from client" ## lets see what the client has to say by grabbing the input ## then display it. Please note that the session.gets will look ## for an end of line character "\n" before moving forward. input = session.gets puts input ## Lets respond with a nice warm welcome message session.puts "Server: Welcome #{session.peeraddr[2]}\n" # reply with goodbye ## now lets end the session since all we wanted to do is ## acknowledge the client puts "log: sending goodbye" session.puts "Server: Goodbye\n" end #end thread conversation end #end loop
这个应用程序,如果与ruby客户端testing,工作得很好。
这是客户:
require 'socket' # establish connection ## We need to tell the client where to connect ## Conveniently it is on localhost at port 15300! clientSession = TCPSocket.new( "localhost", 15300 ) puts "log: starting connection" #send a quick message ## Note that this has a carriage return. Remember our server ## uses the method gets() to get input back from the server. puts "log: saying hello" clientSession.puts "Client: Hello Server World!\n" #wait for messages from the server ## You've sent your message, now we need to make sure ## the session isn't closed, spit out any messages the server ## has to say, and check to see if any of those messages ## contain 'Goodbye'. If they do we can close the connection while !(clientSession.closed?) && (serverMessage = clientSession.gets) ## lets output our server messages puts serverMessage #if one of the messages contains 'Goodbye' we'll disconnect ## we disconnect by 'closing' the session. if serverMessage.include?("Goodbye") puts "log: closing connection" clientSession.close end end #end loop
服务器输出:
Starting up server... log: Connection from ::1 at ::1 log: got input from client Client: Hello Server World! log: sending goodbye
但是当我尝试使用C ++ 11和虚幻引擎4中的TCP函数连接服务器时,我没有得到来自在Ruby中实现的服务器的任何响应(甚至没有“连接来自…”)。
为了理解什么是我尝试运行一些networking分析的问题,从最简单的(Window的资源监视器)开始,到最复杂的(ZenMap)。 在任何情况下都不会有单个服务在选定端口打开的情况下运行(端口15300)。 我已经仔细检查了每一个可能的原因(例如防火墙,其他安全软件),但没有阻止ruby解释器。
为了理解为什么这样一个简单的应用程序不工作,我开始使用Wireshark。 那时我注意到没有本地回送接口,它需要我使用RawCap(设法捕获本地通信并将它们转储到文件上)。 使用它,我设法在我的机器上运行ruby客户机/服务器对和Cygwin Socat /虚幻引擎4时转储本地通信。我发现非常莫名其妙:在端口上没有打开本地TCP套接字ruby对(端口15300),但由虚幻引擎4打开的TCP端口在那里(以及端口15301,我用于testing)。
更新01
我已经更改了虚幻引擎4应用程序中的代码,因为第一个版本使用了默认使用bind
而不是connect
的包含TCPsocket构build器。 现在的代码是:
bool UNetworkBlueprintLibrary::NetworkSetup(int32 ServerPort) { bool res = false; // Creating a Socket pointer, wich will temporary contain our FSocket* Socket = nullptr; ISocketSubsystem* SocketSubsystem = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM); // Instead of that useless FTcpSocketBuilder I will try to create the socket by hand and then debug it... >:( if (SocketSubsystem != nullptr) { // Try to create a stream socket using the system-intependent interface Socket = SocketSubsystem->CreateSocket(NAME_Stream, TEXT("Server Socket"), false); if (Socket != nullptr) { FIPv4Address ServerAddress = FIPv4Address(127, 0, 0, 1); TSharedRef<FInternetAddr> LocalAddress = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->CreateInternetAddr(); uint16 castServerPort = (uint16)ServerPort; // Attach received port and IPAddress to Internet Address pointer LocalAddress->SetIp(ServerAddress.GetValue()); LocalAddress->SetPort(castServerPort); bool SocketCreationError = !Socket->Connect(*LocalAddress); if (SocketCreationError) { GLog->Logf(TEXT("Failed to create Server Socket as configured!")); SocketSubsystem->DestroySocket(Socket); Socket = nullptr; } } } if (Socket != nullptr){ UNetworkBlueprintLibrary::ServerSocket = Socket; res = true; } else { res = false; } return res; }
为了testing虚幻引擎4中的代码是否正常工作,我使用了Cygwin下的socat
:
socat tcp-listen:15300 readline
一旦我的虚幻引擎4应用程序启动,我可以通过套接字发送数据。 我已经证实了这个工作,消除了在虚幻引擎4中开发的应用程序不能通过TCP套接字进行通信的可能性。
鉴于这个积极的结果,我再次尝试使用这个问题上面报告的服务器代码,删除等待来自客户端的消息的行,但结果是相同的:服务器甚至不输出它应该打印的debugging行当有连接时:
puts "log: Connection from #{session.peeraddr[2]} at #{session.peeraddr[3]}"
更新02
回来一次!
我设法使ruby
和Unreal Engine 4
通过本地TCP套接字进行通信。 我需要做的ruby服务器的工作是明确提供本地地址,如下所示:
server = TCPServer.new("127.0.0.1", 15300)
但是,即使这个问题解决了,我仍然对第一次提出的一些问题感兴趣。
更新03
只是我在最后一个小时做的一个考虑。
当我没有提供一个明确的服务器地址的服务器,这个命令
puts "log: Connection from #{session.peeraddr[2]} at #{session.peeraddr[3]}"
回
log: Connection from ::1 at ::1
这确实是对的! ::1
是127.0.0.1
的IPv6版本,所以看起来像ruby
假定它必须创build一个IPv6套接字而不是IPv4。 Unreal Engine 4
不提供IPv6接口,所以这可能是应用程序无法工作的原因。
现在在转储时通过localhost
进行通信,通过端口15300显示以下通信:
No. Time Source Destination Protocol Length Info 105 7.573433 127.0.0.1 127.0.0.1 TCP 52 9994→15300 [SYN] Seq=0 Win=8192 Len=0 MSS=65495 WS=256 SACK_PERM=1 106 7.573433 127.0.0.1 127.0.0.1 TCP 52 15300→9994 [SYN, ACK] Seq=0 Ack=1 Win=8192 Len=0 MSS=65495 WS=256 SACK_PERM=1 107 7.573433 127.0.0.1 127.0.0.1 TCP 40 9994→15300 [ACK] Seq=1 Ack=1 Win=8192 Len=0 108 7.583434 127.0.0.1 127.0.0.1 TCP 66 15300→9994 [PSH, ACK] Seq=1 Ack=1 Win=8192 Len=26 109 7.583434 127.0.0.1 127.0.0.1 TCP 40 9994→15300 [ACK] Seq=1 Ack=27 Win=7936 Len=0 110 7.583434 127.0.0.1 127.0.0.1 TCP 56 15300→9994 [PSH, ACK] Seq=27 Ack=1 Win=8192 Len=16 111 7.583434 127.0.0.1 127.0.0.1 TCP 40 9994→15300 [ACK] Seq=1 Ack=43 Win=7936 Len=0 208 16.450941 127.0.0.1 127.0.0.1 TCP 52 9995→15300 [SYN] Seq=0 Win=8192 Len=0 MSS=65495 WS=256 SACK_PERM=1 209 16.451941 127.0.0.1 127.0.0.1 TCP 52 15300→9995 [SYN, ACK] Seq=0 Ack=1 Win=8192 Len=0 MSS=65495 WS=256 SACK_PERM=1 210 16.451941 127.0.0.1 127.0.0.1 TCP 40 9995→15300 [ACK] Seq=1 Ack=1 Win=8192 Len=0 211 16.456941 127.0.0.1 127.0.0.1 TCP 66 15300→9995 [PSH, ACK] Seq=1 Ack=1 Win=8192 Len=26 212 16.456941 127.0.0.1 127.0.0.1 TCP 40 9995→15300 [ACK] Seq=1 Ack=27 Win=7936 Len=0 213 16.456941 127.0.0.1 127.0.0.1 TCP 56 15300→9995 [PSH, ACK] Seq=27 Ack=1 Win=8192 Len=16 214 16.456941 127.0.0.1 127.0.0.1 TCP 40 9995→15300 [ACK] Seq=1 Ack=43 Win=7936 Len=0
当包显示26或16的LEN
意味着他们正在发送
Server: Welcome 127.0.0.1.
要么
Server: Goodbye.
我只是想分享这些信息,因为它对于答案并不是很有用,但是显示了IPv6通信如何不通过标准的localhost
虚拟适配器。
问题
我想了解的是: