簡體   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