【问题标题】:Unable to connect to a TCPClient on another computer无法连接到另一台计算机上的 TCPClient
【发布时间】:2016-08-18 22:07:02
【问题描述】:

所以我有两台笔记本电脑连接到同一个 wifi 网络,其中一台运行一个非常简单的服务器,另一台运行一个非常简单的客户端连接到它。当我在一台笔记本电脑上同时运行服务器和客户端时,它们可以毫无问题地连接,但在每台笔记本电脑上运行一台时,客户端无法连接到服务器。

服务器的代码是这样的:

using System;
using System.Net;
using System.Net.Sockets;

namespace Utils
{
    /// <summary>
    /// A base server which handles listening for client connections and has simple API to communicate back and forth
    /// </summary>
    public class BaseServer
    {
        #region Properties and Fields

        /// <summary>
        /// The listener we can use to detect incoming connections from clients to the server
        /// </summary>
        private TcpListener Listener { get; set; }

        /// <summary>
        /// Our interface to the single client we are supporting for now
        /// </summary>
        public Comms ClientComms { get; private set; }

        /// <summary>
        /// Determines whether we have clients connected
        /// </summary>
        public bool Connections { get; private set; }

        #endregion

        public BaseServer()
        {
            Listener = new TcpListener(IPAddress.Any, 1490);
            Listener.Start();

            ListenForNewClient();
        }

        /// <summary>
        /// Starts an asynchronous check for new connections
        /// </summary>
        private void ListenForNewClient()
        {
            Listener.BeginAcceptTcpClient(AcceptClient, null);
        }

        /// <summary>
        /// Callback for when a new client connects to the server
        /// </summary>
        /// <param name="asyncResult"></param>
        protected virtual void AcceptClient(IAsyncResult asyncResult)
        {
            ClientComms = new Comms(Listener.EndAcceptTcpClient(asyncResult));
            ClientComms.OnDataReceived += ProcessMessage;

            ListenForNewClient();
        }

        #region Message Callbacks

        /// <summary>
        /// A function which is called when the Client sends a message to the server.
        /// Override to perform custom message handling
        /// </summary>
        /// <param name="data"></param>
        protected virtual void ProcessMessage(byte[] data) { }

        #endregion

    }
}

客户端的代码是这样的:

using System;
using System.Net.Sockets;

namespace Utils
{
    /// <summary>
    /// A base client class which connects and communicates with a remote server
    /// </summary>
    public class BaseClient
    {
        #region Properties and Fields

        /// <summary>
        /// The interface to the server
        /// </summary>
        public Comms ServerComms { get; private set; }

        #endregion

        public BaseClient(string ipAddress, int portNumber = 1490)
        {
            // Attempt to connect
            try
            {
                ServerComms = new Comms(new TcpClient(ipAddress, portNumber));
                ServerComms.OnDataReceived += OnMessageReceived;
                ServerComms.OnDisconnect += OnServerDisconnect;
            }
            catch (Exception e)
            {
                Console.WriteLine("Connection failed");
            }
        }

        #region Callbacks

        /// <summary>
        /// A function which is called when this client receives a message.
        /// Override to perform behaviour when custom messages arrive.
        /// </summary>
        /// <param name="data"></param>
        protected virtual void OnMessageReceived(byte[] data) { }

        /// <summary>
        /// A function called when this client can no longer communicate to the server it is connected to
        /// </summary>
        protected virtual void OnServerDisconnect() { }

        #endregion
    }
}

服务器是这样从主循环启动的:

using System;

namespace BuildServer
{
    class Program
    {
        static void Main(string[] args)
        {
            BaseServer server = new BaseServer();
            while (true)
            {

            }
        }
    }
}

客户端是这样启动的:

using System;
using Utils;

namespace BuildServerClient
{
    class Program
    {
        static void Main(string[] args)
        {
            BaseClient client = new BaseClient();

            while (true)
            {
                Console.WriteLine("Ready");
                string message = Console.ReadLine();
                client.ServerComms.Send(message);
            }
        }
    }
}

最后一个类是 Comms 类,它实际上是 TCPClient 的包装器,目前并未真正使用,但我添加它是为了保持完整性。

using System;
using System.IO;
using System.Net.Sockets;
using System.Text;
using static Utils.Delegates;

namespace Utils
{
    /// <summary>
    /// An interface to a client.
    /// Hides the nuts and bolts and provides a public interface of just data input and output from a data sender/receiver.
    /// </summary>
    public class Comms
    {
        #region Properties and Fields

        private TcpClient Client { get; set; }
        private MemoryStream ReadStream { get; set; }
        private MemoryStream WriteStream { get; set; }
        private BinaryReader Reader { get; set; }
        private BinaryWriter Writer { get; set; }

