TcpClient снова не принимает данные
Есть класс, принимающий данные через TcpClient (TcpConnection). Полностью работает. Есть его наследник - RsaDecorator. Его метод Connect() (строка 240) должен передавать свой публичный ключ и получать чужой в ответ. Для этого есть методы SendKey() и ReceiveKey(). Они почему-то не работают (блок "Не работает") :). Точнее, происходит вход в бесконечный цикл ожидания ответа. Таска с получением ответа запущена с обоих сторон, проверял :). Для проверки в метод добавил обмен сообщениями - всё работает (блок "Работает"). Не ясно, в чём проблема.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Runtime.Serialization.Formatters.Binary;
using System.Security.Cryptography;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace TestProject
{
class Program
{
static void Main(string[] args)
{
Task.Run(() =>
{
Thread.CurrentThread.Name = "Server thread";
TcpListener listener = new TcpListener(IPAddress.Any, 13888);
listener.Start();
TcpConnection client = new RsaDecorator(new TcpConnection(listener.AcceptTcpClient()));
Console.WriteLine("Server: new connection!");
client.ReceivingState = ReceivingState.Method;
client.Connect();
while (client.GetReceivedCount() == 0) Thread.Sleep(100);
Console.WriteLine($"Server (available: {client.GetReceivedCount()}): " +
$"has been received message: {Encoding.UTF8.GetString(client.GetReceived().ToArray())}");
});
Task.Run(() =>
{
Thread.CurrentThread.Name = "Client thread";
TcpConnection connection = new RsaDecorator(new TcpConnection());
connection.SetEndPoint("127.0.0.1", 13888);
connection.ReceivingState = ReceivingState.Method;
connection.Connect();
if (connection.IsActive())
{
connection.Send(Encoding.UTF8.GetBytes("Text"));
}
});
Console.ReadLine();
}
}
public class TcpConnection
{
private readonly TcpClient client;
private BinaryReader reader;
private BinaryWriter writer;
private NetworkStream stream;
private string ip;
private int port;
private Task receiveTask;
private readonly List<byte> receivedBytes = new List<byte>();
public virtual ReceivingState ReceivingState
{
get
{
lock (receiveStateObject)
{
return receivingState;
}
}
set
{
lock (receiveStateObject)
{
receivingState = value;
}
}
}
private ReceivingState receivingState = ReceivingState.Both;
private object receiveStateObject = new object();
public virtual event ReceiveData OnReceiveData;
public TcpConnection(TcpClient client)
{
this.client = client;
if (IsActive())
{
reader = new BinaryReader(client.GetStream());
writer = new BinaryWriter(client.GetStream());
receiveTask = Task.Run(() => BeginReceive());
}
}
public TcpConnection()
: this(new TcpClient())
{ }
public virtual bool IsActive()
{
try
{
client.GetStream().Write(new byte[0]);
return true;
}
catch
{
return false;
}
}
public virtual void SetEndPoint(string ip, int port)
{
this.ip = ip;
this.port = port;
}
public virtual void Connect()
{
if (ip != null && port != 0)
{
client.Connect(ip, port);
reader = new BinaryReader(client.GetStream());
writer = new BinaryWriter(client.GetStream());
stream = client.GetStream();
receiveTask = Task.Run(() => BeginReceive());
}
}
public virtual void Disconnect()
{
client.Close();
reader.Close();
writer.Close();
stream.Close();
}
public virtual void Send(byte[] message)
{
if (IsActive())
{
writer.Write(message);
writer.Flush();
}
}
private void BeginReceive()
{
Thread.CurrentThread.Name = "Receive thread";
while (true)
{
if (IsActive() && client.Available != 0)
{
byte[] temp = reader.ReadBytes(client.Available);
lock (receiveStateObject)
{
if (ReceivingState == ReceivingState.Method || ReceivingState == ReceivingState.Both)
lock (receivedBytes)
{
receivedBytes.AddRange(temp);
}
if (ReceivingState == ReceivingState.Event || ReceivingState == ReceivingState.Both)
lock (receivedBytes)
{
OnReceiveData?.Invoke(temp.ToArray());
}
}
}
else
{
Thread.Sleep(100);
}
}
}
public virtual IEnumerable<byte> GetReceived()
{
lock (receivedBytes)
{
foreach (var item in receivedBytes)
yield return item;
receivedBytes.Clear();
}
}
public virtual int GetReceivedCount()
{
lock (receivedBytes)
{
return receivedBytes.Count;
}
}
}
public class RsaDecorator:TcpConnection
{
private TcpConnection innerConnection;
private RSAParameters publicKey;
private RSAParameters privateKey;
private readonly KeyGen keyGen = new KeyGen();
public override ReceivingState ReceivingState
{
get => innerConnection.ReceivingState;
set => innerConnection.ReceivingState = value;
}
public override event ReceiveData OnReceiveData;
private bool connectionCompleted = false;
public RsaDecorator(TcpConnection connection)
{
innerConnection = connection;
innerConnection.OnReceiveData += (byte[] message) =>
{
OnReceiveData?.Invoke(Decrypt(message));
};
}
private void SendKey(RSAParameters key)
{
RsaSerializable serializableKey = new RsaSerializable(key);
BinaryFormatter formatter = new BinaryFormatter();
using Stream stream = new MemoryStream();
formatter.Serialize(stream, serializableKey);
Console.WriteLine($"Length of stream: {stream.Length}");
innerConnection.Send(stream.ToArray());
}
private RSAParameters ReceiveKey()
{
BinaryFormatter formatter = new BinaryFormatter();
using Stream stream = new MemoryStream();
while (innerConnection.GetReceivedCount() == 0) Thread.Sleep(100);
stream.Write(innerConnection.GetReceived().ToArray());
return ((RsaSerializable)formatter.Deserialize(stream)).GetAsRsaParameters();
}
public override void Connect()
{
if (!innerConnection.IsActive())
innerConnection.Connect();
privateKey = keyGen.GetRSAParameters();
// Не работает
SendKey(privateKey);
publicKey = ReceiveKey();
// Работает
//innerConnection.Send(Encoding.UTF8.GetBytes("Some text"));
//while (innerConnection.GetReceivedCount() == 0) Thread.Sleep(100);
//Console.WriteLine(Encoding.UTF8.GetString(innerConnection.GetReceived().ToArray()));
connectionCompleted = true;
}
public override void Disconnect()
{
connectionCompleted = false;
innerConnection.Disconnect();
}
public override bool IsActive()
{
return connectionCompleted && innerConnection.IsActive();
}
public override IEnumerable<byte> GetReceived()
{
return Decrypt(innerConnection.GetReceived().ToArray());
}
public override void Send(byte[] message)
{
innerConnection.Send(Encrypt(message));
}
public override void SetEndPoint(string ip, int port)
{
innerConnection.SetEndPoint(ip, port);
}
private byte[] Encrypt(byte[] message)
{
using var rsa = new RSACryptoServiceProvider();
rsa.ImportParameters(publicKey);
return rsa.Encrypt(message, false);
}
private byte[] Decrypt(byte[] message)
{
using var rsa = new RSACryptoServiceProvider();
rsa.ImportParameters(privateKey);
return rsa.Decrypt(message, false);
}
public override int GetReceivedCount()
{
return innerConnection.GetReceivedCount();
}
[Serializable]
public class RsaSerializable
{
public byte[] Exponent;
public byte[] Modulus;
public RsaSerializable(RSAParameters parameters)
{
Exponent = parameters.Exponent;
Modulus = parameters.Modulus;
}
public RSAParameters GetAsRsaParameters()
{
return new RSAParameters() { Exponent = Exponent, Modulus = Modulus };
}
}
private class KeyGen
{
internal int KeysCount { get; set; } = 2;
private Queue<RSAParameters> Keys;
/// <summary>
/// Метод, возвращающий ключ
/// </summary>
internal RSAParameters GetRSAParameters()
{
// Заполнение очереди с ключами до указанного количества +1
for (int i = 0; i <= KeysCount - Keys.Count; i++)
GenerateKeyToQueue();
// Ожидание появления ключей в очереди
while (Keys.Count == 0) Thread.Sleep(100);
// Извлечение результата
lock (Keys)
{
return Keys.Dequeue();
}
}
internal KeyGen()
{
Keys = new Queue<RSAParameters>();
GenerateKeyToQueue();
}
/// <summary>
/// Метод, генерирующий ключ и добавляющий его в очередь
/// </summary>
private void GenerateKeyToQueue()
{
// Запуск асинхронной генерации
Task.Run(() =>
{
// Генерация
using var rsa = new RSACryptoServiceProvider();
RSAParameters result = rsa.ExportParameters(true);
// Добавление в очередь
lock (Keys)
{
Keys.Enqueue(result);
}
});
}
}
}
public enum ReceivingState : byte
{
Method,
Event,
Both
}
public delegate void ReceiveData(byte[] message);
}