Я работаю над клиент-серверным приложением, в котором соединения от клиента к серверу остаются открытыми до тех пор, пока клиентское приложение не будет закрыто.
Если серверное приложение неожиданно завершает работу, пока клиент читаетданные, я хочу, чтобы клиент рассматривал это как исключение, но затем перехватил исключение и вызвал событие с исключением в качестве аргумента.
Я написал тест, который, как мне кажется, должен проверить, что эта системаработает, но объект, который я тестирую, похоже, не регистрирует, что сокет закрыт, если я не установлю точку останова и затем продолжу.
Важная часть теста выглядит следующим образом:
StreamingMonitor sm = new StreamingMonitor();
bool errored = false;
string msg = "";
sm.ErrorOccurred += (s, a) =>
{
errored = true;
msg = a.Exception.Message;
};
sm.Enabled = true;
client = listener.AcceptTcpClient();
client.GetStream().Write(BitConverter.GetBytes(10000), 0, 4);
client.Close();
while(!errored)
{}
Assert.AreEqual("A request to send or receive data was disallowed because the socket had already been shut down in that direction with a previous shutdown call", msg);
Объект TcpListener
listener
прослушивает адрес обратной связи.
StreamingMonitor
начинает прослушивать длину данных, которые необходимо извлечь, когда она включена.Предполагается, что длина данных всегда вписывается в 32-разрядное целое число со знаком.
При получении длины сообщения вызывается этот метод.
private void GotMessageLength(IAsyncResult asyncResult)
{
try
{
client.Client.EndReceive(asyncResult);
if(firstMessage)
{
firstMessage = false;
if (Connected != null)
{
Connected(this, new EventArgs());
}
}
int msgLen = BitConverter.ToInt32(messageLength, 0);
byte[] message = new byte[msgLen];
List<byte> lbMessage = new List<byte>();
int bytesReturned = client.Client.Receive(message);
int remaining = (msgLen < bytesReturned) ? bytesReturned - msgLen : msgLen - bytesReturned;
if(remaining > 0)
{
if (bytesReturned > 0)
{
for (int i = 0; i < bytesReturned; i++)
{
lbMessage.Add(message[i]);
}
}
while(remaining > 0)
{
if(!client.Connected)
{
throw new SocketException((int)SocketError.Shutdown);
}
bytesReturned = client.Client.Receive(message);
remaining = (remaining < bytesReturned) ? bytesReturned - remaining : remaining - bytesReturned;
if (bytesReturned > 0)
{
for (int i = 0; i < bytesReturned; i++)
{
lbMessage.Add(message[i]);
}
}
}
message = lbMessage.ToArray();
}
MessageReceived(this, new MessageReceivedEventArgs(message));
if (Enabled)
{
client.Client.BeginReceive(messageLength, 0, 4, SocketFlags.None, GotMessageLength, null);
}
}
catch (SocketException ex)
{
if(ErrorOccurred != null)
{
ErrorOccurred(this, new ErrorEventArgs(ex));
}
}
catch (ObjectDisposedException)
{
}
}
Метод считывает данные из сети.поток, пока он не прочитал указанное число байтов.Если удаленное соединение закрывается, оно должно вызвать исключение сокета.
Однако модульный тест попадает в бесконечный цикл, ожидая возникновения ошибки, поскольку сокет в StreamingMonitor
никогда не осознает, чтодругой конец закрыт.
Как я могу заставить SteamingMonitor
понять, что сервер ушел?
Возможно ли это по адресу обратной связи?
Извините за всекод, я не мог думать, как сократить метод.