Я новичок в МФЦ CWinThread
а также CAsyncSocket
и пытаюсь выучить их сам с помощью диалогового приложения.
Вот что я хочу сделать: сделать модель сервера / мультиклиента: когда число клиентов подключается к серверу, сервер создает потоки в соответствии с количеством клиентов и передает сокет, подключенный к потоку. Я рецензировал эту статью, чтобы сделать прохождение: https://support.microsoft.com/en-us/kb/175668 .
Я успешно сделал поток на каждом соединении, но …
Мой вопрос: Могу ли я из главного окна (GUI) повторно получить доступ ко всем сокетам, которые были переданы потокам в Отправить(широковещательные) данные для всех клиентов?
Вот как я делаю прохождение:
На стороне сервера:
void CMyServerDlg::OnAccept(){
CConnectSoc temp_soc;
m_Listener.Accept(temp_soc);
CSocketThread *pThr = (CSocketThread*)AfxBeginThread(
RUNTIME_CLASS(CSocketThread),
THREAD_PRIORITY_NORMAL,
0,
CREATE_SUSPENDED);
pThr->threadHandleSocket = temp_soc.Detach();
pThr->ResumeThread();
}
Замечания: m_Listener
является объектом класса, который получен из CAsyncSocket
а также CSocketThread
происходит от CWinThread
,
Внутри заголовка темы я добавил 2 строки:
Public:
CConnectSoc threadSocket;
SOCKET threadHandleSocket;
Внутри класса потока .cpp:
BOOL CSocketThread::InitInstance(){
threadSocket.Attach(threadHandleSocket);
return TRUE;
}
Может кто-нибудь сказать мне, что делать дальше, чтобы отправить данные в эти сокеты?
После некоторого исследования я, наконец, думаю, что могу ответить на свой вопрос, спасибо за вашу помощь; но, пожалуйста, исправьте меня, если есть лучшее решение или мое не является хорошей практикой.
МОЕ РЕШЕНИЕ:
Ключевое слово здесь PostMessage()
а также PostThreadMessage()
, Мы должны установить связь между графическим интерфейсом и потоками. Однако проблема в том, что поток не может вызвать PostMessage()
которая является функцией-членом CWnd
отправить сообщение в графический интерфейс (я понятия не имею, почему нет). Поэтому мне нужен указатель в классе потока, чтобы указать на CWnd из GUI:
В заголовке класса потока:
public:
CWnd *wParrent;
Затем на этапе создания потока мне просто нужно добавить 1 строку:
void CMyServerDlg::OnAccept(){
CConnectSoc temp_soc;
m_Listener.Accept(temp_soc);
CSocketThread *pThr = (CSocketThread*)AfxBeginThread(
RUNTIME_CLASS(CSocketThread),
THREAD_PRIORITY_NORMAL,
0,
CREATE_SUSPENDED);
pThr->wParrent = this; //<== this line
pThr->threadHandleSocket = temp_soc.Detach();
pThr->ResumeThread();
}
Сделав это, я теперь могу опубликовать сообщение из цепочки, чтобы дать GUI идентификатор моей цепочки.
В теме .cpp:
BOOL CSocketThread::InitInstance(){
threadSocket.Attach(threadHandleSocket);
wParrent->PostMessage(THREAD_STARTED, 0, (LPARAM)m_nThreadID);
return TRUE;
}
Затем в GUI: мы обрабатываем сообщение THREAD_STARTED
с функцией хранения m_nThreadID
для будущего использования:
Где-то в заголовке Dlg:
CDWordArray m_threadIDs;
Dlg .cpp
LRESULT CMyServer3Dlg::OnThreadStart(WPARAM, LPARAM lParam){
DWORD ThreadID = (DWORD)lParam;
m_threadIDs.Add(ThreadID);
return 0;
}
При отправке данных всем клиентам используйте PostThreadMessage()
в цикле m_ThreadIDs
:
for (int i =0; i<m_threadIDs.GetCount(); ++i){
PostThreadMessage(m_threadIDs[i],SEND_DATA,(WPARAM)bufferSize,(LPARAM)socketBuffer);
}
Справиться SEND_DATA
сообщение в ветке с функцией отправки:
В теме .cpp:
void CSocketThread::SendDataFunc(WPARAM wParam, LPARAM lParam){
ASSERT(threadSocket != NULL);
if(threadSocket == NULL)
{
return;
}
else
{
char *socketBuffer = (char*)lParam;
int bufferSize = (int)wParam;
send(threadSocket, socketBuffer, bufferSize, 0);
}
Это то, что я сделал, и никаких проблем до сих пор ….
Других решений пока нет …