Как правильно закрыть сокет.
От: Ahven  
Дата: 05.05.04 13:17
Оценка:
Коллеги, ситуация такая.
Есть сервер на блокирующих сокетах, один клиент — один поток, т.е. с каждым клиентским потоком связан сокет, который дает ф-я accept.
Поскольку сокеты блокирующие, большую часть времени они сидят на recv.
Когда сервер заканчивает свою работу, он должен закрыть все эти сокеты.
Я пока делаю так — при завершении главного потока пробегаюсь по списку клиентских потоков, ставлю им признак завершения потока и вызываю closesocket для соотв. сокетов. При этом recv завершается с ошибкой WSAECONNRESET. При обработке ошибок я считаю, что если поставлен признак завершения потока и ошибка WSAECONNRESET, то это рассматривается как "сервер вырубают" и ошибкой это не считается.
Вопрос — допустимо ли так делать (т.е. закрывать сокет, принадлежащий одному потоку, из другого). Конечно, можно вызывать не closesocket, а shutdown(fSocket, SD_BOTH), но принцип остается тем же. Может быть, есть способ получше? Как вообще правильно делать по науке?
Re: Как правильно закрыть сокет.
От: merlinJap  
Дата: 05.05.04 15:04
Оценка:
Здравствуйте, Ahven, Вы писали:

A>Коллеги, ситуация такая.

A>Есть сервер на блокирующих сокетах, один клиент — один поток, т.е. с каждым клиентским потоком связан сокет, который дает ф-я accept.
A>Поскольку сокеты блокирующие, большую часть времени они сидят на recv.
A>Когда сервер заканчивает свою работу, он должен закрыть все эти сокеты.
A>Я пока делаю так — при завершении главного потока пробегаюсь по списку клиентских потоков, ставлю им признак завершения потока и вызываю closesocket для соотв. сокетов. При этом recv завершается с ошибкой WSAECONNRESET. При обработке ошибок я считаю, что если поставлен признак завершения потока и ошибка WSAECONNRESET, то это рассматривается как "сервер вырубают" и ошибкой это не считается.
A>Вопрос — допустимо ли так делать (т.е. закрывать сокет, принадлежащий одному потоку, из другого). Конечно, можно вызывать не closesocket, а shutdown(fSocket, SD_BOTH), но принцип остается тем же. Может быть, есть способ получше? Как вообще правильно делать по науке?

Вот кусок кода кодорый закрывает сокет...работает корректно...
У меня при попытке закрыть из другого потока на прямую оставался какой то нейзвестный поток
очевидно именно от TSocket не было времени разбирпться......

void CTcpSender::TcpCloseConnections()
{
if(m_WorkSocketStatus == sockNewNotCreated)
{
delete m_cWorkSocket;
m_WorkSocketStatus = sockNotNew;
}
else if(m_WorkSocketStatus == sockCreated)
{
if (m_cWorkSocket->IsBlocking())
{
m_cWorkSocket->CancelBlockingCall();
}
m_cWorkSocket->Close();
delete m_cWorkSocket;
m_WorkSocketStatus = sockNotNew;
}
}

С уважением merlin
С уважением merlinjap.
Re[2]: Как правильно закрыть сокет.
От: Ahven  
Дата: 05.05.04 15:36
Оценка:
Здравствуйте, merlinJap, Вы писали:

J>void CTcpSender::TcpCloseConnections()

J>{
J> if(m_WorkSocketStatus == sockNewNotCreated)
J> {
J> delete m_cWorkSocket;
J> m_WorkSocketStatus = sockNotNew;
J> }
J> else if(m_WorkSocketStatus == sockCreated)
J> {
J> if (m_cWorkSocket->IsBlocking())
J> {
J> m_cWorkSocket->CancelBlockingCall();
J> }
J> m_cWorkSocket->Close();
J> delete m_cWorkSocket;
J> m_WorkSocketStatus = sockNotNew;
J> }
J>}

Спасибо.
По данному коду есть несколько вопросов:

Во-первых, m_cWorkSocket — какого класса? Стандартный какой-то или Вы сами писали? И, собственно, где закрывается поток, в котором обрабатываются recv и send для данного сокета? Видимо, здесь: m_cWorkSocket->Close()? А как он закрывается?

Во-вторых, там внутри CancelBlockingCall(), часом, нет вызова WSACancelBlockingCall()? А то согласно MSDN последняя функция является устаревшей и нерекомендована к использованию.

