Автор
|
Тема: Чайниковский вопрос про CSocket и thread
|
alexv |
опубликован 02-10-2001 18:59 MSK
Заранее сорри за чайниковский вопрос. Вот назрела проблема. В проге открываю сокет на прослушку. При коннекте к нему создаю новый сокет, и акцепчу к текущему. Хотелось бы, чтобы вся дальнейшая работа с этим новым сокетом происходила в своем треде. Так вот вопрос. Как правильно сделать - в главном потоке создать сокет для работы с соединением, сделать accept, а потом передать этот сокет как параметр в ф-ию потока, или создать ф-цию потока, а в ней уже создавать новый сокет. И второй вопрос - а как заставить правильно ф-цию потока выполняться до завершения коннекта с сокетом. Извините за сумбур. Пишу в виндах совсем недавно. Заранее спасибо.
|
necer
|
опубликован 03-10-2001 10:29 MSK
Именно в главном потоке создается слушающий сокет, по accept создается поток, в потоке создается сокет, которому нередается SOCKET handle. Примерно так: void CListenSocket::OnAccept(int nErrorCode) { CSocket soc; Accept(soc); CConnectThread* pThread = (CConnectThread*)AfxBeginThread(RUNTIME_CLASS(CConnectThread), THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED); ASSERT(pThread); pThread->m_hSocket = soc.Detach(); pThread->ResumeThread(); CAsyncSocket::OnAccept(nErrorCode); } А чтобы поток закрывался после закрытия сокета, в обработчике OnClose сокета надо отправить WM_QUIT потоку. |
server_mouse
|
опубликован 03-10-2001 10:44 MSK
Надеюсь ты не юзаешь MFC-классы для работы с сокетами? Если хочешь многопоточности, то обходи MFC стороной.>Так вот вопрос. Как правильно сделать - в >главном потоке создать сокет для работы с >соединением, сделать accept, а потом >передать этот сокет как параметр в ф-ию >потока, или создать ф-цию потока, а в ней >уже создавать новый сокет. 1. IMHO не принципиально. Но по моему лучше передать уже готовый сокет. Ведь поток может стартовать не так уж и сразу. Твоя ф-ция обработки сокетовых сообщений к тому времени может завершиться и получить новое сообщение... 2. Всё просто. Устанавливаешь евент на событие от сокета и зацикливаешь поток пока не получишь FD_CLOSE. Почитай http://www.sources.ru/cpp/cpp_network_evets_winsock2.shtml Вот кусок исхода из моей проги: DWORD WINAPI CCafe::SockThread(LPVOID ts) { //........ Тут ещё всякий код //Устанавливаем событие на сообщения сокета HANDLE hEvent = WSACreateEvent(); if(::WSAEventSelect(MyClass->sock, hEvent, FD_CONNECT|FD_READ|FD_CLOSE)) { MessageBox(NULL,"SocketEventError","Socket error",MB_OK); return 2; } for(;;) //Вечный цикл :) { //Вдруг нужно закрыть все потоки потому // что главный поток завершается. Нужно // корректно завершить работу. if(WaitForSingleObject(CloseEvent,0 )==WAIT_OBJECT_0) { shutdown(MyClass->sock,2); closesocket(MyClass->sock); WSACloseEvent(hEvent); return 0; } //А теперь собственно ждём события от сокета if( WSA_WAIT_FAILED!=::WSAWaitForMultipleEvents(1, &hEvent, false,50,false)) { WSANETWORKEVENTS NetEv; if(0==WSAEnumNetworkEvents(MyClass->sock,hEvent,&NetEv)) { // Если что-то пришло if(NetEv.lNetworkEvents & FD_READ) { //Читаем из сокета recv(sock,(char*)buf,sizeof(buf),NULL); //....... Ну и т.д. } else if(NetEv.lNetworkEvents & FD_CLOSE) { //Если хост разорвал соединение WSACloseEvent(hEvent); //Освобождаем ресурсы return 0; //Завершаем поток } } //if(0==WSAEnumNetworkEvents } //if( WSA_WAIT_FAILED! } //for(;;) }//SockThread() Ну вот, примерно так.
|
alexv
|
опубликован 03-10-2001 11:31 MSK
Ну я читал про "многопоточность" MFC, а что, все так запущено? |
server_mouse
|
опубликован 03-10-2001 12:06 MSK
Незнаю насколько там всё запущено, но я несколько раз тыкался носом в exception казалось бы из неоткуда и больше не хочу. Может я просто не умею пользоваться MFC-многопоточностью.... |
necer
|
опубликован 03-10-2001 12:26 MSK
Ну, не знаю. Сколько многопоточных приложений MFC писал - все нормально работает. |
server_mouse
|
опубликован 03-10-2001 12:32 MSK
2necer : Может подкинешь пару ссылок где про это можно почитать? |
necer
|
опубликован 03-10-2001 12:47 MSK
Ну, я только MSDN'ом и пользуюсь. Хотя... помнится где-то валялись у меня какие-то семплы, насколько помню, с microsoft.com стянутые. Если найду, куда кинуть-то? Вообще, там все довольно просто (на то и MFC), единственно, неколько геморройно иногда организовывать синхронизацию потоков, но это и в API не лучше. :) |
alexv
|
опубликован 03-10-2001 12:53 MSK
2 necer Если найдешь, то и мне. На мыло... Спасибо. |
server_mouse
|
опубликован 03-10-2001 13:52 MSK
2necer: на server_mouse@chat.ru ;) |
alexv
|
опубликован 03-10-2001 15:28 MSK
Что не так? Делаю: class CServerThread : public CWinThread { public: CClientSocket soc //класс для работы с сокетом //// } В главном потоке определяю класс CMySocket CMySocket::OnAccept(int nErrorCode) { CSocket soc; Accept(soc); CSocketThread* pThread = (CSocketThread*) AfxBeginThread(RUNTIME_CLASS(CSocketThread), THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED); ASSERT(pThread); pThread->soc.Attach(soc.Detach()); pThread->ResumeThread(); CSocket::OnAccept(nErrorCode); } class CClientSocket : public CSocket { public: CServerThread *m_ServThread; //указатель на поток, в котором "живет" данный сокет устанавливается в CServerThread::InitInstance /////////// } CServerThread::InitInstance { soc.m_ServThread = this; ///// } Определяю обработчик: CClientSocket::OnClose(int nErrorCode) { CSocket::OnClose(nErrorCode); m_ServThread->PostThreadMessage(WM_QUIT,0,0); } И после отключения клиента от порта закрывается прога. Что я делаю не так?
|
necer
|
опубликован 04-10-2001 13:19 MSK
Ну, на первый взгляд все верно. Попробуй отследить, куда попадает сообщение WM_QUIT. Может, ты его в главный поток нечаянно отправляешь?P.S. Пример выслал alexv и server_mouse |
divl
|
опубликован 07-03-2001 12:12 MSK
ех если возможно то вышли и мне на мыло (((divlweb@mail.ru))) MFC-многопоточностью... |