我有一个使用TCP/IP协议发送和接收数据的项目,同时,
我会在屏幕左下角显示一个警报对话框,以了解是否有任何数据正在发送
我想将它构建成一个函数并单独在线程上运行。但是发送数据后,我没有收到任何通知,也没有任何错误。
有没有人帮你解决这个问题。非常感谢。
这是我的代码:
UINT JobManager::JobInfoAlert(LPVOID pParam)
{
THREADSTRUCT* ts = (THREADSTRUCT*)pParam;
WSADATA wsData;
WORD ver = MAKEWORD(2, 2);
int wsOk = WSAStartup(ver, &wsData);
if (wsOk != 0)
{
AfxMessageBox(L"Can't Initialize winsock! Quitting");
return 1;
}
// Create a socket
SOCKET listening = socket(AF_INET, SOCK_STREAM, 0);
if (listening == INVALID_SOCKET)
{
AfxMessageBox(L"Can't create a socket! Quitting");
return 1;
}
// Bind the ip address and port to a socket
sockaddr_in hint;
hint.sin_family = AF_INET;
hint.sin_port = htons(54000);
hint.sin_addr.S_un.S_addr = INADDR_ANY; // Could also use inet_pton ....
bind(listening, (sockaddr*)&hint, sizeof(hint));
// Tell Winsock the socket is for listening
listen(listening, SOMAXCONN);
// Wait for a connection
sockaddr_in client;
int clientSize = sizeof(client);
SOCKET clientSocket = accept(listening, (sockaddr*)&client, &clientSize);
char host[NI_MAXHOST]; // Client's remote name
char service[NI_MAXSERV]; // Service (i.e. port) the client is connect on
ZeroMemory(host, NI_MAXHOST); // same as memset(host, 0, NI_MAXHOST);
ZeroMemory(service, NI_MAXSERV);
if (getnameinfo((sockaddr*)&client, sizeof(client), host, NI_MAXHOST, service, NI_MAXSERV, 0) == 0)
{
//cout << host << " connected on port " << service << endl;
}
else
{
inet_ntop(AF_INET, &client.sin_addr, host, NI_MAXHOST);
//cout << host << " connected on port " <<
//ntohs(client.sin_port) << endl;
}
// Close listening socket
closesocket(listening);
// While loop: accept and echo message back to client
char buf[4096];
while (true)
{
ZeroMemory(buf, 4096);
// Wait for client to send data
int bytesReceived = recv(clientSocket, buf, 4096, 0);
if (bytesReceived == SOCKET_ERROR)
{
AfxMessageBox(L"Error in recv(). Quitting");
break;
}
if (bytesReceived == 0)
{
AfxMessageBox(L"Client disconnected");
break;
}
CMFCDesktopAlertWnd* pPopup = new CMFCDesktopAlertWnd;
int m_nAnimation = 2;
int m_nAnimationSpeed = 30;
int m_nTransparency = 180;
bool m_bSmallCaption = false;
bool m_bAutoClose = false;
int m_nAutoCloseTime = 3;
pPopup->SetAnimationType((CMFCPopupMenu::ANIMATION_TYPE) m_nAnimation);
pPopup->SetAnimationSpeed(m_nAnimationSpeed);
pPopup->SetTransparency((BYTE)m_nTransparency);
pPopup->SetSmallCaption(m_bSmallCaption);
pPopup->SetAutoCloseTime(m_bAutoClose ? m_nAutoCloseTime * 1000 : 0);
CPoint m_ptPopup = CPoint(-1, -1);
pPopup->Create(ts->_this, IDD_ALERT_JOB, NULL, m_ptPopup,
RUNTIME_CLASS(JobAlertDlg));
pPopup->SetWindowText(_T("Message"));
//cout << string(buf, 0, bytesReceived) << endl;
// Echo message back to client
send(clientSocket, "OK", bytesReceived + 1, 0);
}
// Close the socket
closesocket(clientSocket);
// Cleanup winsock
WSACleanup();
return 0;
}
BOOL JobManager::OnInitDialog()
{
THREADSTRUCT *_param = new THREADSTRUCT;
_param->_this = this;
CWinThread *ptrThread = AfxBeginThread(JobInfoAlert, _param)
CDialog::OnInitDialog();
return true;
}
您正在工作线程的上下文中创建警报对话框,这意味着该窗口将由该线程拥有,而其父(
JobManager
对话框)将(大概)由UI(主)线程拥有。这是要避免的设置。此外,工作线程是由 AfxBeginThread()
函数的重载版本创建的,它不会创建消息循环,这意味着它不会处理(警报)窗口的消息。
既然您决定创建一个单独的线程来处理套接字通信,那么最好将后台与 UI 操作分开 - 它们可以异步通信。一个非常简单的方法是在对话框类中定义自定义消息 (
WM_APP+nnnn
) 和 ON_MESSAGE()
处理程序。工作线程会将这些消息发布到对话窗口。您可以在 wParam
和 lParam
参数中传递信息,通常(但不一定) wParam
包含整数、枚举、代码等数据,而 lParam
较大的项目(通常是指针),尽管在 x64 下它们是都是 64 位。例如,通知代码可以放置在 wParam
中 - 您可以按照您希望的方式定义消息及其参数。
因此,您应该将创建警报对话框的代码移出线程函数,例如在上述消息处理程序中。这将在 UI 线程的上下文中创建警报对话框,因此它将由 UI 线程拥有。您的代码需要更多改进,例如,在失败、断开连接等情况下,工作线程显示消息框并终止,而
JobManager
对话框似乎没有收到任何通知。您应该将此类信息放入自定义消息中(由处理程序处理),以便对话框类可以采取相应的操作,例如启用/禁用控件或关闭。
轻微内存泄漏,工作线程在退出之前应该释放
THREADSTRUCT
中为OnInitDialog()
分配的内存,您只需分配它并将其传递给线程即可。或者您可以完全避免分配/释放它,您似乎只使用 _this
成员,因此您可以直接将其作为 LPVOID
参数传递。