18,356
社区成员
发帖
与我相关
我的任务
分享
void CClientDlg::OnBnClickedBtnLogin()
{
// TODO: 在此添加控件通知处理程序代码
char cmd[MAX_BUF_SIZE];
if (!m_bConnectOK)
{
MessageBox(_T("请检查网络连接!"), _T("登陆"), MB_OK | MB_ICONERROR);
return;
}
m_bCanRecv = false;
UpdateData();
/*发送命令,已验证服务器可以收到*/
send(m_sockServer, "Login:", CMD_LENGTH + 1, 0);
memset(cmd, '\0', MAX_BUF_SIZE);
WideCharToMultiByte(CP_ACP, NULL, m_strUser.GetString(), m_strUser.GetLength(),
cmd, MAX_BUF_SIZE, NULL, NULL);
/*发送账号,已验证成功*/
send(m_sockServer, cmd, strlen(cmd) + 1, 0);
memset(cmd, '\0', MAX_BUF_SIZE);
WideCharToMultiByte(CP_ACP, NULL, m_strPassword.GetString(), m_strPassword.GetLength(),
cmd, MAX_BUF_SIZE, NULL, NULL);
/*发送密码,已验证成功*/
send(m_sockServer, cmd, strlen(cmd) + 1, 0);
/*下面这条语句执行完之后,MFC界面就一直卡住了,执行不了Sleep开始的语句*/
recv(m_sockServer, cmd, MAX_BUF_SIZE, 0);
Sleep(DELAY_TIME);
if (strcmp(cmd, "LoginOK") != 0)
MessageBox(_T("用户名密码不正确!"), _T("登录失败"), MB_OK | MB_ICONINFORMATION);
else
{
this->ShowWindow(SW_HIDE);
m_dlgOrder.DoModal();
this->ShowWindow(SW_SHOWNORMAL);
}
m_bCanRecv = true;
}
/*这个函数被调用的时候说明,"Login:"命令已经接收成功*/
LRESULT CServerDlg::OnLogin(WPARAM wParam, LPARAM lParam)
{
int i;
CString str;
char tmp[MAX_BUF_SIZE];
if (!m_bConnectOK)
{
MessageBox(_T("请检查网络连接!"), _T("登陆"), MB_OK | MB_ICONERROR);
m_bCanRecv = true;
return 0;
}
Sleep(DELAY_TIME);
/*接收用户名并验证,调试过成功*/
recv(m_SockClient, tmp, MAX_BUF_SIZE, 0);
str = tmp;
for (i = 0; i < QUEUE_LENGTH; i++)
if (customer[i].used && customer[i].user == str)
break;
Sleep(DELAY_TIME);
/*接受密码并验证,调试过成功*/
recv(m_SockClient, tmp, MAX_BUF_SIZE, 0);
str = tmp;
if (i < QUEUE_LENGTH && customer[i].password == str)
{
m_obj = i;
m_lstPlaceInf.SetItemText(0, 3, _T("上菜"));
/*发送验证结果,调试成功,发送没有问题,客户端接受有问题*/
send(m_SockClient, "LoginOK", strlen("LoginOK") + 1, 0);
}
else
send(m_SockClient, "LoginFailed", strlen("LoginFailed") + 1, 0);
m_bCanRecv = true;
return 0;
}
CClientDlg *pThis;
UINT CClientDlg::ThreadProc(LPVOID lpDump)
{
int ret;
CString str;
char szBuf[MAX_BUF_SIZE];
ASSERT(lpDump);
pThis = (CClientDlg*)lpDump;
while (!pThis->m_bExit)
{
if (pThis->m_bCanRecv)
{
memset(szBuf, '\0', MAX_BUF_SIZE);
ret = recv(pThis->m_sockServer, szBuf, MAX_BUF_SIZE, 0);
if (ret > 0)
{
str = szBuf;
pThis->Analysis(str);
}
else
{
::MessageBox(NULL, _T("服务器掉线,请重新打开程序!"), _T("错误"), MB_OK | MB_ICONERROR);
break;
}
}
}
return EXIT_SUCCESS;
}
虽然控制标记字 m_bCanRecv,起到了控制线程的作用,但是由于登陆是由点击按钮发送的,点击按钮发送的消息,被分析命令并处理拦截解决,并在处理前设置控制标记字不允许接收。此时就是服务器处理函数内部与客户端进行双向通讯了,由于 recv 是阻塞的,在设置控制标记字之前实际上是在等待要接受的信息,因此设置之后,还是要接受一条命令,才能做出响应。而此时,问题就在此,原本要指定发送给客户端登陆结果的"LoginOK""LoginFailed",被客户端的命令分析线程吞噬,所以导致客户端内部处理函数的recv一直处于等待接收登陆结果的状态,因此卡死。
不知道楼主可否回复一下如何编写一个“一对多”的服务器/客户端测试样例程序分享给我呢?可以发送到我的邮箱:SweetLoverFT@qq.com,那样的话我会再加分还给你。