Aaron Hull Aaron Hull - 4 months ago 63
Python Question

Minimalist Python Server for Unity3d 5.x

TL;DR: I'm having trouble communicating between a Unity3D client app and a UDP python listener on the server.

I'm trying to simply get a low-level call-and-response from a Unity3D game client via Unity 5.x NetworkTransport LLAPI and Python 3.x socket module

Goal:
Bounce the message sent to the server back to the client.

Problem:


  • The socket opens and the server prints a new recvfrom data every second when I run the Unity3d client, but unity never receives the bounced data.

  • After ~10sec, the client receives a Timeout error along with a DisconnectEvent.



Status:

Client: Unity 5.4

Server: Amazon AWS, port 8888 open

Server-side python app:

import socket

s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind(('', 8888))

print ('Listening on port 8888')

while True:
data, addr = s.recvfrom(4096)

if data:
for i in range(0, len(data)):
print (data[i])
print (data, addr)
s.sendto(data, addr)


Client-side Unity networking class:

using UnityEngine;
using UnityEngine.Networking;
using System.Collections;

public class NetworkExecutor : MonoBehaviour
{
const string addr = IP_ADDR;
const int port = PORT;

bool connected = false;

// Doing lots of error checks but no need to save them. Let's def this and hold onto it.
byte e;

void Start ()
{
// Some testing involves waiting for responses or repetitious send/receive calls.
// We do this in coroutines for both efficiency and human sanity.
StartCoroutine(TestNetwork());
}

IEnumerator TestNetwork()
{
// Define network configurations.
ConnectionConfig config = new ConnectionConfig();
int reliableChannel = config.AddChannel(QosType.Reliable);
int maxConnections = 10;
HostTopology hostTopo = new HostTopology(config, maxConnections);

// Initialize and connect network with config.
NetworkTransport.Init();
int hostId = NetworkTransport.AddHost(hostTopo);
int connectionId = NetworkTransport.Connect(hostId, addr, port, 0, out e);

Debug.Log("<b>Connect.</b> Host ID: " + hostId + " Connection ID: " + connectionId);
ErrStr(e);

// Send test message.
byte[] msg = System.Text.Encoding.UTF8.GetBytes("Send string");
NetworkTransport.Send(hostId, connectionId, reliableChannel, msg, 4096, out e);
Debug.Log("<b>Send.</b> Msg: " + msg);
ErrStr(e);

// Receive test message.
int recHostId;
int recConnectionId;
int recChannelId;
int recSize;
msg = System.Text.Encoding.UTF8.GetBytes("Unmodified byte buffer.");
NetworkEventType eventType = NetworkTransport.Receive(out recHostId, out recConnectionId, out recChannelId, msg, 4096, out recSize, out e);
Debug.Log("<b>Receive.</b> Type: " + eventType + " Msg: " + System.Text.Encoding.UTF8.GetString(msg));
Debug.Log("(hID:" + recHostId + " cID:" + recConnectionId + " chId:" + recChannelId + " " + recSize + ")");
ErrStr(e);

NetworkTransport.Disconnect(hostId, connectionId, out e);
ErrStr(e);

yield break;
}

string ErrStr(byte e)
{
switch ((NetworkError)e)
{
case NetworkError.Ok:
return "Ok";
case NetworkError.WrongHost:
return "<color=red>Wrong Host</color>";
case NetworkError.WrongConnection:
return "<color=red>Wrong Connection</color>";
case NetworkError.WrongChannel:
return "<color=red>Wrong Channel</color>";
case NetworkError.NoResources:
return "<color=red>No Resources</color>";
case NetworkError.BadMessage:
return "<color=red>Bad Message</color>";
case NetworkError.Timeout:
return "<color=red>Timeout</color>";
case NetworkError.MessageToLong:
return "<color=red>Message Too Long</color>";
case NetworkError.WrongOperation:
return "<color=red>Wrong Operation</color>";
case NetworkError.VersionMismatch:
return "<color=red>Version Mismatch</color>";
case NetworkError.CRCMismatch:
return "<color=red>CRC Mismatch</color>";
case NetworkError.DNSFailure:
return "<color=red>DNS Failure</color>";
default:
return "<color=red><b>Big problem, we don't know this error code.</b></color>";
}
}
}


** Forgive the mess. Against my natural urges, many coding conventions and good practices are ignored here. This is because the app only serves the purpose of understanding Unity's and Python's most basic low-level networking usage. When a primitive semaphore can be established, this will be discarded and rewritten properly.

Answer

UDP and TCP are both standard protocol. This means that no matter what programming language you use, they should be able to communicate with each other.

Your python code is using standard UDP code. Your Unity code is not. The NetworkTransport API you used is only made for communication between two Unity applications. It is an LLAPI library which is a tin layer built on of UDP. Again, it is not meant to be used for connection between Unity and a standard UDP connection, but between two Unity programs.

To communicate with your python UDP code, you must use the UdpClient class from the System.Net.Sockets namespace, in your C# code. Here is an example of a UDP code in Unity.