代码之家  ›  专栏  ›  技术社区  ›  JC97

C#SocketException无法连接,因为目标计算机已主动拒绝连接

  •  0
  • JC97  · 技术社区  · 6 年前

    首先,我用(非常简单的)以下代码启动服务器:

    服务器.cs

        private readonly MessageManager _messageManager;
        private readonly ChatServer _chatServer;
    
        public ChatServerSkeleton()
        {
            _messageManager = new MessageManager();
            _chatServer = new ChatServer();
            Console.WriteLine("Server is running on: " + _messageManager.MyAddress);
        }
    

    客户机.cs

        private readonly MessageManager _messageManager;
        public ChatClient ChatClient { get; }
    
        public ChatClientSkeleton(IPEndPoint serverAddress, string name)
        {
            _messageManager = new MessageManager();
            ChatClient = new ChatClient(new ChatServerStub(serverAddress, _messageManager), name);
    
            Console.WriteLine($"IPAddress of {name} is: {_messageManager.MyAddress}");
            Console.WriteLine($"IPAddress of Server is: { serverAddress}");
        }
    

        private readonly TcpListener _serverSocket;
        public IPEndPoint MyAddress { get; }
    
        public MessageManager()
        {
            try
            {
                //Create server socket on random port
                _serverSocket = new TcpListener(IPAddress.Any, FindFreeTcpPort());
    
                //Get host ip address
                IPAddress[] localIps = Dns.GetHostAddresses(Dns.GetHostName());
                IPAddress localhost = localIps.First(ip => ip.AddressFamily == AddressFamily.InterNetwork);
    
                //Get port of serversocket
                IPEndPoint ipEndPoint = _serverSocket.LocalEndpoint as IPEndPoint;
                int port = ipEndPoint.Port;
    
                //Create address
                MyAddress = new IPEndPoint(localhost, port);
            }
            catch (Exception ex)
            {
                Console.Error.WriteLine("Something went wrong with the serversocket:");
                Console.Error.WriteLine(ex);
            } 
        }
    

    FindFreeTcp端口来自这里: https://stackoverflow.com/a/150974/5985593

    到现在为止一切似乎都正常。例如,服务器现在 192.168.0.219:51080 还有客户 192.168.0.219:51085 .

    消息管理器.cs

        public void Send(MethodCallMessage message, IPEndPoint address)
        {
            try
            {
                _serverSocket.Start();
                TcpClient destination = new TcpClient(address.Address.ToString(), address.Port);
                NetworkStream output = destination.GetStream();
                MessageReaderWriter.Write(message, output);
                destination.Close();
            }
            catch (Exception ex)
            {
                Console.Error.WriteLine("Failed to write a message:");
                Console.Error.WriteLine(ex);
            }
            finally
            {
                _serverSocket.Stop();
            }
        }
    

    _server.Start(); 行。

    有人知道我做错了什么吗?

    提前谢谢!

    在服务器上注册客户端时,它可以正常运行1次。但在那之后,如果我想发送一条消息,我会得到SocketException,目标机器主动拒绝了它。

    消息管理器.cs

        public MethodCallMessage WReceive()
        {
            MethodCallMessage result = null;
    
            try
            {
                //_serverSocket.Start();
                TcpClient client = _serverSocket.AcceptTcpClient();
                NetworkStream input = new NetworkStream(client.Client, true);
                result = MessageReaderWriter.Read(input);
                client.Close();
            }
            catch (Exception ex)
            {
                Console.Error.WriteLine("Failed to receive a message:");
                Console.Error.WriteLine(ex);
            }
            finally
            {
                //_serverSocket.Stop();
            }
    
            return result;
        }
    

    此方法在ServerSkeleton&ClientSkeleton中使用,如下所示:

        public void Run()
        {
            while (true)
            {
                MethodCallMessage request = _messageManager.WReceive();
                HandleRequest(request);
            }
        }
    

    所以基本上流程如下:

    1. 我启动服务器(实例化新的消息管理器,第三个片段
    2. 服务器打印IP
    3. 将服务器ip设置为我复制粘贴的内容
    4. 启动客户端骨架(最后一个 片段)
    1 回复  |  直到 6 年前
        1
  •  1
  •   Rob    6 年前

    调用Start()的TcpListener侦听传入连接,然后将它们堆栈到队列中。一旦队列满了,就会产生套接字异常。要从队列中删除连接,您需要使用 AcceptTcpClient AcceptSocket TcpListener方法。然后,这将为您提供一个可以在其上发送和接收数据的连接。

    有一个重载方法。。。 TcpListener.Start(int backlog) ... 它允许您设置挂起队列列表的大小(这样您就可以有5、10个或更多的连接等待TcpListener接受)

    对于服务器TCP套接字,过程是设置它监听本地地址和端口。然后客户端尝试连接到该端点。当它们连接时,TCP侦听套接字接受连接,然后将其传递给一个套接字,该套接字是传输数据的套接字。侦听套接字继续侦听新连接,它本身不传输数据。

    我希望这有意义?

    _serverSocket.Start();
    TcpClient myAcceptedConnection = _serverSocket.AcceptTcpClient();
    // in synchronous blocking socket situation the program flow halts 
    // here til a connection is established
    // once you have a connection ... do stuff with myAcceptedConnection
    

    如果您希望避免阻塞场景,可以使用 TcpListener.Pending() 查看队列中是否有任何连接正在等待

    编辑1:

    就我个人而言,我会将服务器的监听方面与数据的发送和接收分开。。。使用它自己的独立方法,毕竟您希望您的服务器监听传入的连接,直到您关闭它。当您检测到一个传入连接(可能是通过检查循环中的Pending())时,就可以接受它并在新的TcpClient上发送和接收。当你完成了你在那个客户机上发送/接收的任何数据,你可以关闭它,如果这是你想要的。。。你不需要每次发送消息时都关闭和打开一个tcp连接,你可以让它一直打开,直到你完成它,事实上,打开和关闭tcp连接会在握手协议中产生一些开销。

    不过,也有一些警告。。。Tcp连接可能会变得“半开放”,尤其是无线连接可能会导致问题。进入这里有点复杂,但我推荐这一系列优秀的文章 Stephen Cleary 作为一个很好的通读。阅读整个博客,因为里面有很多好的信息。

    所以,简单地说,我会。。。

    1. 启动服务器侦听的server start()方法。
    2. 一个serverAccept()方法,检查是否有任何挂起的连接,如果有,则接受它们。
    3. 用于连接到服务器的客户端的client connect()方法

    通常情况下,流量是。。。

    1. 服务器侦听
    2. 客户端连接
    3. 服务器接受
    4. 服务器接收
    5. (然后服务器发送/接收,客户端发送/接收)