我正在尝试编写一个小型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.");
}
}
}
我所做的是我只是镜像了我认为与执行该功能相关的代码 所以服务器应该首先从客户端接收消息,然后向客户端发送消息
如果我注释掉客户端将消息发送到服务器,则服务器会成功将消息发送到客户端
你可以帮我解决一下,告诉我为什么它不能同时在两个方向都起作用,但是另外它可以吗?提前致谢
答案 0 :(得分:2)
您正在接收方拨打ReadToEnd
- 但是,发件人尚未说它已完成发送 - 发件人仅关闭流 传入的信息永远不会到来;基本上,你已经陷入僵局。
有很多方法可以解决这类问题,包括:
ReadLine
可能会有用如果您只发送一条消息,则最后一步很简单;只需使用:
socket.Shutdown(SocketShutdown.Send);
发送消息后,接收方将知道它不会再获得套接字上的数据。另请注意,您必须清除之前加密流之类的内容,以确保数据实际上全部已发送(并且不会缓冲和丢失)。
就个人而言,我倾向于使用第一个选项(长度前缀),主要是因为我通常处理多消息二进制协议。
答案 1 :(得分:0)
据我所知Read()
上的NetworkStream
- 方法没有阻塞,因此在发送启动消息后立即尝试通过ReadToEnd()
读取将无法找到任何数据,因此没有收到消息(返回一个空字符串)。尝试使用.DataAvailable
- 属性在调用读取方法之前等待数据。有关示例,请参阅MSDN。
代码中的第二个问题是写入CryptoStream后缺少FlushFinalBlock()
,因为流保留了状态,否则在关闭之前不发送部分加密块(注意这是Flush()
和FlushFinalBlock()
之间存在严重差异。因此,在等待阅读答案之前,您应该在客户端上调用CStreamWRITE.FlushFinalBlock()
。