Как создать соединение Socket между Unity / C # Server и Android / Java Client? - PullRequest
0 голосов
/ 11 января 2019

Я работаю над академическим проектом, который состоит в управлении имитируемой средой, созданной в Unity3D, из обычного приложения для Android. Я уже создал сценарий в Unity, и мобильное приложение полностью завершено, моя проблема в соединении. Я решил использовать сокеты из-за его простоты. Мне удалось подключить приложение к серверу, написанному на C #, через обычные сокеты, я знаю, что информацию можно отправлять, но когда я реализовал ее в Unity, все не удалось, поэтому я решил использовать TCP Listener вместо Sockets в Unity / C # (клиент Android по-прежнему использует обычное 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: сервер сокетов C # (пока нет Unity), работающий с Java-клиентом Android: ! [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);
    }

}

1 Ответ

0 голосов
/ 11 января 2019

Вот более подробный ответ, чем мой комментарий, для дальнейшего использования.

Проблема заключается в следующем, если проверка 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 the foreach loop unnecessarily, and the programm will try to call close () `на соединение, которое уже закрыто, что приводит к большему количеству ошибок. Удаление потока освободит его, так что сборщик мусора сможет его собрать, освободив память.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...