【问题标题】:TcpListener doesn't accept TcpClient when run on a different device [C#, Unity]TcpListener 在不同的设备上运行时不接受 TcpClient [C#, Unity]
【发布时间】:2017-07-27 12:33:24
【问题描述】:

服务器代码(用 .NET-Core 编写)

using System;
using System.Collections;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Text;
using System.Xml;
using System.Xml.Schema;
using Models;
using System.Collections.Generic;
using Newtonsoft.Json;
using Logger;
using System.IO;

public class Server
{
    private TcpListener listen;
    private int port;
    private IPAddress localAddress;
    private List<ClientModel> clients;
    private NetworkStream stream;
    private LoggerDevice logger;
    private Dictionary<IPAddress, PlayerModel> lockedPlayers;
    private string response;
    private bool isLuminol;
    private bool isFixative;

    /// <summary>
    /// Server constructor
    /// </summary>
    /// <param name="log">Object used to create server logs</param>
    public Server(LoggerDevice log)
    {
        port = 8000;
        localAddress = IPAddress.Parse(GetLocalIPAddress());
        listen = new TcpListener(localAddress, port);
        //listen = new TcpListener(IPAddress.Any, port);
        IPEndPoint iep = listen.LocalEndpoint as IPEndPoint;
        //localAddress = iep.Address;
        clients = new List<ClientModel>();

        response = string.Empty;
        logger = log;

        lockedPlayers = new Dictionary<IPAddress, PlayerModel>();

        isLuminol = false;
        isFixative = false;
    }


    /// <summary>
    /// Returns a local IP Address of the host
    /// </summary>
    /// <returns>Local IP Address of the host</returns>
    public static string GetLocalIPAddress()
    {
        var host = Dns.GetHostEntryAsync(Dns.GetHostName());
        Console.WriteLine("DNS HOSTNAME: " + Dns.GetHostName());
        foreach (var ip in host.Result.AddressList)
        {
            if (ip.AddressFamily == AddressFamily.InterNetwork)
            {
                return ip.ToString();
            }
        }
        throw new Exception("Local IP Address Not Found!");
    }

    /// <summary>
    /// Main server thread method
    /// Displays current IP Address and connects with clients
    /// </summary>
    public void ServThread()
    {
        response = "Adres IP serwera: " + ((IPEndPoint)(listen.LocalEndpoint)).Address.ToString() + '\n';
        Console.WriteLine(response);
        logger.WriteLine(response);

        ClientModel currentClient;

        listen.Start();

        while (true)
        {
            Console.WriteLine("Czekam na polaczenie...");
            currentClient = new ClientModel();

            currentClient.clientSender = listen.AcceptTcpClientAsync().Result;
            ThreadPool.QueueUserWorkItem(HandleClient, currentClient);
        }
    }

    /// <summary>
    /// Method creating and configuring a new instance of ClientModel
    /// Assigns new ClientModel.Id when needed and matches ClientModel with the assigned player if reconnecting
    /// </summary>
    /// <param name="c">Client to be handled (explicitly converted to ClientModel in the method)</param>
    private void HandleClient(object c)
    {
            ClientModel currentClient = (ClientModel)c;

            response = "Polaczono!";
            Console.WriteLine(response);
            logger.WriteLine(response);

            CommunicationModel currentCommunication = new CommunicationModel();
            Random rand = new Random();

            string currentID;
            if (string.IsNullOrEmpty(currentClient.Id))
            {
                Guid g = Guid.NewGuid();
                currentID = g.ToString();

                currentClient.Id = g.ToString();

                response = "Nadano nowe ID: " + currentClient.Id;
                Console.WriteLine(response);
                logger.WriteLine(response);
                clients.Add(currentClient);
            }
            currentID = currentClient.Id;

            currentCommunication.Id = currentID;

            IPEndPoint ipep = (IPEndPoint)currentClient.clientSender.Client.RemoteEndPoint;
            IPAddress ipa = ipep.Address;
            if (lockedPlayers.ContainsKey(ipa))
            {
                CommunicationModel mess = new CommunicationModel();
                string currentId = currentClient.Id;

                response = "Dolaczyl gracz ze zwiazanym playerem (ID: "+currentID+")";
                Console.WriteLine(response);
                logger.WriteLine(response);

                currentClient.clientSender.GetStream();
                currentClient.clientSender.GetStream().Flush();

                mess.Id = currentId;
                mess.Message = JsonConvert.SerializeObject(lockedPlayers[ipa]);

                mess.Type = 101;

                string comMess = JsonConvert.SerializeObject(mess);

                byte[] data = UTF8Encoding.UTF8.GetBytes(comMess);
                currentClient.clientSender.GetStream().Write(data, 0, data.Length);

                response = "Pomyslnie przypisano gracza z ID: "+currentId+"do jego domyslnego playera";
                Console.WriteLine(response);
                logger.WriteLine(response);
            }

            servMessReceived(clients.Find(x => x.Id.Equals(currentID)));
    }


public class ItemModel
{
    public string Name = "";
    public bool Have;
}

ServThread 是从其他脚本启动的。

客户端代码(Unity中的脚本)

using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using Models;
using UnityEngine;
using System.Collections;

class Client : MonoBehaviour
{
    TcpClient clientSocket;
    CommunicationModel mess;
    IPEndPoint end;
    PlayerNetworkController player;

    NetworkStream clientStream;
    int state = 0;
    byte[] rec = new byte[100000];
    int bytes;

    bool reading;

