套接字编程c#/Client-Server通信

本文关键字:Client-Server 通信 编程 套接字 | 更新日期: 2023-09-27 18:24:48

我正试图在.NET中制作两个程序(在控制台应用程序中),它们通过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发布并设置它。在localhost上工作,但使用公共ip(如"xx.xxx.xxx:PORT/default/index")时会出现错误。然而,它在错误中显示了网站名称。此外,当使用计算机的本地IP时,它也不起作用(类似192.168.1.180)

谢谢你的帮助。

套接字编程c#/Client-Server通信

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

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

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