[c#] Подскажите по работе с сокетами
try-catch на Send-Receive?
Так стоит уже try catch, и не ловит обрыв связи с сервером, а если оборвать связь вообще с сетью, то ловит.
Тогда кусок кода с передачей данных пости
rivate void EstablishSocket(Object state)
{
NetworkStream rstream = null;
NetworkStream wstream = null;
try
{
//RevisionNew.TransferTransport send = new RevisionNew.TransferTransport;
//String sendtext;
//String strid = "123";
Socket temp1 = new
Socket(AddressFamily.InterNetwork,
SocketType.Stream,ProtocolType.Tcp);
temp1.Blocking = true;
temp1.Connect(endPoint);
wsocket = temp1;
wstream = new NetworkStream(wsocket);
writer = new StreamWriter(wstream);
/*
TerminalInfo Info = new TerminalInfo;
//*
byte[] idtmp = Info.UniqueUnitID;
int id = 0;
for (int i = 0;i < idtmp.Length; i++)
{
id += (int)idtmp;
}
String strid = id.ToString;
*/
String strid = this.TerminalId;
//MessageBox.Show(strid);
RevisionNew.TransferTransport send = new RevisionNew.TransferTransport;
send.Command = "InitializeTerminalWriter";
send.Data = strid;
send.Type = "Command";
String sendtext = this.GetXML(send, send.GetType;
writer.Write(sendtext+(char)10);
//writer.Write("w!"+strid+"!"+(char)10);
writer.Flush;
// Try a client connection
// Для начала стартуем ридер
Socket temp = new
Socket(AddressFamily.InterNetwork,
SocketType.Stream,ProtocolType.Tcp);
temp.Blocking = true;
temp.Connect(endPoint);
rsocket = temp;
rstream = new NetworkStream(rsocket);
reader = new StreamReader(rstream);
// Encoding.UTF8
// потом добавим врайтер
TextWriter TempWrite =new StreamWriter(rstream);
send.Command = "InitializeTerminalReader";
sendtext = this.GetXML(send, send.GetType;
TempWrite.WriteLine(sendtext + (char)10);
TempWrite.Flush;
//String tmp1 = "test";
//writer.Write(tmp1);
//writer.Flush;
char[] handshake = new char[13];
//
String tmp = "";
try
{
tmp = reader.ReadLine;
//byte[] sss = BitConverter.GetBytes( tmp );
char[] a = tmp.ToCharArray;
if (!(tmp.Length > 0
{
rsocket.Close;
rsocket = null;
wsocket.Close;
wsocket = null;
}
}
catch
{
rsocket.Close;
rsocket = null;
wsocket.Close;
wsocket = null;
}
// If it all worked out, create stream objects
if(rsocket != null)
{
Notifications(Notification.Initialized, this);
//String tmp = System.Convert.ToString(handshake);
Notifications(Notification.ReceivedAppend, tmp);
// Start receiving talk
// Note: on w2k and later platforms, the NetworkStream.Read
// method called in ReceiveTalk will generate an exception when
// the remote connection closes. We handle this case in our
// catch block below.
ReceiveTalk;
// On Win9x platforms, NetworkStream.Read returns 0 when
// the remote connection closes, prompting a graceful return
// from ReceiveTalk above. We will generate a Notification.End
// message here to handle the case and shut down the remaining
// WinTalk instance.
Notifications(Notification.End, "Remote connection has closed.");
}
else
{
Notifications(Notification.Error,
"Failed to Establish Socket, did you specify the correct port?");
}
}
catch(IOException e)
{
SocketException sockExcept = e.InnerException as SocketException;
if(sockExcept != null && 10054 == sockExcept.ErrorCode)
{
Notifications(Notification.End, "Remote connection has closed.");
}
else
{
if (Notifications != null)
Notifications(Notification.Error, "Socket Error:\n"+e.Message);
}
}
catch(Exception e)
{
Notifications(Notification.Error, "Socket Error:\n"+e.Message);
}
}
{
NetworkStream rstream = null;
NetworkStream wstream = null;
try
{
//RevisionNew.TransferTransport send = new RevisionNew.TransferTransport;
//String sendtext;
//String strid = "123";
Socket temp1 = new
Socket(AddressFamily.InterNetwork,
SocketType.Stream,ProtocolType.Tcp);
temp1.Blocking = true;
temp1.Connect(endPoint);
wsocket = temp1;
wstream = new NetworkStream(wsocket);
writer = new StreamWriter(wstream);
/*
TerminalInfo Info = new TerminalInfo;
//*
byte[] idtmp = Info.UniqueUnitID;
int id = 0;
for (int i = 0;i < idtmp.Length; i++)
{
id += (int)idtmp;
}
String strid = id.ToString;
*/
String strid = this.TerminalId;
//MessageBox.Show(strid);
RevisionNew.TransferTransport send = new RevisionNew.TransferTransport;
send.Command = "InitializeTerminalWriter";
send.Data = strid;
send.Type = "Command";
String sendtext = this.GetXML(send, send.GetType;
writer.Write(sendtext+(char)10);
//writer.Write("w!"+strid+"!"+(char)10);
writer.Flush;
// Try a client connection
// Для начала стартуем ридер
Socket temp = new
Socket(AddressFamily.InterNetwork,
SocketType.Stream,ProtocolType.Tcp);
temp.Blocking = true;
temp.Connect(endPoint);
rsocket = temp;
rstream = new NetworkStream(rsocket);
reader = new StreamReader(rstream);
// Encoding.UTF8
// потом добавим врайтер
TextWriter TempWrite =new StreamWriter(rstream);
send.Command = "InitializeTerminalReader";
sendtext = this.GetXML(send, send.GetType;
TempWrite.WriteLine(sendtext + (char)10);
TempWrite.Flush;
//String tmp1 = "test";
//writer.Write(tmp1);
//writer.Flush;
char[] handshake = new char[13];
//
String tmp = "";
try
{
tmp = reader.ReadLine;
//byte[] sss = BitConverter.GetBytes( tmp );
char[] a = tmp.ToCharArray;
if (!(tmp.Length > 0
{
rsocket.Close;
rsocket = null;
wsocket.Close;
wsocket = null;
}
}
catch
{
rsocket.Close;
rsocket = null;
wsocket.Close;
wsocket = null;
}
// If it all worked out, create stream objects
if(rsocket != null)
{
Notifications(Notification.Initialized, this);
//String tmp = System.Convert.ToString(handshake);
Notifications(Notification.ReceivedAppend, tmp);
// Start receiving talk
// Note: on w2k and later platforms, the NetworkStream.Read
// method called in ReceiveTalk will generate an exception when
// the remote connection closes. We handle this case in our
// catch block below.
ReceiveTalk;
// On Win9x platforms, NetworkStream.Read returns 0 when
// the remote connection closes, prompting a graceful return
// from ReceiveTalk above. We will generate a Notification.End
// message here to handle the case and shut down the remaining
// WinTalk instance.
Notifications(Notification.End, "Remote connection has closed.");
}
else
{
Notifications(Notification.Error,
"Failed to Establish Socket, did you specify the correct port?");
}
}
catch(IOException e)
{
SocketException sockExcept = e.InnerException as SocketException;
if(sockExcept != null && 10054 == sockExcept.ErrorCode)
{
Notifications(Notification.End, "Remote connection has closed.");
}
else
{
if (Notifications != null)
Notifications(Notification.Error, "Socket Error:\n"+e.Message);
}
}
catch(Exception e)
{
Notifications(Notification.Error, "Socket Error:\n"+e.Message);
}
}
Разрыв происходит в ReceiveTalk? Оно нормально исключения обрабатвыает?
Нет, если оборвать связь с сервером, тоникакие исключения не выбрасываются, а если оборвать связь с сетью вообще, то выскакивает вот catch(IOException e) это исключение в EsteblishSocket
Если ты ждёшь ответа от сервера, а его нет, то ты долго ждать будешь.
Используй тайм-ауты.
Используй тайм-ауты.
А почему при обрыве сети исключение выскакивает сразу же?
Я понятия не имею, как ты "обрываешь связь" и в какой момент.
Потому что блокирующая операция на сокете получает уведомление от драйвера и немедленно завершается с исключением.
Обрываю локальное соединение с сетью.
В любой момент
В любой момент
Нужно ли делать отдельный поток который регулярно делает запросы на сервер и в случае его недоступности выбрасывает исключение?
Можешь приделать таймаут к сокету следующим образом:
//Send operations will timeout of confirmation is not received within 1000 milliseconds.
sSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, 1000);
щас попробую
Где лучше приделать?
Socket temp = new Socket(AddressFamily.InterNetwork, SocketType.Stream,ProtocolType.Tcp);
temp.Blocking = true;
//Можно, к примеру, сюда привинтить :)
temp.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, 1000); temp.Connect(endPoint);
rsocket = temp;
rstream = new NetworkStream(rsocket);
Обычно всё подвисает в receive, если сервер пропадает неожиданно.
Вот тут нужен внешний таймер, если конечно в вашем .net в библиотеки такого уже не спрятано.
Вот тут нужен внешний таймер, если конечно в вашем .net в библиотеки такого уже не спрятано.
А какое потом исключение должно вылететь?
Там и на Receive есть таймер.
SocketOptionName.ReceiveTimeout называется.
Блокирующие сокеты - отстой
SocketOptionName.ReceiveTimeout называется.
Блокирующие сокеты - отстой

Это лучше всего по ходу выполнения нелегитимных действий смотреть 

Не ловит ):
А поподробнее?
Вставил в разных вариантах в том числе и в том как ты рекомендовал.
Исключение не ловится.
может нужно другое исключение.
Обрыв связи должен отлавливаться в любой момент, а не только при соединении с сервером.
Исключение не ловится.
может нужно другое исключение.
Обрыв связи должен отлавливаться в любой момент, а не только при соединении с сервером.
может нужно другое исключение.
В смысле? У тебя что, исключение летит, но влом посмотреть какое именно?
Не летит исклюбчение в том-то и дело, а нужно что бы летело
Опять же - пиши сюда код, будем смотреть.
Только в [code] [/code] обрамляй, а то читать курсив неудобно
Только в [code] [/code] обрамляй, а то читать курсив неудобно

private void EstablishSocket(Object state)
{
NetworkStream rstream = null;
NetworkStream wstream = null;
try
{
//RevisionNew.TransferTransport send = new RevisionNew.TransferTransport;
//String sendtext;
//String strid = "123";
Socket temp1 = new
Socket(AddressFamily.InterNetwork,
SocketType.Stream,ProtocolType.Tcp);
temp1.Blocking = true;
temp1.Connect(endPoint);
wsocket = temp1;
wstream = new NetworkStream(wsocket);
writer = new StreamWriter(wstream);
/*
TerminalInfo Info = new TerminalInfo;
//*
byte[] idtmp = Info.UniqueUnitID;
int id = 0;
for (int i = 0;i < idtmp.Length; i++)
{
id += (int)idtmp[i];
}
String strid = id.ToString;
*/
String strid = this.TerminalId;
//MessageBox.Show(strid);
RevisionNew.TransferTransport send = new RevisionNew.TransferTransport;
send.Command = "InitializeTerminalWriter";
send.Data = strid;
send.Type = "Command";
String sendtext = this.GetXML(send, send.GetType;
writer.Write(sendtext+(char)10);
//writer.Write("w!"+strid+"!"+(char)10);
writer.Flush;
// Try a client connection
// Для начала стартуем ридер
Socket temp = new
Socket(AddressFamily.InterNetwork,
SocketType.Stream,ProtocolType.Tcp);
temp.Blocking = true;
temp.Connect(endPoint);
rsocket = temp;
rsocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, 1000);//debug
rstream = new NetworkStream(rsocket);
reader = new StreamReader(rstream);
// Encoding.UTF8
// потом добавим врайтер
TextWriter TempWrite =new StreamWriter(rstream);
send.Command = "InitializeTerminalReader";
sendtext = this.GetXML(send, send.GetType;
TempWrite.WriteLine(sendtext + (char)10);
TempWrite.Flush;
//String tmp1 = "test";
//writer.Write(tmp1);
//writer.Flush;
char[] handshake = new char[13];
//
String tmp = "";
try
{
tmp = reader.ReadLine;
//byte[] sss = BitConverter.GetBytes( tmp );
char[] a = tmp.ToCharArray;
if (!(tmp.Length > 0
{
rsocket.Close;
rsocket = null;
wsocket.Close;
wsocket = null;
}
}
catch
{
rsocket.Close;
rsocket = null;
wsocket.Close;
wsocket = null;
}
// If it all worked out, create stream objects
if(rsocket != null)
{
Notifications(Notification.Initialized, this);
//String tmp = System.Convert.ToString(handshake);
Notifications(Notification.ReceivedAppend, tmp);
// Start receiving talk
// Note: on w2k and later platforms, the NetworkStream.Read
// method called in ReceiveTalk will generate an exception when
// the remote connection closes. We handle this case in our
// catch block below.
ReceiveTalk;
// On Win9x platforms, NetworkStream.Read returns 0 when
// the remote connection closes, prompting a graceful return
// from ReceiveTalk above. We will generate a Notification.End
// message here to handle the case and shut down the remaining
// WinTalk instance.
Notifications(Notification.End, "Remote connection has closed.");
}
else
{
Notifications(Notification.Error,
"Failed to Establish Socket, did you specify the correct port?");
}
}
catch(IOException e)
{
SocketException sockExcept = e.InnerException as SocketException;
if(sockExcept != null && 10054 == sockExcept.ErrorCode)
{
Notifications(Notification.End, "Remote connection has closed.");
}
else
{
if (Notifications != null)
Notifications(Notification.Error, "Socket Error:\n"+e.Message);
}
}
catch(Exception e)
{
Notifications(Notification.Error, "Socket Error:\n"+e.Message);
}
}
private void ReceiveTalk
{
char[] commandBuffer = new char[20];
char[] oneBuffer = new char[1];
int readMode = 1;
//int counter = 0;
StringBuilder text = new StringBuilder;
String tmp;
//, tmp1;
//tmp1 = "привет";
while(readMode != 0)
{
tmp = reader.ReadLine;
//tmp1 = PrintCPBytes(tmp, 1251);
if(tmp == "end")
{
readMode = 0;
continue;
}
Notifications(Notification.ReceivedRefresh, tmp);
}
}
О!
вместо
надо вставить
как завещал
вместо
rsocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, 1000);//debug
надо вставить
rsocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, 1000);//debug
как завещал

Теперь исключение вылетает, даже если есть соединение с сервером ):
Какое именно исключение вылетает?
>catch(IOException e)
> {
SocketException sockExcept = e.InnerException as SocketException;
Вот это.
Если увеличить время таймаута, то нормально - вылетает только при обрубании сервера, как и должно быть.
> {
SocketException sockExcept = e.InnerException as SocketException;
Вот это.
Если увеличить время таймаута, то нормально - вылетает только при обрубании сервера, как и должно быть.
Исключение вылетает при любом случае есть соединение или нет.
достаточно просто ничего не делать и подождать время таймаута.
Может нужно в отдельном потоке что-то отправлять на сервер и ждать по атймауту, или какой-нибудь другой вариант?
достаточно просто ничего не делать и подождать время таймаута.
Может нужно в отдельном потоке что-то отправлять на сервер и ждать по атймауту, или какой-нибудь другой вариант?
Маза, если не знаком с таким изобретением, как асинхронные сокеты, то про потоки советую забыть.
А
А
подождать время таймаутадействительно необходимо?
если программа две секунды ничего не делает, то вылетает исключение. Это не дело.
Во-первых, если программа целых две(!) секунды ждет, то это уже не дело.
А во-вторых, в каком конкретно месте возникает исключение?
А во-вторых, в каком конкретно месте возникает исключение?
>catch(IOException e)
Вот эта штука ловит исключение, которое появляется при подключении РесивТафмАута.
>Во-первых, если программа целых две(!) секунды ждет, то это уже не дело.
Дело в том что не ждёт а не взаимодейстьтвует с сервером, а такое вполне возможно, то есть если я сервер не отрубаю, а просто ничего не делаю, то вылетает исключение, такого быть не должно.
Вот эта штука ловит исключение, которое появляется при подключении РесивТафмАута.
>Во-первых, если программа целых две(!) секунды ждет, то это уже не дело.
Дело в том что не ждёт а не взаимодейстьтвует с сервером, а такое вполне возможно, то есть если я сервер не отрубаю, а просто ничего не делаю, то вылетает исключение, такого быть не должно.
А что думаешь по поводу вот этой вещи
LingerOption lingerOption = new LingerOption(true, 2);
rsocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Linger, lingerOption);
LingerOption lingerOption = new LingerOption(true, 2);
rsocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Linger, lingerOption);
При чем тут Linger?
Короче, вешай на OnReceive обработчик, и все тут.
>OnReceive
куда вешать?
куда вешать?
>rsocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, 2000);//debug
Вот эту вещь вставляю в разные места кода, выскакивает исключение если 2 секунды замешкаться, так быть не должно.
Что за обработчик к ней ещё можно приделать?
Вот эту вещь вставляю в разные места кода, выскакивает исключение если 2 секунды замешкаться, так быть не должно.
Что за обработчик к ней ещё можно приделать?
Опс, улетел в другую степь.
Всё-таки непонятно, почему задержка блокирующим Receive и следующее за ним возникновение ошибки - неправильное поведение. Структура программы и протокол обмена ясны? Или это просто какой-то пример, взятый с потолка?
Всё-таки непонятно, почему задержка блокирующим Receive и следующее за ним возникновение ошибки - неправильное поведение. Структура программы и протокол обмена ясны? Или это просто какой-то пример, взятый с потолка?
Нет это пример конкретный и сразу же тестируемый на ходу так сказать объяснений.
>Всё-таки непонятно, почему задержка блокирующим Receive и следующее за ним возникновение ошибки - неправильное поведение.
Потому что непонятно почему исключение вызвано при обрыве сервера или просто прога ничего не делает.
Цель - нужно отследить те моменты когда теряется связь с сервером и принять меры.
>Всё-таки непонятно, почему задержка блокирующим Receive и следующее за ним возникновение ошибки - неправильное поведение.
Потому что непонятно почему исключение вызвано при обрыве сервера или просто прога ничего не делает.
Цель - нужно отследить те моменты когда теряется связь с сервером и принять меры.
SocketOptionName.KeepAlive Field
Может эта штука лучше?
Может эта штука лучше?
Цель - нужно отследить те моменты когда теряется связь с сервером и принять меры.Ну так и цепляй эти действия к обработчику SocketException-а, в чем проблема?
>Ну так и цепляй эти действия к обработчику SocketException-а, в чем проблема?
Непонятно как это сделать
Непонятно как это сделать
...
catch(IOException e)
{
SocketException sockExcept = e.InnerException as SocketException;
MessageBox.Show("Работы ведуться. :cool: "); // Вот сюда нужно вставлять обработчик.
}
...
Там уже есть обработчик.
Какой именно?
Объясню что происходит, я вставил ReceiveTimeout 2000, после объявления rsockеt, обработчик исключения есть, сделан так же как ты предлагал. После запуска проги она сразу же (через 2сек) вываливается в это исключение, видимо ничего не пришло от сервера.
SocketException sockExcept = e.InnerException as SocketException;
if(sockExcept != null && 10054 == sockExcept.ErrorCode)
{
Notifications(Notification.End, "Remote connection has closed.");
}
else
{
if (Notifications != null)
Notifications(Notification.Error, "Socket Error:\n"+e.Message);
}
if(sockExcept != null && 10054 == sockExcept.ErrorCode)
{
Notifications(Notification.End, "Remote connection has closed.");
}
else
{
if (Notifications != null)
Notifications(Notification.Error, "Socket Error:\n"+e.Message);
}
После запуска проги она сразу же (через 2сек) вываливается в это исключениеПосле запуска или после вызова Receive?
Скорее после вызова Recieve
Ну так если сервер не выполняет свои обязанности, то клиент в этом не виноват. 

Что можно сделать в этом случае?
Кстати нашёл в инете что с ресивомтаймаут часто бывает подобная проблема
Кстати нашёл в инете что с ресивомтаймаут часто бывает подобная проблема
Что можно сделать в этом случае?Увеличивать время таймаута, разве непонятно?
Лично я проблемы никакой не вижу, код рабочий.
у всех виденных мной сетевых приложений, от которых требуется надёжность, были какие-то специальные таймеры
независимо от того, блокирующие сокеты использовались, или нет
но они не под .net были, конечно
независимо от того, блокирующие сокеты использовались, или нет
но они не под .net были, конечно
Ну вот, а во фреймворкских сокетах таймеры уже вкрученные с завода идут. Пользуйся, казалось бы, сколько влезет...
Так увеличивал такая же хуйня
Это ж далеко не мелкомягкое изобретение, SO_RCVTIMEO и SO_SNDTIMEO не вчера появились...
Вот только afaik не любят их, хз почему, наверное есть подводные камни.
Вот только afaik не любят их, хз почему, наверное есть подводные камни.
>вкрученные с завода идут.
вот такое вот исключение выскакивает {"An unknown, invalid, or unsupported option or level was specified in a getsockopt or setsockopt call" }
Может есть что почитать на эту тему?
Это ж далеко не мелкомягкое изобретение, SO_RCVTIMEO и SO_SNDTIMEO не вчера появились...afaik, не любят их в Linux. Где еще не любят?
Вот только afaik не любят их, хз почему, наверное есть подводные камни.
Пробывал ещё вот такой вот вариант
В результате в одном случае получаю timeOut == -1 и исключение {"An unknown, invalid, or unsupported option or level was specified in a getsockopt or setsockopt call" }
В другом случае timeOut == 0 и исключение не вылетает.
Int32 timeout = (Int32)rsocket.GetSocketOption(SocketOptionLevel.Socket,
SocketOptionName.ReceiveTimeout);
// try to set what we received (we don't want to change the default value)
rsocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, timeout);
В результате в одном случае получаю timeOut == -1 и исключение {"An unknown, invalid, or unsupported option or level was specified in a getsockopt or setsockopt call" }
В другом случае timeOut == 0 и исключение не вылетает.
Оставить комментарий
markmsk
Есть программа на дот.нете на с#, обращается к серверу через сокет.Вопрос такой как отловить обрыв связи с сервером?
если нужно код выложу