    private void Start()
    {
        //clientSocket = new TcpClient(AddressFamily.InterNetwork);
        mess = new CommunicationModel();
        player = IOC.Resolve<WorshipGameManager>("WorshipGameManager").playerNetworkController;
        bool reading = true;
    }

    private void Update()
    {

    }

    public void ConnectEnd(string ip)
    {
        end = new IPEndPoint(IPAddress.Parse(ip), 8000);

        clientSocket = new TcpClient(AddressFamily.InterNetwork);
        clientSocket.Connect(end.Address, end.Port);

        clientStream = clientSocket.GetStream();
        StartCoroutine(ReceiveMessage());
    }

    private IEnumerator ReceiveMessage()
    {
        //Odczytywanie odpowiedzi
        //clientStream = clientSocket.GetStream();
        float timePassed = 0.0f;
        rec = new byte[100000];
        while (true)
        {
            if (timePassed > 5.0f)
                timePassed = 0.0f;
            timePassed += Time.deltaTime;

            clientStream.BeginRead(rec, 0, rec.Length, new AsyncCallback(this.HandleMessage), this);

            yield return new WaitWhile(() => reading == true || timePassed >= 5.0f);
        }

    }

    public void HandleMessage(IAsyncResult ar)
    {
        reading = true;
        bytes = clientStream.EndRead(ar);
        clientStream.Flush();
        if (bytes > 0)
        {
            string responseMessage = UTF8Encoding.UTF8.GetString(rec, 0, bytes);
            Debug.Log("Message received: " + responseMessage);


            CommunicationModel cm = JsonUtility.FromJson<CommunicationModel>(responseMessage);
            Debug.Log("cm.Name: " + cm.Name);
            Debug.Log("cm.Type: " + cm.Type);
            Debug.Log("cm.Id: " + cm.Id);
            Debug.Log("cm.Message: " + cm.Message);

            if (player == null)
                player = IOC.Resolve<WorshipGameManager>("WorshipGameManager").playerNetworkController;

            switch (cm.Type)
            {
                case 100:
                    player.OnConnectToServer(""); break;
                case 101:
                    player.GetPlayerData(cm); break;
                case 111:
                    player.GetItemFromServer(cm); break;
                case 112:
                    player.SetLuminolActive(cm); break;
                case 113:
                    player.SetItemFromServer(cm); break;
                case 114:
                    player.SetType(cm); break;
            }
        }
        reading = false;
    }
    public void SendMessageAsync(short type, string message)
    {
        {
            byte[] rec = new byte[100000];

            mess.Id = "0";
            mess.Type = type;
            mess.Message = message;

            rec = Encoding.ASCII.GetBytes(JsonUtility.ToJson(mess));

            NetworkStream clientStream = clientSocket.GetStream();

            clientStream.Write(rec, 0, rec.Length);
            clientStream.Flush();

            message = Console.ReadLine();
        }
    }

    public void OnServerConnect()
    {
        Debug.Log("OnServerConnect");
        player.OnConnectToServer("");
    }
}

这是管理与服务器的所有连接的脚本。

在连接之前,播放器会看到一个菜单,其中包含一个 IP 输入字段和一个连接按钮,该按钮从其他脚本触发 OnConnectToServer(),该脚本从该脚本触发 ConnectEnd。

当我在编辑器中运行游戏时,服务器连接正常。只有当我构建应用程序并在我的 Android 设备上播放它时,它才无法连接(ServerApp 没有显示适当的消息)

我已经尝试在笔记本电脑上禁用防火墙,以管理员身份运行服务器并在连接到不同网络时测试这两个应用程序;

这与我计算机上的 Unity 构建过程或网络设置有关吗?或者我的脚本有问题?

编辑: LoggerDevice、ItemModel、CommunicationModel 都是包含在不同脚本中的类,它们不包含直接连接到服务器的方法

【问题讨论】:

    标签: c# android unity3d networking .net-core


    【解决方案1】:

    这是你的问题:

    port = 8000;
    localAddress = IPAddress.Parse(GetLocalIPAddress());
    listen = new TcpListener(localAddress, port);
    

    您正在侦听来自此 (IPAddress.Parse(GetLocalIPAddress())) ip 地址的连接。改成这段代码:

    port = 8000;
    localAddress = IPAddress.Any;
    listen = new TcpListener(localAddress, port);
    

    而且您应该能够从任何点连接。


    您可以在msdn page 上阅读:

    此构造函数允许您指定侦听传入连接尝试的本地 IP 地址和端口号。在调用此构造函数之前,您必须首先使用所需的本地地址创建一个 IPAddress。将此 IPAddress 作为 localaddr 参数传递给构造函数。如果您不关心分配了哪个本地地址,请为 localaddr 参数指定 IPAddress.Any,底层服务提供商将分配最合适的网络地址。如果您有多个网络接口,这可能有助于简化您的应用程序。如果您不关心使用哪个本地端口,您可以将端口号指定为 0。在这种情况下,服务提供商将分配一个介于 1024 和 5000 之间的可用端口号。如果您使用这种方法,您可以使用 LocalEndpoint 属性发现已分配的本地网络地址和端口号。

    【讨论】:

    • 如何显示服务器IP地址,以便在游戏中输入字段?
    • 和以前一样。上面的一段代码可以从指定的 IPAddress 之外连接到您的服务器。
    • 因为它是为外部连接打开的,所以使用你机器的IP,一切都应该可以正常工作
    猜你喜欢
    • 1970-01-01
    • 2011-10-06
    • 2012-01-16
    • 1970-01-01
    • 1970-01-01
    • 2017-03-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多