C# 通过 NetworkStream 发送和接收消息——代码简单,但无法按预期工作

标签 c# client networkstream tcplistener

我正在尝试编写一个小型 C# 应用程序,它将能够以客户端/服务器方式发送和接收加密消息。

这个 MSDN 示例非常接近我需要的东西(只是为了获得基本功能) http://msdn.microsoft.com/en-us/library/as0w18af.aspx http://msdn.microsoft.com/en-us/library/te15te69.aspx

因此客户端加密消息,将其发送到服务器,服务器解密并将明文写入控制台。

在这个方向上一切正常

但是,当我尝试从服务器向客户端发送消息(无论加密还是明文)时,它失败了。

服务器代码

using System;
using System.Net.Sockets;
using System.Threading;
using System.IO;
using System.Net;
using System.Security.Cryptography;

class Class1
{
   static void Main(string[] args)
   { 
      try
      {
         byte[] Key = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16};
         byte[] IV = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16};

         string ipAddress = "127.0.0.1";
         TcpListener TCPListen = new TcpListener(IPAddress.Parse(ipAddress),11000);

         TCPListen.Start();

         while(!TCPListen.Pending())
         {
            Console.WriteLine("Still listening. Will try in 5 seconds.");
            Thread.Sleep(5000);
         }

         TcpClient TCP = TCPListen.AcceptTcpClient();

         NetworkStream NetStream = TCP.GetStream();


         RijndaelManaged RMCrypto = new RijndaelManaged();



         CryptoStream CStream_READ = new CryptoStream(NetStream, RMCrypto.CreateDecryptor(Key, IV), CryptoStreamMode.Read);
         StreamReader SReader = new StreamReader(CStream_READ);
         Console.WriteLine("The decrypted original message: {0}", SReader.ReadToEnd());

// so far so good, but the next portion of the code does not run properly 

         CryptoStream CStream_WRITE = new CryptoStream(NetStream, RMCrypto.CreateEncryptor(Key,IV),CryptoStreamMode.Write);
         StreamWriter SWriter = new StreamWriter(CStream_WRITE);
         SWriter.WriteLine("message from server");
         SWriter.Flush();
         Console.WriteLine("The message was sent.");



         SReader.Close();
         SWriter.Close();
         NetStream.Close();
         TCP.Close();
      }
      //Catch any exceptions. 
      catch
      {
         Console.WriteLine("The Listener Failed.");
      }
   }
}

客户端代码

using System;
using System.IO;
using System.Security.Cryptography;
using System.Net.Sockets;

public class main
{
   public static void Main(string[] args)
   {
      try
      {

         TcpClient TCP = new TcpClient("localhost",11000);

         NetworkStream NetStream = TCP.GetStream();

         RijndaelManaged RMCrypto = new RijndaelManaged();

         byte[] Key = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16};
         byte[] IV = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16};

         CryptoStream CStreamWRITE = new CryptoStream(NetStream, RMCrypto.CreateEncryptor(Key, IV), CryptoStreamMode.Write);

         StreamWriter SWriter = new StreamWriter(CStreamWRITE);

         SWriter.WriteLine("Hello World!");
         SWriter.Flush();

         Console.WriteLine("The message was sent.");

  // so far so good, but the next portion of the code does not run properly 
         CryptoStream CStreamREAD = new CryptoStream(NetStream, RMCrypto.CreateDecryptor(Key,IV),CryptoStreamMode.Read);
         StreamReader SReader = new StreamReader(CStreamREAD);
         Console.WriteLine("od servera som dostal: {0}", SReader.ReadToEnd());

         SWriter.Close();
         SWriter.Close();
         CStreamWRITE.Close();
         NetStream.Close();
         TCP.Close();
      }
      catch
      {
         Console.WriteLine("The connection failed.");
      }
   }
}

我所做的是,我只是镜像了我认为与执行该功能相关的代码 所以服务器应该首先接收来自客户端的消息,然后将消息发送给客户端

如果我注释掉客户端向服务器发送消息,则服务器成功将消息发送给客户端

您能帮我一下,告诉我为什么它不能同时在两个方向上工作,但单独工作却可以吗?

提前致谢

最佳答案

您正在接收方上调用ReadToEnd - 但是,发送方尚未表示它已完成发送 - 发送方仅在之后<强>关闭流等/strong> 永远不会到来的消息;基本上,你已经陷入了僵局。

解决此类问题的方法有很多,包括:

  • 在消息中使用长度前缀,以便接收者提前知道需要多少数据(并可以相应地限制自己)
  • 在消息中使用终止符(可能是 cr/lf),以便接收者知道它已到达消息的末尾;对于文本协议(protocol),ReadLine 可能会很有用
  • 关闭出站流

如果您只发送一条消息,最后一个很简单;只需使用:

socket.Shutdown(SocketShutdown.Send);

发送消息后,接收方将知道它不会在套接字上获取更多数据。另请注意,您必须在执行此操作之前清除加密流等内容,以确保数据实际上已全部发送(而不是缓冲和丢失)。

就我个人而言,我倾向于使用第一个选项(长度前缀),主要是因为我通常处理多消息二进制协议(protocol)。

关于C# 通过 NetworkStream 发送和接收消息——代码简单,但无法按预期工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9659893/

相关文章:

c# - 在模块化表单应用程序中使用 AppDomain.UnhandledException

c# - 使用带有 HierarchicalDatatemplate 的附加行为

windows - 在 Windows 上的 Emacs 中使用 Jabber 的问题

c# - Networkstream不规则速度

c# - 是否可以在 DirectShow .Net 中使用 http url 作为源过滤器的源位置?

c# - Visual Studio 2017 Asp.Net Core 项目不会在构建时复制依赖的 dll 文件

c# - 异步委托(delegate)的 BeginInvoke 回调在哪个线程中?

Android客户端将输入消息设置为textview

java - 从应用程序客户端访问EJB(项目配置)

c# - 何时为客户端-服务器应用程序使用不同的端口?