这个概念看起来很简单:创建两个独立的应用程序,从客户端向服务器发送加密文本,然后从服务器向客户端发送回复——我假设我可以简单地在两者之间建立一个 TcpClient 连接,获取一个 NetworkStream,并在该 NetworkStream 上使用两个 CryptoStream(一个用于读取,一个用于写入)。但是,在我下面的示例中(主要基于 MSDN 示例),文本可以被加密,发送到服务器,解密并显示得很好,但是当服务器尝试回复时,它会抛出“无法将数据写入交通连接……”。当 StreamWriter 关闭时,底层流可能正在关闭?顺便说一句,当通过 NetworkStream 本身发送未加密的文本时,这个概念非常有效,因为 NetworkStream 本身就是双向的。
编辑:似乎关闭 CryptoStream 会导致其他所有内容也被关闭。如果我在客户端发送消息后在服务器上手动调用 sendReply() ,服务器将成功回复(只要客户端上没有关闭 NetworkStream )。然后服务器将抛出“无法从传输连接读取数据:阻塞操作被对 WSACancelBlockingCall 的调用中断。” 在 SReader.Readline。多个 CryptoStreams 似乎可以工作,所以真正的问题可能是服务器不知道何时停止读取。我也不确定如何补救。在消息中添加“\r\n”并使用 ReadLine() 似乎没有帮助。
服务器:
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 };
Thread listener;
NetworkStream nwStream;
TcpClient client;
RijndaelManaged RMCrypto;
CryptoStream CryptStreamRead;
CryptoStream CryptStreamWrite;
StreamReader SReader;
StreamWriter SWriter;
private void Form1_Load(object sender, EventArgs e)
{
listener = new Thread(new ThreadStart(tcpListen));
listener.IsBackground = true;
listener.Start();
}
private void tcpListen()
{
int port = 7777;
string dataReceived;
TcpListener listener = new TcpListener(IPAddress.Any, port);
listener.Start();
while (true)
{
client = listener.AcceptTcpClient();
nwStream = client.GetStream();
RMCrypto = new RijndaelManaged();
CryptStreamRead = new CryptoStream(nwStream, RMCrypto.CreateDecryptor(Key, IV), CryptoStreamMode.Read);
SReader = new StreamReader(CryptStreamRead);
string received = SReader.ReadLine();
Invoke(new MethodInvoker(() => textBoxReceived.Text = received));
Invoke(new MethodInvoker(() => sendReply("REPLY: " + received)));
//SReader.Close();
//CryptStreamRead.Close();
//nwStream.Close();
//client.Close();
//listener.Stop();
}
}
private void sendReply(string input)
{
try
{
CryptStreamWrite = new CryptoStream(nwStream, RMCrypto.CreateEncryptor(Key, IV), CryptoStreamMode.Write);
SWriter = new StreamWriter(CryptStreamWrite);
SWriter.WriteLine(input);
SWriter.Flush();
SWriter.Close();
CryptStreamWrite.Close();
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
客户:
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 };
int port = 7777;
string serverIP = "127.0.0.1";
TcpClient client;
NetworkStream nwStream;
RijndaelManaged RMCrypto;
CryptoStream CryptStreamWrite;
CryptoStream CryptStreamRead;
StreamWriter SWriter;
StreamReader SReader;
private void sendToServer(string input)
{
try
{
string textToSend = textBoxToSend.Text;
client = new TcpClient(serverIP, port);
nwStream = client.GetStream();
RMCrypto = new RijndaelManaged();
//CryptoStream CryptStream = new CryptoStream(nwStream,RMCrypto.CreateEncryptor(Key, IV), CryptoStreamMode.Write);
CryptStreamWrite = new CryptoStream(nwStream, RMCrypto.CreateEncryptor(Key, IV)), CryptoStreamMode.Write);
SWriter = new StreamWriter(CryptStreamWrite);
SWriter.WriteLine(textBoxToSend.Text);
SWriter.Flush();
SWriter.Close();
CryptStreamWrite.Close();
//nwStream.Close();
//client.Close();
waitForResponse();
}
catch
{
textBoxReceived.Text = "Cannot Create Connection to Server";
}
}
private void waitForResponse()
{
try
{
CryptStreamRead = new CryptoStream(nwStream, RMCrypto.CreateDecryptor(CalculateMD5Hash(textBoxKey.Text), CalculateMD5Hash(textBoxKey.Text)), CryptoStreamMode.Read);
SReader = new StreamReader(CryptStreamRead);
textBoxReceived.Text = SReader.ReadLine();
SReader.Close();
CryptStreamRead.Close();
nwStream.Close();
client.Close();
}
catch
{
textBoxReceived.Text = "No Response From Server";
}
}