【问题标题】:Socket Programming c# / Client-Server communicationSocket 编程 c# / 客户端-服务器通信
【发布时间】:2016-02-29 19:03:21
【问题描述】:

我正在尝试在 .NET 中制作 2 个程序(在控制台应用程序中),通过 Web 一起进行通信(代码来自您可以在下面找到的视频,我只是想在调整代码之前让代码工作) .原谅我,我不是一个有经验的程序员。

我有一个服务器和一个客户端,当我在我的计算机(本地)上运行它们时它们都能完美运行。 我可以将多个客户端连接到服务器,发送请求并获得响应。 当我在一台计算机上运行服务器并在另一台计算机上运行客户端并尝试通过互联网连接时,我遇到了这个问题。

我可以连接到服务器但无法通信,例如尝试请求时间时没有数据交换。我认为问题主要来自网络本身而不是代码。

这是服务器的代码:

class Program
{
    private static Socket _serverSocket;
    private static readonly List<Socket> _clientSockets = new List<Socket>();
    private const int _BUFFER_SIZE = 2048;
    private const int _PORT = 50114;
    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()
    {
      //  IPAddress addip = GetBroadcastAddress();
        Console.WriteLine("Setting up server...");
        _serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        _serverSocket.Bind(new IPEndPoint(IPAddress.Any , _PORT));
        _serverSocket.Listen(5);
        _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");
            current.Close(); // Dont shutdown because the socket may be disposed and its disconnected anyway
            _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);
    }
}

这里是客户端代码:

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

    private const int _PORT = 50114;

    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);
                _clientSocket.Connect("IpAddr", _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 app
    /// </summary>
    private static void Exit()
    {
        SendString("exit"); // Tell the server we re 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);
    }
}
 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);
                _clientSocket.Connect("IpAddr", _PORT);
            }
            catch (SocketException) 
            {
                Console.Clear();
            }
        }

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

“IpAddr”是路由器公网IP的占位符。

这是我当前代码基于的视频:https://www.youtube.com/watch?v=xgLRe7QV6QI

我直接从中获取了代码(您可以在描述中链接的网站上找到 2 个代码文件)。

我运行服务器,它等待连接。然后我运行尝试连接到服务器的客户端。我连接并在服务器上显示连接成功。然后客户端发送一个类似“获取时间”的请求,服务器应该捕获并响应:

 byte[] data = Encoding.ASCII.GetBytes(DateTime.Now.ToLongTimeString());
 current.Send(data);

返回网络端:

这是我尝试过的所有方法的列表,在寻找解决方案大约一整天后,这些都是导致问题的常见主要原因:

  • 我已经有一个用于路由器的静态公共 IP(所以公共 IP 永远不会改变)。尽管如此,我还是在 noip.com 上创建了一个动态 dns。

  • 我为运行服务器的计算机提供了静态租约,因此它始终具有相同的本地 ip。

  • 我在 Windows 防火墙中创建了规则,以确保我使用的端口已打开。我在尝试通信的两台计算机上都这样做了。

  • 我转发了路由器上的端口,使其指向运行服务器的计算机的本地 IP。 (我尝试了很多不同的端口,没有机会)

  • 我尝试激活路由器上的“DMZ”,但很可能不是解决方案

  • 我尝试创建一个 ASP.NET 网站,该网站的页面返回一个字符串,使用 IIS 7.5 发布并设置它。在本地主机上工作,但使用像“xx.xxx.xxx.xx:PORT/default/index”这样的公共 ip 我得到一个错误。然而,它在错误中显示了网站名称。另外,当使用计算机的本地 IP 时,它也不起作用(例如 192.168.1.180)。

感谢您的帮助。

【问题讨论】:

  • 不要在 YouTube 上学习编码,买一本书。这个例子坏了,浪费时间。它没有实现协议,因此您的服务器永远不会收到“get time”,它在一个数据包中接收“get t”,在另一个数据包中接收“ime”。例如。至少,这就是我在快速跳过视频时看到的。如果您需要帮助调试代码,请在您的问题中包含所有相关代码。 :) 连接代码无关紧要并且有效,否则您会遇到无法连接的异常。错误出现在处理数据发送和接收的代码中。
  • 它在本地工作,我不需要任何调试,我花了很多时间在网上寻找解决方案,所以我只是在这里发布我的问题^^。
  • “它可以在我的机器上运行” 是破坏网络代码的经典借口,但这并不能减少它的破坏。如果您可以连接,但通信未按预期工作,则代码不起作用。我当然不是想惹你生气,但是这类教程每天都会产生多个这样的问题。请在您的问题中包含代码。
  • 好的,谢谢您的编辑。在客户端上键入“get time”后,您在两个控制台上看到了什么?服务器是否显示它接收到任何东西
  • 我用客户端和服务器的完整代码编辑了我的帖子。我以这段代码为例,但我尝试了很多我在网上找到的不同的东西(不仅在 youtube 上)。一切都在本地完美运行,但是当我将 IP 地址更改为路由器的公共 IP 地址时,它不再工作了,除了“连接”部分。

标签: c# sockets iis networking server


【解决方案1】:

我了解了消息框架,谢谢 CodeCaster。

对于对此感到好奇的人,这是我发现的一个有趣的链接:http://blog.stephencleary.com/2009/04/message-framing.html

但在尝试更改代码之前,我在 AWS vps 上运行了服务器,它立即运行,问题可能来自我的 isp 或路由器。我只是想知道它如何在不处理消息框架的情况下工作。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-08-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-27
    • 2016-10-29
    • 1970-01-01
    相关资源
    最近更新 更多