【问题标题】:Receiving messages and sending messages over NetworkStream to a Client接收消息并通过 NetworkStream 向客户端发送消息
【发布时间】:2020-07-10 07:22:51
【问题描述】:

我有一个关于通过 C# 中的网络流从 TCPListener 服务器向客户端发送和接收消息的问题。现在,我的 TCPListener 实例可以从客户端接收一条消息并将其写入服务器控制台,它可以接受一个输入字符串并将其发送回客户端。但我希望改进从客户端接收多个连续消息并将多个连续响应发送回客户端的功能。如果 NetworkStream 的 ReadAsync 和 WriteAsync 函数可以处理接收多个连续消息或发送多个连续消息并且是否有更好的方法来实现这一点,是否有人碰巧有任何指针?此外,由于 Console.ReadLine 函数将在服务器从未接收到来自 ReadLine 的任何用户输入(并且没有按下 Enter 键)的情况下阻塞,有没有办法测试是否有来自键盘的可选用户输入?这样,只有当服务器从用户接收到某种控制台输入时,我才能尝试执行发送消息命令,否则可以继续接收客户端消息。

   public static async Task getMessage(TcpListener server)
      {
            byte[] bytes = new byte[256];
            using (var theStream = await server.AcceptTcpClientAsync())
            {
                using (var tcpStream = theStream.GetStream())
                {

                    await tcpStream.ReadAsync(bytes, 0, bytes.Length);
                    var msg = Encoding.UTF8.GetString(bytes);
                    Console.WriteLine(msg);
                    var payload = Console.ReadLine();
                    var bytes2 = Encoding.UTF8.GetBytes(payload);
                    await tcpStream.WriteAsync(bytes2, 0, bytes2.Length);
                }

           }

      } 

【问题讨论】:

  • 我认为人们对您的帖子进行了评分,因为您试图将多个响应从服务器发送回客户端,这是有问题的。客户端是主机,服务器是从机。所以通常你会让客户端发送命令,服务器确认(可选),服务器进程命令,服务器发送响应。如果客户端发送多条消息,则您需要为每条消息发送一个 ID,以便服务器可以使用 ID 进行响应,以便客户端知道哪个响应与每个命令相关联。您正在使用网络的两层 1) 应用层 2) TCP 传输层。
  • 亲爱的@jdweng,TCP 不是面向请求/响应的协议。它是一个真正的双向异步通信协议,允许并发读/写。如果你说的是真的,玩 PUBG 之类的游戏会消耗比必要更多的网络资源,并且会引入延迟。想想你的 PUBG 客户端不断询问所有其他玩家的所有动作和动作。这不是为多人实时动作游戏编程通信的有效方式。你所说的对于像 HTTP 这样的无状态协议是正确的。
  • @Oguz Ozgul :我确切地知道 TCP 是如何运作的,并且已经使用了 40 年。您必须定义一个应用层协议。对于聊天应用程序,两种方式的异步协议是可以接受的。但是永远不应该在命令和控制应用程序中使用双向异步。服务器是奴隶。您可以通过 TCP 实现其他协议,例如令牌环。但这变得越来越复杂,所以这里需要。

标签: c# tcplistener networkstream


【解决方案1】:

看到一个服务器实现只用于一个客户端很有趣!

TCP 是一种双向通信协议,所以是的,您当然可以在需要时发送您想要的东西,同时接收任何东西。

我试图将 cmets 放在源代码中,让它自己解释。

但关键点是将TcpClientNetworkStream 实例声明为静态变量,以便主线程(从控制台读取并将有效负载发送到客户端的线程)可以访问它们

希望这会有所帮助。

public static async Task getMessage(TcpListener server)
{
    byte[] bytes = new byte[256];
    using (theStream = await server.AcceptTcpClientAsync())
    {
        using (tcpStream = theStream.GetStream())
        {
            // We are using an infinite loop which ends when zero bytes have been received.
            // Receiving zero bytes means the transmission is over (client disconnected)
            while (await tcpStream.ReadAsync(bytes, 0, bytes.Length) > 0)
            {
                var msg = Encoding.UTF8.GetString(bytes);
                Console.WriteLine(msg);
            }
            Console.WriteLine("Client has disconnected");
        }
    }
}

/// <summary>
/// Transmists the payload to the client
/// </summary>
/// <param name="payload">The payload to transmit to the client</param>
/// <returns></returns>
static async Task Transmit(string payload)
{
    var bytes2 = Encoding.UTF8.GetBytes(payload);
    await tcpStream.WriteAsync(bytes2, 0, bytes2.Length);
}

// We are declaring the TcpClient and NetworkStream as static variables
// to be able to access them from all the threads.
private static TcpClient theStream;
public static NetworkStream tcpStream;

static void Main(string[] args)
{
    TcpListener server = new TcpListener(IPAddress.Loopback, 9876);
    server.Start();

    // Start the task getMessage() to accept a client and receive
    Task.Run(() => getMessage(server));

    string payload;
    while ((payload = Console.ReadLine()) != "exit")
    {
        // Check if the client has connected.
        if (tcpStream != null)
        {
            // Check if they are still connected
            if (theStream.Client.Connected)
            {
                Task.Run(() => Transmit(payload));
            }
            else
            {
                Console.WriteLine("the client connection is lost");
                break;
            }
        }
        else
        {
            Console.WriteLine("The client has not connected yet.");
        }
    }

    Console.WriteLine("Stopping the server");
    server.Stop();
}

【讨论】:

    猜你喜欢
    • 2012-01-18
    • 2023-03-11
    • 2017-09-30
    • 2014-05-10
    • 2015-03-28
    • 1970-01-01
    • 2018-09-08
    • 2022-01-15
    • 1970-01-01
    相关资源
    最近更新 更多