【问题标题】:C# Client-Server Sockets not connectingC# 客户端-服务器套接字未连接
【发布时间】:2018-03-11 23:33:44
【问题描述】:

我输入了以下视频教程中的 C# 客户端/服务器课程...

C# Socket Programming - Multiple Clients

我使用 Visual Studio 2017 编译了该程序。

程序编译无误,可在单台计算机上运行。也就是说,如果我在同一台计算机上同时运行客户端和服务器,它们就可以正常连接。所以一切似乎都在工作。

但是,当我尝试将客户端和服务器放在家庭网络上的不同计算机上时,它们将无法连接。当安全防火墙询问时,我允许他们都拥有完全访问权限。

我不明白为什么将它们放在通过 WiFi 连接的同一个家庭网络上的不同计算机上时它们无法工作。计算机共享文件没有问题。

此外,在 YouTube 上的视频课程下方是已输入文件的链接。我什至将它们复制并粘贴到 Visual Studio 中并编译它们。但我得到完全相同的结果。它们在单台机器上编译和运行都很好,但我无法让它们在不同的机器上连接。

有什么想法吗?

我对只能连接到自身的计算机没有用处。

我做错了什么?

这里是硬拷贝客户端代码的链接:

Multi Client

这里是硬拷贝服务器代码的链接:

Multi Server

这是一个非常短的程序。

我不知道我做错了什么。我是否需要添加更多内容才能使其真正识别除自身以外的计算机?

客户端代码:

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

namespace MultiClient
{
class Program
{
    private static readonly Socket ClientSocket = new Socket
        (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

    private const int PORT = 100;

    static void Main()
    {
        Console.Title = "Client";
        ConnectToServer();
        RequestLoop();
        Exit();
    }

    private static void ConnectToServer()
    {
        int attempts = 0;

        while (!ClientSocket.Connected)
        {
            try
            {
                attempts++;
                Console.WriteLine("Connection attempt " + attempts);
                // Change IPAddress.Loopback to a remote IP to connect to a remote host.
                ClientSocket.Connect(IPAddress.Loopback, PORT);
            }
            catch (SocketException) 
            {
                Console.Clear();
            }
        }

        Console.Clear();
        Console.WriteLine("Connected");
    }

    private static void RequestLoop()
    {
        Console.WriteLine(@"<Type ""exit"" to properly disconnect client>");

        while (true)
        {
            SendRequest();
            ReceiveResponse();
        }
    }

    /// <summary>
    /// Close socket and exit program.
    /// </summary>
    private static void Exit()
    {
        SendString("exit"); // Tell the server we are exiting
        ClientSocket.Shutdown(SocketShutdown.Both);
        ClientSocket.Close();
        Environment.Exit(0);
    }

    private static void SendRequest()
    {
        Console.Write("Send a request: ");
        string request = Console.ReadLine();
        SendString(request);

        if (request.ToLower() == "exit")
        {
            Exit();
        }
    }

    /// <summary>
    /// Sends a string to the server with ASCII encoding.
    /// </summary>
    private static void SendString(string text)
    {
        byte[] buffer = Encoding.ASCII.GetBytes(text);
        ClientSocket.Send(buffer, 0, buffer.Length, SocketFlags.None);
    }

    private static void ReceiveResponse()
    {
        var buffer = new byte[2048];
        int received = ClientSocket.Receive(buffer, SocketFlags.None);
        if (received == 0) return;
        var data = new byte[received];
        Array.Copy(buffer, data, received);
        string text = Encoding.ASCII.GetString(data);
        Console.WriteLine(text);
    }
}
}

服务器代码:

using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;

namespace MultiServer
{
    class Program
    {
        private static readonly Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        private static readonly List<Socket> clientSockets = new List<Socket>();
        private const int BUFFER_SIZE = 2048;
        private const int PORT = 100;
        private static readonly byte[] buffer = new byte[BUFFER_SIZE];

        static void Main()
        {
            Console.Title = "Server";
            SetupServer();
            Console.ReadLine(); // When we press enter close everything
            CloseAllSockets();
        }

        private static void SetupServer()
        {
            Console.WriteLine("Setting up server...");
            serverSocket.Bind(new IPEndPoint(IPAddress.Any, PORT));
            serverSocket.Listen(0);
            serverSocket.BeginAccept(AcceptCallback, null);
            Console.WriteLine("Server setup complete");
        }

        /// <summary>
        /// Close all connected client (we do not need to shutdown the server socket as its connections
        /// are already closed with the clients).
        /// </summary>
        private static void CloseAllSockets()
        {
            foreach (Socket socket in clientSockets)
            {
                socket.Shutdown(SocketShutdown.Both);
                socket.Close();
            }

            serverSocket.Close();
        }

        private static void AcceptCallback(IAsyncResult AR)
        {
            Socket socket;

            try
            {
                socket = serverSocket.EndAccept(AR);
            }
            catch (ObjectDisposedException) // I cannot seem to avoid this (on exit when properly closing sockets)
            {
                return;
            }

           clientSockets.Add(socket);
           socket.BeginReceive(buffer, 0, BUFFER_SIZE, SocketFlags.None, ReceiveCallback, socket);
           Console.WriteLine("Client connected, waiting for request...");
           serverSocket.BeginAccept(AcceptCallback, null);
        }

        private static void ReceiveCallback(IAsyncResult AR)
        {
            Socket current = (Socket)AR.AsyncState;
            int received;

            try
            {
                received = current.EndReceive(AR);
            }
            catch (SocketException)
            {
                Console.WriteLine("Client forcefully disconnected");
                // Don't shutdown because the socket may be disposed and its disconnected anyway.
                current.Close(); 
                clientSockets.Remove(current);
                return;
            }

            byte[] recBuf = new byte[received];
            Array.Copy(buffer, recBuf, received);
            string text = Encoding.ASCII.GetString(recBuf);
            Console.WriteLine("Received Text: " + text);

            if (text.ToLower() == "get time") // Client requested time
            {
                Console.WriteLine("Text is a get time request");
                byte[] data = Encoding.ASCII.GetBytes(DateTime.Now.ToLongTimeString());
                current.Send(data);
                Console.WriteLine("Time sent to client");
            }
            else if (text.ToLower() == "exit") // Client wants to exit gracefully
            {
                // Always Shutdown before closing
                current.Shutdown(SocketShutdown.Both);
                current.Close();
                clientSockets.Remove(current);
                Console.WriteLine("Client disconnected");
                return;
            }
            else
            {
                Console.WriteLine("Text is an invalid request");
                byte[] data = Encoding.ASCII.GetBytes("Invalid request");
                current.Send(data);
                Console.WriteLine("Warning Sent");
            }

            current.BeginReceive(buffer, 0, BUFFER_SIZE, SocketFlags.None, ReceiveCallback, current);
        }
    }
}

注意:我认为代码可能还不错。我的问题很可能是权限问题?还是防火墙设置?或者我可能需要指定 IP 地址?

显然这个程序没有报告任何错误。它只是无法在同一网络上通过 WiFi 连接的两台笔记本电脑之间进行连接。

如果客户端和服务器在同一台计算机上运行,​​它就可以正常工作。但这没什么用。

【问题讨论】:

  • 请花时间阅读How to Ask并发布minimal reproducible example
  • 如果您尝试从同一网络上的两台不同机器连接,您需要在客户端机器上指定 IP 地址(服务器机器)。另外请检查您的防火墙。 eg : ClientSocket.Connect("指定服务器IP", PORT);

标签: c# sockets client-server


【解决方案1】:

好的,BEN SEBASTIAN 回答了我的问题。

我所要做的就是在客户端软件中指定服务器 IP。

ClientSocket.Connect("specify the server IP", PORT);

我以为我昨天已经尝试过了,但无法让它工作,但今天它连接起来没有问题。这就是我们所需要的一切。

很遗憾,原始视频教程没有详细说明这一点,或者如果他详细说明了,我错过了。

无论如何,这解决了问题。

感谢 Ben 花时间阅读并回复我的问题。

现在我需要找到一种方法来确保我的服务器笔记本始终具有相同的 IP 地址。我不确定它是由 WiFi 路由器分配的,还是硬编码到笔记本中的。它可能是动态分配的,所以我可能想修改它以确保它始终相同。不能有一个 IP 地址不可靠的服务器。

【讨论】:

    最近更新 更多