繁体   English   中英

如何在Unity / C#服务器和Android / Java客户端之间创建Socket连接?

[英]How to create a Socket connection between Unity/C# Server and Android/Java Client?

我正在研究一个学术项目,该项目包括控制通过常规Android应用程序在Unity3D中创建的模拟环境。 我已经在Unity中创建了场景,并且移动应用程序已完全完成,我的问题出在连接上。 我选择使用套接字是因为它很简单。 我设法通过常规的套接字将应用程序连接到用C#编写的服务器,我知道可以发送信息,但是当我在Unity中实现它时,一切都失败了,所以我决定在Unity / C中使用TCP侦听器代替套接字#(客户端Android仍然通过Socket使用常规的TCP连接),实际上,应用程序已连接,但没有信息传输,因为Unity控制台抛出错误,提示: ObjectDisposedException: Can not access to disposed object. Object name: 'System.Net.Sockets.TcpClient'. 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#套接字(尚无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);
    }

}

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

问题在于如果检查if (IsConnected(client.tcp))存在以下问题。

现在发生的事情是,当客户端连接到服务器时(因此if返回true ),您正在使用client.tcp.Close();关闭连接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 the client.tcp.Dispose(); to your logic closing the stream. If you don't do this it'll keep getting included in the client.tcp.Dispose(); to your logic closing the stream. If you don't do this it'll keep getting included in the loop unnecessarily, and the programm will try to call client.tcp.Dispose(); to your logic closing the stream. If you don't do this it'll keep getting included in the foreach loop unnecessarily, and the programm will try to call在已经关闭的连接上loop unnecessarily, and the programm will try to call close()`,从而导致更多错误。 处理流将释放它,以便垃圾收集器可以收集它,从而释放内存。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM