У меня возникла проблема с SSLStream, возвращающей некоторые данные, когда удаленный клиент ничего не отправил. У меня возникает эта проблема, когда сервер прослушивает новую команду. Если сервер не получает новый запрос, функция ReadMessage() должна перехватывать IOException из-за таймаута чтения SSLStream. Проблема возникает, когда sslStream.Read() выполняется во второй раз, кажется, что он считывает 5 байтов, которые не были отправлены клиентом. Таким образом, проблема происходит в такой последовательности:SSLStream считывает неверные данные + KB3147458 Ошибка SSLStream (?)
-> ReadMessage() -> sslstream.Read() -> таймаут исключение пойманы, как ожидалось
-> ReadMessage() -> sslstream.Read() -> тайм-аут исключением не поймали, 5 байт читается даже несмотря на то, клиент ничего не послал
-> ReadMessage() -> sslstream.Read() -> таймаут исключение пойманы, как ожидалось
-> ReadMessage() -> sslstream.Read() -> исключение таймаута НЕ поймано, 5 байт прочитано, хотя клиент ничего не отправил ...
и так далее ..
public void ClientHandle(object obj)
{
nRetry = MAX_RETRIES;
// Open connection with the client
if (Open() == OPEN_SUCCESS)
{
String request = ReadMessage();
String response = null;
// while loop for the incoming commands from client
while (!String.IsNullOrEmpty(request))
{
Console.WriteLine("[{0}] {1}", RemoteIPAddress, request);
response = Execute(request);
// If QUIT was received, close the connection with the client
if (response.Equals(QUIT_RESPONSE))
{
// Closing connection
Console.WriteLine("[{0}] {1}", RemoteIPAddress, response);
// Send QUIT_RESPONSE then return and close this thread
SendMessage(response);
break;
}
// If another command was received, send the response to the client
if (!response.StartsWith("TIMEOUT"))
{
// Reset nRetry
nRetry = MAX_RETRIES;
if (!SendMessage(response))
{
// Couldn't send message
Close();
break;
}
}
// Wait for new input request from client
request = ReadMessage();
// If nothing was received, SslStream timeout occurred
if (String.IsNullOrEmpty(request))
{
request = "TIMEOUT";
nRetry--;
if (nRetry == 0)
{
// Close everything
Console.WriteLine("Client is unreachable. Closing client connection.");
Close();
break;
}
else
{
continue;
}
}
}
Console.WriteLine("Stopped");
}
}
public String ReadMessage()
{
if (tcpClient != null)
{
int bytes = -1;
byte[] buffer = new byte[MESSAGE_SIZE];
try
{
bytes = sslStream.Read(buffer, 0, MESSAGE_SIZE);
}
catch (ObjectDisposedException)
{
// Streams were disposed
return String.Empty;
}
catch (IOException)
{
return String.Empty;
}
catch (Exception)
{
// Some other exception occured
return String.Empty;
}
if (bytes != MESSAGE_SIZE)
{
return String.Empty;
}
// Return string read from the stream
return Encoding.Unicode.GetString(buffer, 0, MESSAGE_SIZE).Replace("\0", String.Empty);
}
return String.Empty;
}
public bool SendMessage(String message)
{
if (tcpClient != null)
{
byte[] data = CreateMessage(message);
try
{
// Write command message to the stream and send it
sslStream.Write(data, 0, MESSAGE_SIZE);
sslStream.Flush();
}
catch (ObjectDisposedException)
{
// Streamers were disposed
return false;
}
catch (IOException)
{
// Error while trying to access streams or connection timedout
return false;
}
catch (Exception)
{
return false;
}
// Data sent successfully
return true;
}
return false;
}
private byte[] CreateMessage(String message)
{
byte[] data = new byte[MESSAGE_SIZE];
byte[] messageBytes = Encoding.Unicode.GetBytes(message);
// Can't exceed MESSAGE_SIZE parameter (max message size in bytes)
if (messageBytes.Length >= MESSAGE_SIZE)
{
throw new ArgumentOutOfRangeException("message", String.Format("Message string can't be longer than {0} bytes", MESSAGE_SIZE));
}
for (int i = 0; i < messageBytes.Length; i++)
{
data[i] = messageBytes[i];
}
for (int i = messageBytes.Length; i < MESSAGE_SIZE; i++)
{
data[i] = messageBytes[messageBytes.Length - 1];
}
return data;
}
Сам же ReadMessage(), SendMessage() и CreateMessage() функции используются также клиентом для отправки сообщений на сервер. Константа MESSAGE_SIZE тоже такая же, и она установлена в 2048.
Хрустальный шар говорит, что вы изменили message_size и забыл обновить копию DLL, которая использует сервер. В вашем коде есть фундаментальная ошибка, посмотрите пример кода в статье MSDN для SslStream, обратите внимание на цикл do-while в методе ReadMessage(). Не хватает вашего. –
Константа MESSAGE_SIZE такая же, и она установлена в 2048. Я выяснил, что проблема в том, что я повторно использую sslStream, даже если я не должен это делать. В статье MSDN говорится, что SSLStream вернет gargabe после возникновения исключения тайм-аута. –
Да, ReadMessage() требует цикла do-while, чтобы проверить правильность чтения всех байтов. –