Подключаюсь, сначала нормальное общение, как только немного простой (отсутствие активности) на клиенте, то получаю принудительный разрыв соединения. Но тоже не сразу, а после того как попытаюсь что-нибудь запросить у сервера. По логам вижу что запрос от клиента до сервера дошел и тот на него ответил, но на клиенте ничего нет. Проблема имеет характер только на реальном хостинге, а на домашней машине все в порядке.
При необходимости могу предоставить код, а так я использую этот.
Код клиента.
public async Task Send(Packet message)
{
var buffer = message?.ToBytes();
if (buffer?.Length > 0)
{
try
{
var bytes = BitConverter.GetBytes(buffer.Length).ToList();
bytes.AddRange(buffer);
await _stream.WriteAsync(bytes.ToArray(), 0, bytes.Count);
}
catch (ObjectDisposedException)
{
Console.WriteLine(@"Connection close");
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
}
private async Task<byte[]> ReceiveTask(int byteCount)
{
var buffer = new byte[byteCount];
var pos = 0;
while (pos < byteCount)
{
var count = await _stream.ReadAsync(buffer, pos, buffer.Length - pos);
if (count == 0)
throw new EndOfStreamException();
pos += count;
}
return buffer;
}
public async void Receive()
{
try
{
while (true)
{
var packetLenBytes = await ReceiveTask(4);
var packetlen = BitConverter.ToInt32(packetLenBytes, 0);
if (packetlen > MaxLenSize && packetlen < 0) break;
var data = await ReceiveTask(packetlen);
RaiseEventMessegaReceive(data);
}
}
catch (OutOfMemoryException exception)
{
Console.WriteLine(exception);
}
catch (Exception exception)
{
Console.WriteLine(exception);
}
finally
{
Dispose();
}
}
Код на сервере:
public ClientTcp(TcpClient client, ServerTcp serverTcp)
{
_client = client;
_serverTcp = serverTcp;
_serverTcp.ClientAdd(this);
_stream = client.GetStream();
_client.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true);
Address = ((IPEndPoint)_client.Client.RemoteEndPoint).Address;
Port = ((IPEndPoint)_client.Client.RemoteEndPoint).Port;
GUID = Guid.NewGuid().ToString();
Program.ClientLogger.Info($"Client from {Address}:{Port} connect.");
Task.Run(Receive);
}
public async Task Send(Packet message)
{
if (message == null)
throw new ArgumentNullException(nameof(message));
Program.CommandLogger.Info($"Sent: {message.Command} to {Address}:{Port}");
var buffer = message.ToBytes();
if (buffer.Length > 0)
{
try
{
await _stream.WriteAsync(buffer.ToArray(), 0, buffer.Length);
}
catch (Exception)
{
Dispose();
}
}
}
private async Task<byte[]> ReceiveTask(int byteCount)
{
var buffer = new byte[byteCount];
var pos = 0;
while (pos < byteCount)
{
var count = await _stream.ReadAsync(buffer, pos, buffer.Length - pos);
if (count == 0)
throw new EndOfStreamException();
pos += count;
}
return buffer;
}
private async Task Receive()
{
try
{
while (true)
{
var packetLenBytes = await ReceiveTask(4);
var packetlen = BitConverter.ToInt32(packetLenBytes, 0);
if (packetlen > MaxLenSize)
break;
var data = await ReceiveTask(packetlen);
RaiseEventMessegaReceive(data);
}
}
catch (Exception)
{
// ignore
}
finally
{
Dispose();
}
}
Подобные проблемы могут возникать из-за межсетевых экранов, отслеживающих состояние соединения. Обычно они используются для реализации PNAT (трансляции сетевых адресов). Этой трансляцией может заниматься ваш роутер или провайдер. Проверьте IP-адрес компьютера, где запущен клиент: если он из подсетей 10.0.0.0/8, 172.16.0.0/12 или 192.168.0.0/16 (так называемые диапазоны серых адресов) - значит, где-то NAT точно есть.
Но даже если вы используете белый IP - это еще не означает, что между клиентом и сервером нет межсетевого экрана.
Проблема таких промежуточных устройств - в том, что при простое соединения они "забывают" про него, после чего начинают блокировать входящие пакеты. Транслятор адресов это делает просто потому что не знает куда пакет направить, другие межсетевые экраны - в приступе паранойи :-)
Для того, чтобы избежать подобного поведения, следует ввести в протокол пустую команду ("пинг"), которую бы клиент периодически отправлял серверу для поддержки соединения в активном состоянии. Интервал передачи следует сделать настраиваемым, поскольку необходимая частота служебных пакетов зависит от настроек сетевого оборудования.
Альтернативный вариант - включить на сокете настройку KeepAlive. Но по умолчанию интервал отправки служебных пустых пакетов системой - 2 часа, а потому нельзя особо надеяться на него.
Возможно также, что все эти соображения тут ни при чем - а просто вас в коде есть ошибка. Используйте Wireshark чтобы точно убедиться что ответ от сервера до вас не доходит.
Современные инструменты для криптотрейдинга: как технологии помогают принимать решения
Апостиль в Лос-Анджелесе без лишних нервов и бумажной волокиты
Основные этапы разработки сайта для стоматологической клиники
Продвижение своими сайтами как стратегия роста и независимости