我正在尝试编写一个小型 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/