        /// <summary>
        /// Useful buffer for reading packeted messages from the server
        /// </summary>
        private byte[] ReadBuffer { get; set; }

        /// <summary>
        /// An event that is fired when this Comms receives a message
        /// </summary>
        public event OnDataReceived OnDataReceived;

        /// <summary>
        /// An event that is fired when this Comms can no longer communicate with the client sending it messages
        /// </summary>
        public event OnDisconnect OnDisconnect;

        #endregion

        public Comms(TcpClient client)
        {
            Client = client;
            ReadStream = new MemoryStream();
            WriteStream = new MemoryStream();
            Reader = new BinaryReader(ReadStream);
            Writer = new BinaryWriter(WriteStream);

            ReadBuffer = new byte[2048];
            Client.NoDelay = true;

            StartListening();
        }

        #region Data Sending Functions

        /// <summary>
        /// Convert a string to a byte array and then send to our client
        /// </summary>
        /// <param name="client"></param>
        /// <param name="str"></param>
        public void Send(string str)
        {
            SendByteArray(Encoding.UTF8.GetBytes(str));
        }

        /// <summary>
        /// Send a byte array to our client
        /// </summary>
        /// <param name="client"></param>
        /// <param name="bytes"></param>
        protected void SendByteArray(byte[] bytes)
        {
            Writer.Write(bytes);

            int bytesWritten = (int)WriteStream.Position;
            byte[] result = new byte[bytesWritten];

            WriteStream.Position = 0;
            WriteStream.Read(result, 0, bytesWritten);
            WriteStream.Position = 0;

            Client.GetStream().BeginWrite(result, 0, result.Length, null, null);
            Writer.Flush();
        }

        #endregion

        #region Data Receiving Functions

        /// <summary>
        /// Start listening for messages from the server
        /// </summary>
        private void StartListening()
        {
            try
            {
                Client.GetStream().BeginRead(ReadBuffer, 0, 2048, StreamReceived, null);
            }
            catch
            {
                OnDisconnect?.Invoke();
            }
        }

        /// <summary>
        /// Callback which processes a message sent from the server
        /// </summary>
        /// <param name="ar"></param>
        private void StreamReceived(IAsyncResult ar)
        {
            int bytesRead = 0;
            try
            {
                lock (Client.GetStream())
                {
                    bytesRead = Client.GetStream().EndRead(ar);
                }
            }
            catch { }

            //Create the byte array with the number of bytes read
            byte[] data = new byte[bytesRead];

            //Populate the array
            for (int i = 0; i < bytesRead; i++)
            {
                data[i] = ReadBuffer[i];
            }

            OnDataReceived?.Invoke(data);

            //Listen for new data
            StartListening();
        }

        #endregion
    }
}

IP 地址和端口号是正确的,因为它在同一台机器上运行时可以正常工作,我想这可能是防火墙问题还是什么?有没有人对可能导致此问题的原因有任何想法?

【问题讨论】:

  • 到底出了什么问题?
  • 无法连接并超时。在我创建 TCPClient & 的部分周围有一个 try catch,它总是因为超时而捕获异常。

标签: c# tcpclient tcplistener


【解决方案1】:

确保服务器计算机上的防火墙(Windows 防火墙或其他防火墙)已关闭,或者您的端口号存在防火墙例外。

【讨论】:

  • 我关闭了私有网络的防火墙,但还是不行。我也应该为访客和公共网络这样做吗?
  • 没有IP地址和端口号是正确的,因为当我在同一台计算机上运行它们时它们都可以工作(并且我没有使用本地主机作为我的IP地址)。
  • 如果您使用的是 127.0.0.1,那是错误的地址。
  • 我没有使用 127.0.0.1。我使用的是计算机的实际 IP 地址和正确的端口号。
  • 启动服务器实例。在另一台笔记本电脑上,尝试使用 Telnet 客户端和正确的端口号连接到服务器实例。您可能需要安装它(它是 Windows 的一部分 - 请参阅 technet.microsoft.com/en-us/library/cc771275(v=ws.10).aspx)。安装后,这篇文章 (support.symantec.com/en_US/article.TECH107919.html) 大致描述了我所了解的内容。如果 telnet 可以连接,但您的客户端不能,那么问题出在您的客户端。如果 telnet 无法连接,则说明您的 tcp 服务器、防火墙或网络存在问题。
【解决方案2】:

大卫的回答是正确的。我之前尝试过只为专用网络禁用防火墙。但是,我为访客和公共网络禁用了防火墙,效果很好。

codenoir 提出的测试方法在排除我的客户方面也非常有效。我怀疑这与防火墙有关,但一旦你排除了不可能......

感谢两位

【讨论】:

    猜你喜欢
    • 2019-07-18
    • 2016-09-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-15
    • 1970-01-01
    相关资源
    最近更新 更多