[c#] Подскажите по работе с сокетами
try-catch на Send-Receive?
Так стоит уже try catch, и не ловит обрыв связи с сервером, а если оборвать связь вообще с сетью, то ловит.
Тогда кусок кода с передачей данных пости
{
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);
Вот тут нужен внешний таймер, если конечно в вашем .net в библиотеки такого уже не спрятано.
А какое потом исключение должно вылететь?
SocketOptionName.ReceiveTimeout называется.
Блокирующие сокеты - отстой
Это лучше всего по ходу выполнения нелегитимных действий смотреть
Не ловит ):
А поподробнее?
Исключение не ловится.
может нужно другое исключение.
Обрыв связи должен отлавливаться в любой момент, а не только при соединении с сервером.
может нужно другое исключение.
В смысле? У тебя что, исключение летит, но влом посмотреть какое именно?
Не летит исклюбчение в том-то и дело, а нужно что бы летело
Только в [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
как завещал
Теперь исключение вылетает, даже если есть соединение с сервером ):
Какое именно исключение вылетает?
> {
SocketException sockExcept = e.InnerException as SocketException;
Вот это.
Если увеличить время таймаута, то нормально - вылетает только при обрубании сервера, как и должно быть.
достаточно просто ничего не делать и подождать время таймаута.
Может нужно в отдельном потоке что-то отправлять на сервер и ждать по атймауту, или какой-нибудь другой вариант?
А
подождать время таймаутадействительно необходимо?
если программа две секунды ничего не делает, то вылетает исключение. Это не дело.
А во-вторых, в каком конкретно месте возникает исключение?
Вот эта штука ловит исключение, которое появляется при подключении РесивТафмАута.
>Во-первых, если программа целых две(!) секунды ждет, то это уже не дело.
Дело в том что не ждёт а не взаимодейстьтвует с сервером, а такое вполне возможно, то есть если я сервер не отрубаю, а просто ничего не делаю, то вылетает исключение, такого быть не должно.
LingerOption lingerOption = new LingerOption(true, 2);
rsocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Linger, lingerOption);
При чем тут Linger?
Короче, вешай на OnReceive обработчик, и все тут.
куда вешать?
Вот эту вещь вставляю в разные места кода, выскакивает исключение если 2 секунды замешкаться, так быть не должно.
Что за обработчик к ней ещё можно приделать?
Всё-таки непонятно, почему задержка блокирующим Receive и следующее за ним возникновение ошибки - неправильное поведение. Структура программы и протокол обмена ясны? Или это просто какой-то пример, взятый с потолка?
>Всё-таки непонятно, почему задержка блокирующим Receive и следующее за ним возникновение ошибки - неправильное поведение.
Потому что непонятно почему исключение вызвано при обрыве сервера или просто прога ничего не делает.
Цель - нужно отследить те моменты когда теряется связь с сервером и принять меры.
Может эта штука лучше?
Цель - нужно отследить те моменты когда теряется связь с сервером и принять меры.Ну так и цепляй эти действия к обработчику SocketException-а, в чем проблема?
Непонятно как это сделать
...
catch(IOException e)
{
SocketException sockExcept = e.InnerException as SocketException;
MessageBox.Show("Работы ведуться. :cool: "); // Вот сюда нужно вставлять обработчик.
}
...
Там уже есть обработчик.
Какой именно?
Объясню что происходит, я вставил ReceiveTimeout 2000, после объявления rsockеt, обработчик исключения есть, сделан так же как ты предлагал. После запуска проги она сразу же (через 2сек) вываливается в это исключение, видимо ничего не пришло от сервера.
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 были, конечно
Ну вот, а во фреймворкских сокетах таймеры уже вкрученные с завода идут. Пользуйся, казалось бы, сколько влезет...
Так увеличивал такая же хуйня
Вот только afaik не любят их, хз почему, наверное есть подводные камни.
>вкрученные с завода идут.
вот такое вот исключение выскакивает {"An unknown, invalid, or unsupported option or level was specified in a getsockopt or setsockopt call" }
Может есть что почитать на эту тему?
Это ж далеко не мелкомягкое изобретение, SO_RCVTIMEO и SO_SNDTIMEO не вчера появились...afaik, не любят их в Linux. Где еще не любят?
Вот только afaik не любят их, хз почему, наверное есть подводные камни.
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
Есть программа на дот.нете на с#, обращается к серверу через сокет.Вопрос такой как отловить обрыв связи с сервером?
если нужно код выложу