Ruby如何在Windows 7下通过TCP管理本地主机通信?

时间:2015-06-03 11:03:26

标签: ruby windows c++11 tcp unreal-engine4

我正在尝试在Ruby服务器和与虚幻引擎4连接的C ++库之间实现简单的本地TCP通信。

我已经为ruby服务器使用了一些示例代码,它使用socket库并实现了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客户端进行测试,此应用程序可以正常运行。

这是客户:

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中实现的服务器获得任何响应(甚至不是“来自......的连接”)

要了解问题是什么,我尝试运行一些netwrok分析,从最简单的(Window的资源监视器)开始,到最复杂的(ZenMap)。在任何情况下,都没有一个服务在所选端口打开的情况下运行(端口15300)。我已经仔细检查了每一个可能的原因(例如防火墙,其他安全软件),但没有阻止ruby解释器。

为了理解为什么这么简单的应用程序无法正常工作,我开始使用Wireshark。就在那时我注意到没有本地环回接口,这需要我使用RawCap(它设法捕获本地通信并将它们转储到文件中)。使用它我在ruby客户端/服务器对和Cygwin Socat /虚幻引擎4的运行期间设法将本地通信转储到我的机器上。我发现的是非常令人费解的:端口上没有打开的本地TCP套接字用于ruby pair(端口15300),但虚幻引擎4打开的TCP端口(以及端口15301,我用于测试的端口)。

更新01

我已经更改了我的虚幻引擎4应用程序中的代码,因为第一个版本使用了包含的TCPsocket构建器,默认情况下使用bind而不是connect。现在代码是:

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;
} 

为了测试虚幻引擎4中的代码是否正常工作,我在Cygwin下使用了socat

socat tcp-listen:15300 readline

一旦我的虚幻引擎4应用程序启动,我就可以通过套接字发送数据。我已经确认这是有效的,消除了我在虚幻引擎4中开发的应用程序没有通过TCP套接字进行通信的可能性。

鉴于这个积极的结果,我再次尝试使用在此问题之上报告的服务器代码,删除等待来自客户端的消息的行,但结果是相同的:服务器甚至不输出调试行它应该在有连接时打印:

puts "log: Connection from #{session.peeraddr[2]} at #{session.peeraddr[3]}"

更新02

再次回来!

我设法让rubyUnreal 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

哪个确实是对的! ::1127.0.0.1的IPv6版本,因此看起来ruby假定它必须创建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虚拟适配器。

问题

我想了解的是:

  • 由于没有本地环回接口,ruby如何通过本地TCP套接字进行通信?

0 个答案:

没有答案