Кстати, а как Вы закрывали напрямую из другого потока?
Re: Как правильно закрыть сокет.
От: butcher Россия http://bu7cher.blogspot.com
Дата: 05.05.04 15:37
Оценка:
Здравствуйте, Ahven.

Вы писали 5 мая 2004 г., 17:17:44:

A> Вопрос — допустимо ли так делать (т.е. закрывать сокет,

A> принадлежащий одному потоку, из другого). Конечно, можно вызывать
A> не closesocket, а shutdown(fSocket, SD_BOTH), но принцип остается
A> тем же.
Если вас устраивает такой способ.. Но, ИМХО, у вас кривоватая
архитектура приложения..

A> Может быть, есть способ получше? Как вообще правильно

A> делать по науке?
Неблокирующие сокеты использовать не пробовали?

--
С уважением, butcher
Posted via RSDN NNTP Server 1.8 beta

Нет ничего невозможного..
Re[3]: Как правильно закрыть сокет.
От: merlinJap  
Дата: 05.05.04 15:52
Оценка:
Здравствуйте, Ahven, Вы писали:

A>Здравствуйте, merlinJap, Вы писали:


J>>void CTcpSender::TcpCloseConnections()

J>>{
J>> if(m_WorkSocketStatus == sockNewNotCreated)
J>> {
J>> delete m_cWorkSocket;
J>> m_WorkSocketStatus = sockNotNew;
J>> }
J>> else if(m_WorkSocketStatus == sockCreated)
J>> {
J>> if (m_cWorkSocket->IsBlocking())
J>> {
J>> m_cWorkSocket->CancelBlockingCall();
J>> }
J>> m_cWorkSocket->Close();
J>> delete m_cWorkSocket;
J>> m_WorkSocketStatus = sockNotNew;
J>> }
J>>}

A>Спасибо.

A>По данному коду есть несколько вопросов:

A>Во-первых, m_cWorkSocket — какого класса? Стандартный какой-то или Вы сами писали? И, собственно, где закрывается поток, в котором обрабатываются recv и send для данного сокета? Видимо, здесь: m_cWorkSocket->Close()? А как он закрывается?


A>Во-вторых, там внутри CancelBlockingCall(), часом, нет вызова WSACancelBlockingCall()? А то согласно MSDN последняя функция является устаревшей и нерекомендована к использованию.


A>Кстати, а как Вы закрывали напрямую из другого потока?



m_cWorkSocket обычный CSocket. Поток создаеться при помощи CreateThread затем блокируеться...на recv при выполнении комманды CancelBlockingCall() снимаеться блокировка и возвращаеться код ошибки... по этому коду..и завершаеться поток обычным выходом...плюс можно еще использовать WaitForSingleObject.
С уважением merlinjap.
Re[3]: Как правильно закрыть сокет.
От: merlinJap  
Дата: 05.05.04 16:10
Оценка:
Здравствуйте, Ahven, Вы писали:

A>Здравствуйте, merlinJap, Вы писали:


J>>void CTcpSender::TcpCloseConnections()

J>>{
J>> if(m_WorkSocketStatus == sockNewNotCreated)
J>> {
J>> delete m_cWorkSocket;
J>> m_WorkSocketStatus = sockNotNew;
J>> }
J>> else if(m_WorkSocketStatus == sockCreated)
J>> {
J>> if (m_cWorkSocket->IsBlocking())
J>> {
J>> m_cWorkSocket->CancelBlockingCall();
J>> }
J>> m_cWorkSocket->Close();
J>> delete m_cWorkSocket;
J>> m_WorkSocketStatus = sockNotNew;
J>> }
J>>}

A>Спасибо.

A>По данному коду есть несколько вопросов:

A>Во-первых, m_cWorkSocket — какого класса? Стандартный какой-то или Вы сами писали? И, собственно, где закрывается поток, в котором обрабатываются recv и send для данного сокета? Видимо, здесь: m_cWorkSocket->Close()? А как он закрывается?


A>Во-вторых, там внутри CancelBlockingCall(), часом, нет вызова WSACancelBlockingCall()? А то согласно MSDN последняя функция является устаревшей и нерекомендована к использованию.


A>Кстати, а как Вы закрывали напрямую из другого потока?


Да забыл CancelBlockingCall() то же стандартная функция...
С уважением merlinjap.
Re[2]: Как правильно закрыть сокет.
От: Ahven  
Дата: 05.05.04 16:11
Оценка:
Здравствуйте, butcher, Вы писали:

B>Если вас устраивает такой способ.. Но, ИМХО, у вас кривоватая

