【问题标题】:How to create a Socket connection between Unity/C# Server and Android/Java Client?如何在 Unity/C# 服务器和 Android/Java 客户端之间创建 Socket 连接?
【发布时间】:2019-01-11 18:11:11
【问题描述】:

我正在从事一个学术项目,该项目包括从传统的 Android 应用程序控制在 Unity3D 中创建的模拟环境。我已经在 Unity 中创建了场景并且移动应用程序已经完全完成,我的问题在于连接。我选择使用套接字是因为它简单。我设法通过常规的 Sockets 将应用程序连接到用 C# 编写的服务器,我知道可以发送信息,但是当我在 Unity 中实现它时,一切都失败了,所以我决定在 Unity/C 中使用 TCP Listener 而不是 Sockets #(客户端Android仍然使用通过Sockets的常规TCP连接),实际上应用程序连接但没有信息传输,因为Unity控制台抛出错误说:ObjectDisposedException: Can not access to disposed object. Object name: 'System.Net.Sockets.TcpClient'.(错误出现在行号中56:stream = client.tcp.GetStream ();) 主要目标是获取信息流,这些信息流可以用以下形式表示:"1: 0: 1: 0" 并能够对该字符串进行拆分,并根据该值更改灯泡的状态或其他元素,但我需要基本的东西:建立连接流。我不是 C# 方面的专家,更不会使用 Unity,我对设计真的不太了解,但我想做一个创新的工作,希望有人能指导我。

PD:使用 Android Java 客户端的 C# Socket(尚无 Unity)服务器: ![1] https://imgur.com/a/HuNcDC3

//这是我的 Unity3D/C# 服务器:

public class SocketManager : MonoBehaviour
{
private List<ServerClient> connectedClients;
private List<ServerClient> disconectedClients;
private TcpListener server;
private string data;
private NetworkStream stream;
private StreamReader stremaReader;
private bool serverStarted;
public int socketPort = 7691;

private void Start()
{
    connectedClients = new List<ServerClient>();
    disconectedClients = new List<ServerClient>();
    try
    {
        server = new TcpListener(IPAddress.Parse("192.168.1.64"),        socketPort);
        server.Start();

        serverListening();
        serverStarted = true;
        Debug.Log("Server started. Port: " + socketPort.ToString());


    }
    catch (Exception ex)
    {
        Debug.Log("Server socket error: " + ex);
    }
}

private void Update()
{
    if (!serverStarted)
        return;

    foreach (ServerClient client in connectedClients)
    {
        if (IsConnected(client.tcp))
        {
            client.tcp.Close();
            disconectedClients.Add(client);
            continue;
        }
        else
        {
            stream = client.tcp.GetStream();
            if (stream.DataAvailable)
            {
                this.stremaReader = new StreamReader(stream, true);
                data = stremaReader.ReadLine();

                if (data != null)
                    OnIcomingData(client, data);
            }
        }
    }
}

private void OnIcomingData(ServerClient client, string data)
{
    Debug.Log(client.clientName + ": " + data);
}

private bool IsConnected(TcpClient tcp)
{
    try
    {

        if (tcp != null && tcp.Client != null && tcp.Client.Connected)
        {
            if (tcp.Client.Poll(0, SelectMode.SelectRead))
            {
                return !(tcp.Client.Receive(new byte[1], SocketFlags.Peek) == 0);
            }

            return true;

        }
        else
        {
            return false;
        }

    }
    catch
    {
        return false;
    }
}

private void serverListening()
{
    server.BeginAcceptTcpClient(AcceptTcpClient, server);
}
private void AcceptTcpClient(IAsyncResult asyncResult)
{
    TcpListener tcplistener = (TcpListener)asyncResult.AsyncState;
    connectedClients.Add(new ServerClient(tcplistener.EndAcceptTcpClient(asyncResult)));
    serverListening();
}

}

public class ServerClient
{

public TcpClient tcp;
public string clientName;

public ServerClient(TcpClient tcp)
{
    this.tcp = tcp;
    this.clientName = "Android";
}
}

// 这是我的 Android/Java 客户端:

public class SocketThread extends Thread {

private Socket adviser;
private DataOutputStream dataOut;

@Override
public void run() {
    super.run();
    Log.e("Status:", "Thread started");
    try {
        adviser = new Socket("192.168.1.64", 7691);
        dataOut = new DataOutputStream(adviser.getOutputStream());
    } catch (IOException ex) {
        Logger.getLogger(SocketThread.class.getName()).log(Level.SEVERE, null, ex);
    }
}

public void sendCommand(String text) {
    try {
        dataOut.writeUTF(text);
        Log.e("Sended Text: ", text);
    } catch (IOException ex) {
        Logger.getLogger(SocketThread.class.getName()).log(Level.SEVERE, null, ex);
    }

}

【问题讨论】:

  • 在你的 foreach 循环中,你得到一个 if 语句 if (IsConnected(client.tcp)),如果它是真的(客户端已连接),你通过调用 client.tcp.Close(); 关闭连接。这是故意的吗?还是您的意思是!IsConnected?如果客户端未连接(因为您关闭了连接,它将在下一次迭代中)您尝试使用stream = client.tcp.GetStream(); 获取流,因为流已关闭,所以这是不可能的。所以我认为if (!IsConnected(client.tcp)) 应该可以解决问题?
  • remy_rm,是的,你说得对,我非常感谢你的帮助,我不再有错误,但是,我没有显示我从手机发送的字符串,我知道两个设备都已连接,但服务器没有获取信息,我正在通过调试进行一些检查。 ..

标签: java c# android unity3d


【解决方案1】:

这是比我的评论更详细的答案,以供将来参考。

问题出在以下if检查if (IsConnected(client.tcp))

现在发生的情况是,当客户端连接到服务器时(因此 if 返回 true),您正在使用 client.tcp.Close(); 关闭连接并将连接添加到您的 disconectedClients 列表(但您是不从您的connectedClients 列表中删除客户端!这意味着客户端现在在两个列表中)。然后,当 foreach 循环的下一次迭代 foreach (ServerClient client in connectedClients) 出现时,if (IsConnected(client.tcp)) 将返回 false(客户端不再连接到服务器,因为您在上一次迭代中调用了 close()

然后您尝试在已关闭的流上调用stream = client.tcp.GetStream();,导致错误提示您无法获取流。

这应该可以解决它:

if (IsConnected(client.tcp))
{
    client.tcp.Close();
    client.tcp.Dispose(); //Dispose of a stream to release it for GC
    disconectedClients.Add(client);
    connectedClients.Remove(client); //Note to also remove the disconnected client from the connectedClients list.
    continue;
}
else
{ ...rest of logic }

请注意,我在已关闭的连接上添加了 connectedClients.Remove(client);client.tcp.Dispose(); to your logic closing the stream. If you don't do this it'll keep getting included in theforeachloop unnecessarily, and the programm will try to callclose()`,导致更多错误。处理流将释放它,以便垃圾收集器可以收集它,从而释放内存。

【讨论】:

    猜你喜欢
    • 2011-11-05
    • 2020-02-18
    • 1970-01-01
    • 2017-02-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-27
    • 1970-01-01
    相关资源
    最近更新 更多