50分,线程毒死了
- C/C++ code
服务器三个线程,1. 第一个线程 分配时接受客户端的数据2. 第二个线程扫描一个map并主动推送用户在线列表的线程,3.第三个线程 检测下线的用户,一旦检测到,则通知服务器界面,让服务器界面去掉该用户,并告知其他用户。客户端检测了 ,没有问题, 我单独写了服务器,可以接收客户端的数据和客户端发送的心跳包。都收到了。但是开启客户端,对服务端调试,则发现很多地方进步了。很是奇怪。大家能帮忙看看 这个三个线程是否存在问题嘛?谢谢了//处理客户端的数据unsigned int CMyServerDlg::ReceiveUserPacke(void*){ while(1) { if(WaitForSingleObject(pThis->hKillReceiveEvent,0)==WAIT_OBJECT_0) return 0; { CMutexHelper mtHelp(&mu); if(pThis->m_pCurSock==NULL) { return 0; } } char rcvBuf[500]; memset(rcvBuf,sizeof(rcvBuf),0); if(SOCKET_ERROR!=pThis->m_pCurSock->Receive(rcvBuf,sizeof(rcvBuf))) { //解析 CPacket* pPack=(CPacket*)rcvBuf; if(pPack->type==CPacket::HeartBeat) // 心跳包 { CMutexHelper mtHelp(&mu); //这里,服务器不做回应,只是简单的更新最后发言时间 std::map<std::string,COnLineUser*>::iterator iter=pThis->on_line_userMap.find(std::string(pPack->receive_id)); if(iter!=pThis->on_line_userMap.end()) { //找到,更新时间 iter->second->theLastTalkTime=time(NULL); } } else if(pPack->type==CPacket::Verification) //验证 { //构建一个在线用户 COnLineUser* ponlineUser=new COnLineUser; //这里可以去服务器的数据库里查找,是否有该用户,如果有,则。。。。可以完善 memcpy(ponlineUser->UserId,pPack->send_id,sizeof(pPack->send_id)); ponlineUser->theLastTalkTime=time(NULL); //获取日历时间 CMutexHelper mtHelp(&mu); ponlineUser->psock=pThis->m_pCurSock; //这里是浅拷贝 pThis->on_line_userMap.insert(std::make_pair(ponlineUser->UserId,ponlineUser)); //添加到在线用户表中 static std::string strAddUser=ponlineUser->UserId; //要添加的用户 pThis->PostMessage(WM_USER_LOGIN_ON_OR_OFF,ADD_USER,LPARAM(strAddUser.c_str())); } else if(pPack->type==CPacket::Msg) //消息 { CMutexHelper mtHelp(&mu); std::map<std::string,COnLineUser*>::iterator iter=pThis->on_line_userMap.find(std::string(pPack->receive_id)); if(iter!=pThis->on_line_userMap.end()) { //找到,转发出去,并且更新最后发言时间 iter->second->psock->Send(rcvBuf,sizeof(rcvBuf)); iter->second->theLastTalkTime=time(NULL); } else //可以告诉用户,发送失败,可以完善该功能 { } } } } return 0;}//提示上线用户的线程,开启服务器后就可以创建该线程unsigned int CMyServerDlg::NoiftyUserLogon(void*){ while(1) { if(WaitForSingleObject(pThis->hNodifyLogonEvent,0)==WAIT_OBJECT_0) return 0; { CMutexHelper cmHelp(&mu); //对所有用户发送在线用户列表,构造logon数据包即可 std::map<std::string,COnLineUser*>::iterator iter; std::map<std::string,COnLineUser*>::iterator iter2; for(iter=pThis->on_line_userMap.begin();iter!=pThis->on_line_userMap.end();++iter) { //构造logon包 CPacket packet; packet.type=CPacket::SomeOneLogOn; strcpy(packet.send_id,iter->second->UserId); for(iter2=pThis->on_line_userMap.begin(); iter2!=pThis->on_line_userMap.end(); ++iter2) { if(iter!=iter2) { iter2->second->psock->Send(&packet,sizeof(CPacket)); } } } } Sleep(NOTIFY_ONLINE_USER_INTEVAL); } //end while return 0;}//提示下线用户线程,检测map,并发消息给界面,让界面删去已经下线的用户,客户断也要删去unsigned int CMyServerDlg::NofityUserLogoff(void*){ static std::string strDeletedUser; //要删除的用户 while(1) { if(WaitForSingleObject(pThis->hNodifyLogoffEvent,0)==WAIT_OBJECT_0) return 0; { CMutexHelper mtHelp(&mu); std::map<std::string,COnLineUser*>::iterator iter=pThis->on_line_userMap.begin(); while(iter!=pThis->on_line_userMap.end()) { time_t t=time(NULL); double time_interval=difftime(t,iter->second->theLastTalkTime); if(time_interval>TIMEOUT) //超时,移除该用户 { //构造下线包,发给所有用户 //构造logoff包 CPacket packet; packet.type=CPacket::SomeOneLogOn; strcpy(packet.send_id,iter->second->UserId); std::map<std::string,COnLineUser*>::iterator iter2=iter; for(iter2=pThis->on_line_userMap.begin(); iter2!=pThis->on_line_userMap.end(); ++iter2) { if(iter!=iter2) { iter2->second->psock->Send(&packet,sizeof(CPacket)); } } //服务器界面上删去下线的用户 strDeletedUser=iter2->second->UserId; pThis->PostMessage(WM_USER_LOGIN_ON_OR_OFF,DELETE_USER,(LPARAM)(strDeletedUser.c_str())); ++iter2; delete iter->second; pThis->on_line_userMap.erase(iter); //删除该用户 iter=iter2; continue; } else //更新该用户的最后发言时间 { iter->second->theLastTalkTime=t; ++iter; } } //end while } Sleep(CHECK_LOGOFF_USER); } return 0;}
[解决办法]
MFC的?
给你看几段我服务端的代码。
我用双向链表存在线列表。
- C/C++ code
void CClientSocket::OnReceive(int nErrorCode){ g_cs.Lock(); pWnd = static_cast<CCUPJOINServerDlg*>(AfxGetMainWnd()); Message msg; Receive(&msg, sizeof(msg)); //得到数据 if (msg.iType == VS_KEEPONLINE) return; //心跳包,不处理。 if (msg.iSubType == VS_LOGIN) { int RecvLogin = pWnd->UserCheck(msg.strName, msg.strPassword); if (RecvLogin == 1) // normal user msg.iType = VS_USER; else if (RecvLogin == 2) // admin user msg.iType = VS_ADMIN; else { LinkedUser.Delete(LinkedUser.Find(msg.strName)); msg.iType = VS_FAIL; msg.iSubType = VS_LOGIN; Send(&msg, sizeof(msg)); return; } //CString UserName = msg.strName; CString strtmp; UINT t; GetPeerName(strtmp, t); msg.SetContent(strtmp); if (CheckBaned(strtmp, msg)) { msg.iType = VS_FAIL; msg.iSubType = VS_BANED; Send(&msg, sizeof(msg)); return; } int IsExist = pWnd->CheckRepeatAndKick(msg); this->SetUserName(msg.strName); pWnd->m_pClientSocketList.AddTail(this); //CUP状态 if (pWnd->m_CupApply) msg.n_UserNum = 1; else if (pWnd->m_CupStart) msg.n_UserNum = 2; else msg.n_UserNum = 0; if (IsExist) pWnd->SendMsg(msg); //给全局发上线消息 else { pWnd->SendMsg(msg); //给全局发上线消息 LinkedUser.Append(0, msg.strName);//写在这里添加后,链表里存的UserName不会重复。 } MakeOnlineList();//发送在线列表 return; }...}