B>архитектура приложения..

Почему же кривоватая... Я так понимаю, архитектура вполне очевидная, и, более того, часто используемая. В качестве примера могу привести стандартный класс Delphi TServerSocket. Там идея такая же, если использовать serverType = stThreadBlocking (кстати, и закрывают они эти сокеты тоже из другого потока с помощью closesocket).
Да и в литературе и сети такая модель неоднократно описывается. Например, http://www.citforum.ru/book/cook/winsock.shtml, см. там "Пример реализации TCP эхо-сервера". Да и в прочих статьях я подобное видал, например, здесь где-то на rsdn.ru есть статья про пул соединений (ссылку на память не скажу). Однако, ни в одной статье не нашел ответа именно на этот вопрос — как правильно закрывать клиентский сокет и поток.

А ведь вопрос даже не в моей архитектуре — если использовать блокирующие сокеты, надо иметь возможность как-то их закрывать при завершении работы программы. При этом ясно, что закрывать надо из другого потока — откуда же ещё, если сам поток висит на recv?

B>Неблокирующие сокеты использовать не пробовали?


Пока нет
Но, конечно, с ними я знаком. Однако должен же быть общепринятый способ решать мою задачу. Я думаю (по примеру исходников из Delphi), что общепринятый способ это closesocket или shutdown из другого потока. Вопрос в том, правильно ли я думаю?
Re: Как правильно закрыть сокет.
От: Аноним  
Дата: 05.05.04 16:40
Оценка:
Делаю точно также, проблем нет
Re[3]: Как правильно закрыть сокет.
От: butcher Россия http://bu7cher.blogspot.com
Дата: 05.05.04 16:41
Оценка:
Здравствуйте, Ahven.

Вы писали 5 мая 2004 г., 20:11:02:

A> Почему же кривоватая... Я так понимаю, архитектура вполне

A> очевидная, и, более того, часто используемая.
Я понимаю, что она очевидная, но такая архитектура, ИМХО, источник
ошибок в программе, хотя если делать всё грамотно, то я не возражаю

A> Однако, ни в одной статье не нашел ответа именно на этот

A> вопрос — как правильно закрывать клиентский сокет и поток.
Ну а какие ещё вы можете придумать способы?
На вскидку, например, использование модели select, через определённый
таймаут проверять готовность к чтению и необходимость к закрытию, но
способ тоже на мой взгляд не очень..

A> А ведь вопрос даже не в моей архитектуре — если использовать

A> блокирующие сокеты, надо иметь возможность как-то их закрывать при
A> завершении работы программы. При этом ясно, что закрывать надо из
A> другого потока — откуда же ещё, если сам поток висит на recv?
ИМХО, закрывать сокет должен тот поток, который его создал. Такой же
точки зрения я придерживаюь и в отношении других дескрипторов,
динамически выделенной памяти и прочего..

B>>Неблокирующие сокеты использовать не пробовали?

A> Пока нет
A> Но, конечно, с ними я знаком.
Попробуйте, возможно вам понравится
--
С уважением, butcher
Posted via RSDN NNTP Server 1.8 beta

Нет ничего невозможного..
Re[4]: Как правильно закрыть сокет.
От: Ahven  
Дата: 06.05.04 09:27
Оценка:
Здравствуйте, butcher, Вы писали:

A>> А ведь вопрос даже не в моей архитектуре — если использовать

A>> блокирующие сокеты, надо иметь возможность как-то их закрывать при
A>> завершении работы программы. При этом ясно, что закрывать надо из
A>> другого потока — откуда же ещё, если сам поток висит на recv?
B>ИМХО, закрывать сокет должен тот поток, который его создал. Такой же
B>точки зрения я придерживаюь и в отношении других дескрипторов,
B>динамически выделенной памяти и прочего..
Ну, это бесспорно. Возможно, я не совсем корректно выразился — я имел в виду, что подобным образом сокет закрываю только в случае "жесткой посадки", т.е. когда сервер вырубают невзирая на наличие открытых соединений. В нормальном случае, конечно, клиент сам закрывает соедиение, когда заканчивает диалог — либо сокет закрывает и сервер получает recv() == 0 либо клиент посылает сообщение определенного вида.

B>>>Неблокирующие сокеты использовать не пробовали?

A>> Пока нет
A>> Но, конечно, с ними я знаком.
B>Попробуйте, возможно вам понравится
Наверняка

Ну, в общем спасибо ещё раз. Будем стучать по клавишам
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.