1//函数名称:IOThreadProc 2//函数功能:消息处理的线程 3//处理对象:核心函数 4//研究人员:长寿梦 5DWORD WINAPI CP2PServer::IOThreadProc(LPVOID lpParam) 6{ 7 CP2PServer *pThis=(CP2PServer *)lpParam; 8 char buff[MAX_PACKET_SIZE]; 9 CP2PMessage *pMsg=(CP2PMessage *)buff; 10 sockaddr_in remoteAddr; 11 // 12 WSABUF wsaBuf; 13 wsaBuf.buf=buff; 14 wsaBuf.len=MAX_PACKET_SIZE; 15 // 16 DWORD dwRecv; 17 DWORD dwFlags=0; 18 int nAddrLen=sizeof(remoteAddr); 19 20 _RecordsetPtr m_record; //记录集, 记录ADO查询的数据 21 _bstr_t vSQL; //SQL语句 22 CString strNo,strName,strPhone,strText,strLog,strTime; 23 CString strPassword,strIp,strPort,strOnline; 24 COleDateTime time; 25 26 while(TRUE) 27 { // 接收信息到wsaBuf 28 int nRet=::WSARecvFrom(pThis->g_s,&wsaBuf,1,&dwRecv,&dwFlags,(sockaddr *)&remoteAddr,&nAddrLen,&pThis->g_ol,NULL); 29 30 if(nRet==SOCKET_ERROR) 31 { 32 int nError=::WSAGetLastError(); 33 if(nError==WSA_IO_PENDING) 34 { 35 // TRACE0("没接到消息,正在等待。。。重叠接收信息\n"); 36 ::WSAGetOverlappedResult(pThis->g_s,&pThis->g_ol,&dwRecv,TRUE,&dwFlags); 37 } 38 //else if() 39 } 40 //查看是否要退出 41 if(pThis->g_bThreadExit) 42 break; 43 if(dwRecv<sizeof(CP2PMessage)) 44 continue; 45 //消息循环:总共处理15个消息 46 switch(pMsg->nMessageType) 47 { 48 //[1/15]用户登陆消息////////////////////////////////////////////////////////////// 49 case USERLOGIN: 50 { 51 strNo=pMsg->peer.ImNo; 52 strPassword=(char*)(pMsg+1); 53 //写到日志列表中 54 time=COleDateTime::GetCurrentTime(); 55 strTime=time.Format("%H:%M:%S "); 56 strLog=strTime+strNo+" 请求登陆"; 57 ::PostMessage(g_pPage3->m_hWnd,WM_NEWLOG,(WPARAM)(LPCTSTR)strLog,0); 58 59 vSQL="select * from imuser where ImNo='"+strNo+"' and Impassword='"+strPassword+"' and ImOnline=0"; 60 m_record=pThis->ado.GetRecordSet(vSQL); 61 //如果登录成功,则返回自己信息,记录登录地址,接收离线消息,接收离线好友请求,设置为在线状态,广播这状态变化 62 if(!m_record->adoEOF) 63 { 64 //写到日志列表中 65 time=COleDateTime::GetCurrentTime(); 66 strTime=time.Format("%H:%M:%S "); 67 strLog=strTime+strNo+" 登陆成功"; 68 ::PostMessage(g_pPage3->m_hWnd,WM_NEWLOG,(WPARAM)(LPCTSTR)strLog,0); 69 70 strName=(LPCTSTR)(_bstr_t)m_record->GetCollect("ImName"); 71 strPhone=(LPCTSTR)(_bstr_t)m_record->GetCollect("ImPhone"); 72 73 strName.TrimRight(" "); 74 strPhone.TrimRight(" "); 75 76 //登陆成功,并返回用户自己的信息 77 pMsg->nMessageType=USERLOGACK; 78 strcpy((char*)pMsg->peer.ImNo,(LPCSTR)(LPCTSTR)strNo); 79 strcpy((char*)pMsg->peer.ImName,(LPCSTR)(LPCTSTR)strName); 80 strcpy((char*)pMsg->peer.ImPhone,(LPCSTR)(LPCTSTR)strPhone); 81 ::sendto(pThis->g_s,(char *)pMsg,sizeof(CP2PMessage),0,(sockaddr*)&remoteAddr,sizeof(remoteAddr)); 82 //将IP,状态写入数据库 inet_addr,inet_ntoa, 83 strIp=::inet_ntoa(remoteAddr.sin_addr); //将IP转成字符串 84 strPort.Format("%d",ntohs(remoteAddr.sin_port)); //将端口转成字符串,先要转化成本地字节序 85 vSQL="update imuser set ImOnline='1',ImIp='"+strIp+"',ImPort='"+strPort+"' where ImNo='"+strNo+"'"; 86 pThis->ado.ExecuteSQL(vSQL); 87 //设置服务器该用户在线状态 88 strText=strName+"("+strNo+")"; 89 ::PostMessage(g_pPage1->m_hWnd,WM_USERSTATIC_UPDATE,(WPARAM)(LPCTSTR)strText,(LPARAM)(LPCTSTR)"Login"); 90 91 //发送离线的消息:对表[OfflineMessage]的操作 92 vSQL="select * from OfflineMessage where ImNo='"+strNo+"'"; 93 m_record=pThis->ado.GetRecordSet(vSQL); 94 ::Sleep(500); /**////////////////////// 95 char *pBuf = NULL; 96 char sendBuf[MAX_PACKET_SIZE]; 97 while(!m_record->adoEOF) 98 { 99 long lDataSize = m_record->GetFields()->GetItem("ImMsg")->ActualSize;/**////得到数据的长度 100 if(lDataSize > 0) 101 { 102 _variant_t varBLOB; 103 varBLOB = m_record->GetFields()->GetItem("ImMsg")->Value; 104 if(varBLOB.vt == (VT_ARRAY | VT_UI1)) /**////判断数据类型是否正确 105 { 106 SafeArrayAccessData(varBLOB.parray,(void **)&pBuf);/**////得到指向数据的指针 107 /**//*****在这里我们可以对pBuf中的数据进行处理*****/ 108 memset(sendBuf,0,MAX_PACKET_SIZE); 109 memcpy(sendBuf,pBuf,lDataSize); 110 SafeArrayUnaccessData (varBLOB.parray); 111 CP2PMessage *pM=(CP2PMessage *)sendBuf; 112 pM->nMessageType=P2PMESSAGE; 113 CString sss=(char *)(pM+1)+sizeof(MessageInfo); 114 //AfxMessageBox(sss); 115 ::sendto(pThis->g_s,(char *)sendBuf,lDataSize,0,(sockaddr*)&remoteAddr,sizeof(remoteAddr)); 116 117 } 118 } 119 m_record->MoveNext(); 120 } 121 //删除该用户的离线好友请求 122 vSQL="delete from OfflineMessage where ImNo='"+strNo+"'"; 123 pThis->ado.ExecuteSQL(vSQL); 124 125 //发送离线好友请求的消息:对表[OffAddfriend]的操作 126 vSQL="select * from OffAddfriend where ImNo='"+strNo+"'"; 127 m_record=pThis->ado.GetRecordSet(vSQL); 128 ::Sleep(500); /**////////////////////// 129 //char *pBuf = NULL; 130 //char sendBuf[sizeof(CP2PMessage)+sizeof(NewFriendMessage)]; 131 while(!m_record->adoEOF) 132 { 133 long lDataSize = m_record->GetFields()->GetItem("ImInfo")->ActualSize;/**////得到数据的长度 134 if(lDataSize > 0) 135 { 136 _variant_t varBLOB; 137 varBLOB = m_record->GetFields()->GetItem("ImInfo")->Value; 138 if(varBLOB.vt == (VT_ARRAY | VT_UI1)) /**////判断数据类型是否正确 139 { 140 SafeArrayAccessData(varBLOB.parray,(void **)&pBuf); /**////得到指向数据的指针 141 /**//*****在这里我们可以对pBuf中的数据进行处理*****/ 142 memset(sendBuf,0,MAX_PACKET_SIZE); 143 memcpy(sendBuf,pBuf,lDataSize); 144 SafeArrayUnaccessData (varBLOB.parray); 145 ::sendto(pThis->g_s,(char *)sendBuf,lDataSize,0,(sockaddr*)&remoteAddr,sizeof(remoteAddr)); 146 147 } 148 } 149 m_record->MoveNext(); 150 } 151 //删除该用户的离线好友请求 152 vSQL="delete from OffAddfriend where ImNo='"+strNo+"'"; 153 pThis->ado.ExecuteSQL(vSQL); 154 155 //给所有用户发送消息,该用户状态发生了变化 156 vSQL="select ImIp,ImPort,ImOnline from imuser where ImNo!='"+strNo+"'and ImOnline=1"; //只要IP地址和端口号 157 m_record=pThis->ado.GetRecordSet(vSQL); 158 while(!m_record->adoEOF) 159 { 160 //保存状态改变的用户信息(登陆的用户) 161 CP2PMessage peerMsg={0}; 162 peerMsg.nMessageType=CHANGESTATE; //改变状态消息 163 strcpy((char*)peerMsg.peer.ImNo,(LPCSTR)(LPCTSTR)strNo); 164 strcpy((char*)peerMsg.peer.ImName,(LPCSTR)(LPCTSTR)strName); 165 peerMsg.peer.ImOnline=1; 166 167 //要发送对象的地址 168 strIp=(LPCTSTR)(_bstr_t)m_record->GetCollect("ImIp"); 169 strPort=(LPCTSTR)(_bstr_t)m_record->GetCollect("ImPort"); 170 strOnline=(LPCTSTR)(_bstr_t)m_record->GetCollect("ImOnline"); 171 strIp.TrimRight(" "); 172 strPort.TrimRight(" "); 173 strOnline.TrimRight(" "); 174 175 remoteAddr.sin_addr.S_un.S_addr=inet_addr(strIp); 176 remoteAddr.sin_port=htons(atoi(strPort)); 177 if(strOnline=="1" && strPort!="0") 178 ::sendto(pThis->g_s,(char *)&peerMsg,sizeof(peerMsg),0,(sockaddr *)&remoteAddr,sizeof(remoteAddr)); 179 m_record->MoveNext(); 180 } 181 182 } 183 //如果登录失败 184 else 185 { 186 //写到日志列表中 187 time=COleDateTime::GetCurrentTime(); 188 strTime=time.Format("%H:%M:%S "); 189 strLog=strTime+strNo+" 登陆失败"; 190 ::PostMessage(g_pPage3->m_hWnd,WM_NEWLOG,(WPARAM)(LPCTSTR)strLog,0); 191 } 192 } 193 break; 194 195 //[2/15]注销/////////////////////////////////////////////////////////////////////////////// 196 case USERLOGOUT: 197 { 198 strNo=pMsg->peer.ImNo; 199 strName=pMsg->peer.ImName; 200 //写到日志列表中 201 time=COleDateTime::GetCurrentTime(); 202 strTime=time.Format("%H:%M:%S "); 203 strLog=strTime+strNo+" 退出"; 204 ::PostMessage(g_pPage3->m_hWnd,WM_NEWLOG,(WPARAM)(LPCTSTR)strLog,0); 205 206 vSQL="update imuser set ImOnline='0',ImPort='0' where ImNo='"+strNo+"'"; 207 pThis->ado.ExecuteSQL(vSQL); 208 //离线状态 209 strText=strName+"("+strNo+")"; 210 ::PostMessage(g_pPage1->m_hWnd,WM_USERSTATIC_UPDATE,(WPARAM)(LPCTSTR)strText,(LPARAM)(LPCTSTR)"Logout"); 211 212 //给所有用户发送消息,该用户状态发生了变化 213 vSQL="select ImIp,ImPort,ImOnline from imuser where ImNo!='"+strNo+"'and ImOnline=1"; //只要IP地址和端口号 214 m_record=pThis->ado.GetRecordSet(vSQL); 215 while(!m_record->adoEOF) 216 { 217 //保存状态改变的用户信息(登陆的用户) 218 CP2PMessage peerMsg={0}; 219 peerMsg.nMessageType=CHANGESTATE; //改变状态消息 220 strcpy((char*)peerMsg.peer.ImNo,(LPCSTR)(LPCTSTR)strNo); 221 strcpy((char*)peerMsg.peer.ImName,(LPCSTR)(LPCTSTR)strName); 222 peerMsg.peer.ImOnline=0; 223 //要发送对象的地址 224 225 strIp=(LPCTSTR)(_bstr_t)m_record->GetCollect("ImIp"); 226 strPort=(LPCTSTR)(_bstr_t)m_record->GetCollect("ImPort"); 227 strOnline=(LPCTSTR)(_bstr_t)m_record->GetCollect("ImOnline"); 228 strIp.TrimRight(" "); 229 strPort.TrimRight(" "); 230 strOnline.TrimRight(" "); 231 232 233 remoteAddr.sin_addr.S_un.S_addr=inet_addr(strIp); 234 remoteAddr.sin_port=htons(atoi(strPort)); 235 if(strOnline=="1" && strPort!="0") 236 ::sendto(pThis->g_s,(char *)&peerMsg,sizeof(peerMsg),0,(sockaddr *)&remoteAddr,sizeof(remoteAddr)); 237 m_record->MoveNext(); 238 } 239 240 241 } 242 break; 243 244 245 //[3/15]获取通讯录列表///////////////////////////////////////////////////////////// 246 case GETUSERLIST: 247 { 248 int Online=0; 249 strNo=pMsg->peer.ImNo; 250 //写到日志列表中 251 time=COleDateTime::GetCurrentTime(); 252 strTime=time.Format("%H:%M:%S "); 253 strLog=strTime+strNo+" 获取通讯录列表"; 254 ::PostMessage(g_pPage3->m_hWnd,WM_NEWLOG,(WPARAM)(LPCTSTR)strLog,0); 255 // 256 vSQL="select ImNo,ImName,ImOnline from imuser where ImNo!='"+strNo+"'"; 257 m_record=pThis->ado.GetRecordSet(vSQL); 258 while(!m_record->adoEOF) 259 { 260 CP2PMessage peerMsg={0}; 261 strNo=(LPCTSTR)(_bstr_t)m_record->GetCollect("ImNo"); 262 strName=(LPCTSTR)(_bstr_t)m_record->GetCollect("ImName"); 263 Online=atoi((LPCTSTR)(_bstr_t)m_record->GetCollect("ImOnline")); 264 //去掉空格 265 strNo.TrimRight(" "); 266 strName.TrimRight(" "); 267 strcpy((char*)peerMsg.peer.ImNo,(LPCSTR)(LPCTSTR)strNo); 268 strcpy((char*)peerMsg.peer.ImName,(LPCSTR)(LPCTSTR)strName); 269 peerMsg.peer.ImOnline=Online; 270 peerMsg.nMessageType=GETUSERLISTACK; 271 ::sendto(pThis->g_s,(char *)&peerMsg,sizeof(peerMsg),0,(sockaddr *)&remoteAddr,sizeof(remoteAddr)); 272 m_record->MoveNext(); 273 } 274 275 } 276 break; 277 278 //[4/15]获取好友列表///////////////////////////////////////////////////////////////////////// 279 case GETFRIENDLIST: 280 { 281 int Online=0; 282 strNo=pMsg->peer.ImNo; 283 //写到日志列表中 284 time=COleDateTime::GetCurrentTime(); 285 strTime=time.Format("%H:%M:%S "); 286 strLog=strTime+strNo+" 获取好友列表"; 287 ::PostMessage(g_pPage3->m_hWnd,WM_NEWLOG,(WPARAM)(LPCTSTR)strLog,0); 288 // 289 vSQL="select ImNo,ImName,ImOnline from imuser,friend where friend.imno1='"+strNo+"' and friend.imno2=imuser.imno"; 290 m_record=pThis->ado.GetRecordSet(vSQL); 291 while(!m_record->adoEOF) 292 { 293 CP2PMessage peerMsg={0}; 294 strNo=(LPCTSTR)(_bstr_t)m_record->GetCollect("ImNo"); 295 strName=(LPCTSTR)(_bstr_t)m_record->GetCollect("ImName"); 296 Online=atoi((LPCTSTR)(_bstr_t)m_record->GetCollect("ImOnline")); 297 //去掉空格 298 strNo.TrimRight(" "); 299 strName.TrimRight(" "); 300 strcpy((char*)peerMsg.peer.ImNo,(LPCSTR)(LPCTSTR)strNo); 301 strcpy((char*)peerMsg.peer.ImName,(LPCSTR)(LPCTSTR)strName); 302 peerMsg.peer.ImOnline=Online; 303 peerMsg.nMessageType=GETFRIENDLISTACK; 304 ::sendto(pThis->g_s,(char *)&peerMsg,sizeof(peerMsg),0,(sockaddr *)&remoteAddr,sizeof(remoteAddr)); 305 m_record->MoveNext(); 306 } 307 } 308 break; 309 310 //[5/15]发给服务器的语音 311 case GETVOIP: 312 strNo=(char*)(pMsg+1); 313 //是发给服务器的语音,则返回信息,否则转发(P2PCONNECT 的处理相同) 314 if(strNo=="10000") 315 { 316 //有语音请求,需建立监听 317 ::SendMessage(g_pDlg->m_hWnd,WM_NEWVOIP,NULL,NULL); 318 //保存发送方的端口,如果g_nVOIPPort不为0表示已经连接,还没断开 319 CP2PMessage ackMsg; 320 ackMsg.nMessageType=GETVOIPACK; 321 memcpy(&ackMsg.peer,&pThis->m_LocalPeer,sizeof(PEER_INFO)); 322 sockaddr_in peerAddr ={0}; 323 peerAddr.sin_family=AF_INET; 324 325 if(g_nVOIPPort==0 && !g_pDlg->m_bBtnConnectDown) 326 { 327 g_nVOIPPort=pMsg->peer.p2pAddr.nPort; 328 ackMsg.peer.p2pAddr.nPort=g_nLocalPort; 329 330 } 331 else 332 { 333 ackMsg.peer.p2pAddr.nPort=0; //返回0表示对方正在通话中 334 335 } 336 337 for(int i=0;i<pMsg->peer.AddrNum;i++) 338 { 339 peerAddr.sin_addr.S_un.S_addr=pMsg->peer.addr[i].dwIp; 340 peerAddr.sin_port=htons(pMsg->peer.addr[i].nPort); 341 ::sendto(pThis->g_s,(char *)&ackMsg,sizeof(ackMsg),0,(sockaddr *)&peerAddr,sizeof(peerAddr)); 342 //CString str; 343 //str=::inet_ntoa(peerAddr.sin_addr); 344 //AfxMessageBox(str); 345 } 346 break; 347 } 348 349 //[6/15]连接:消息转发的实现 *关键技术*///////////////////////////////////////////////////////////////////////// 350 case P2PCONNECT: 351 { 352 strNo=(char*)(pMsg+1); 353 CString strFrom=pMsg->peer.ImNo; 354 if(pMsg->nMessageType==P2PCONNECT) 355 { 356 //写到日志列表中 357 time=COleDateTime::GetCurrentTime(); 358 strTime=time.Format("%H:%M:%S "); 359 strLog=strTime+strFrom+"--->"+strNo+" 消息请求"; 360 ::PostMessage(g_pPage3->m_hWnd,WM_NEWLOG,(WPARAM)(LPCTSTR)strLog,0); 361 362 } 363 else 364 { 365 //写到日志列表中 366 time=COleDateTime::GetCurrentTime(); 367 strTime=time.Format("%H:%M:%S "); 368 strLog=strTime+strFrom+"--->"+strNo+" 语音请求"; 369 ::PostMessage(g_pPage3->m_hWnd,WM_NEWLOG,(WPARAM)(LPCTSTR)strLog,0); 370 } 371 372 //如果A发给server,则服务器直接应答 373 if(strNo=="10000") 374 { 375 CP2PMessage ackMsg; 376 ackMsg.nMessageType=P2PCONNECTACK; 377 memcpy(&ackMsg.peer,&pThis->m_LocalPeer,sizeof(PEER_INFO)); 378 ::sendto(pThis->g_s,(char *)&ackMsg,sizeof(ackMsg),0,(sockaddr*)&remoteAddr,sizeof(remoteAddr)); //发送确认连接 379 380 } 381 //如果A发给B,则sever从数据库中搜索B地址,按此地址转发给B 382 else 383 { 384 vSQL="select * from imuser where ImNo='"+strNo+"' "; 385 m_record=pThis->ado.GetRecordSet(vSQL); 386 if(!m_record->adoEOF) 387 { 388 strIp=(LPCTSTR)(_bstr_t)m_record->GetCollect("ImIp"); 389 strPort=(LPCTSTR)(_bstr_t)m_record->GetCollect("ImPort"); 390 strOnline=(LPCTSTR)(_bstr_t)m_record->GetCollect("ImOnline"); 391 strIp.TrimRight(" "); 392 strPort.TrimRight(" "); 393 strOnline.TrimRight(" "); 394 if(strOnline=="1" && strPort!="0") 395 { 396 remoteAddr.sin_addr.S_un.S_addr=inet_addr(strIp); 397 remoteAddr.sin_port=htons(atoi(strPort)); 398 ::sendto(pThis->g_s,(char*)pMsg,sizeof(CP2PMessage),0,(sockaddr*)&remoteAddr,sizeof(remoteAddr)); 399 } 400 } 401 else //语音请求的账号不存在 402 { 403 if(pMsg->nMessageType==GETVOIP) 404 { 405 pMsg->nMessageType=GETVOIPACK; 406 pMsg->peer.p2pAddr.nPort=10000; //端口==10000表示账号不存在 407 ::sendto(pThis->g_s,(char *)pMsg,sizeof(CP2PMessage),0,(sockaddr*)&remoteAddr,sizeof(remoteAddr)); 408 409 } 410 } 411 } 412 //AfxMessageBox(strNo); 413 414 } 415 break; 416 417 //[7/15]加为好友//////////////////////////////////////////////////////////////////////// 418 case ADDFRIEND: 419 { 420 CString strFrom,strTo; 421 strFrom=pMsg->peer.ImNo; 422 strTo=(char *)(pMsg+1); 423 //写到日志列表中 424 time=COleDateTime::GetCurrentTime(); 425 strTime=time.Format("%H:%M:%S "); 426 strLog=strTime+strFrom+"--->"+strTo+" 加为好友"; 427 ::PostMessage(g_pPage3->m_hWnd,WM_NEWLOG,(WPARAM)(LPCTSTR)strLog,0); 428 //AfxMessageBox(strFrom+"------>"+strTo); 429 strNo=(char*)(pMsg+1); 430 vSQL="select * from imuser where ImNo='"+strTo+"' "; 431 m_record=pThis->ado.GetRecordSet(vSQL); 432 if(!m_record->adoEOF) 433 { 434 strIp=(LPCTSTR)(_bstr_t)m_record->GetCollect("ImIp"); 435 strPort=(LPCTSTR)(_bstr_t)m_record->GetCollect("ImPort"); 436 strOnline=(LPCTSTR)(_bstr_t)m_record->GetCollect("ImOnline"); 437 strIp.TrimRight(" "); 438 strPort.TrimRight(" "); 439 strOnline.TrimRight(" "); 440 if(strOnline=="1" && strPort!="0") 441 { 442 remoteAddr.sin_addr.S_un.S_addr=inet_addr(strIp); 443 remoteAddr.sin_port=htons(atoi(strPort)); 444 ::sendto(pThis->g_s,(char*)pMsg,sizeof(CP2PMessage)+sizeof(NewFriendMessage),0,(sockaddr*)&remoteAddr,sizeof(remoteAddr)); 445 } 446 else //没在线,先将离线好友请求添加到数据库中 447 { 448 //取得记录集 449 char *pNo=(char*)(pMsg+1); 450 vSQL="select * from OffAddfriend"; 451 m_record=pThis->ado.GetRecordSet(vSQL); 452 m_record->AddNew(); /**////添加新记录 453 m_record->PutCollect("ImNo",_variant_t(pNo)); /**////为新记录填充ImNo字段 454 455 //将离线请求写到数据库 456 char *pBuf = buff; 457 VARIANT varBLOB; 458 SAFEARRAY *psa; 459 SAFEARRAYBOUND rgsabound[1]; 460 if(pBuf) 461 { 462 rgsabound[0].lLbound = 0; 463 rgsabound[0].cElements = dwRecv; //存入的数据是去掉用户名的 464 psa = SafeArrayCreate(VT_UI1, 1, rgsabound); /**////创建SAFEARRAY对象 465 for (long i = 0; i <(long)dwRecv; i++) 466 SafeArrayPutElement (psa, &i, pBuf++); /**////将pBuf指向的二进制数据保存到SAFEARRAY对象psa中 467 468 varBLOB.vt = VT_ARRAY | VT_UI1; /**////将varBLOB的类型设置为BYTE类型的数组 469 varBLOB.parray = psa; /**////为varBLOB变量赋值 470 m_record->GetFields()->GetItem("ImInfo")->Value=varBLOB; /**////加入BLOB类型的数据 471 } 472 m_record->Update(); 473 } 474 } 475 476 } 477 break; 478 479 //[8/15]strTo 答应 strFrom 好友请求()//////////////////////////////////////////////////// 480 case ADDFRIENDACK: 481 { 482 CString strFrom,strTo; 483 BOOL bAllow; 484 NewFriendMessage *pNew=(NewFriendMessage *)(pMsg+1); 485 strFrom=pNew->szNo; 486 strTo=pMsg->peer.ImNo; 487 bAllow=pNew->bAllow; 488 //写到日志列表中 489 time=COleDateTime::GetCurrentTime(); 490 strTime=time.Format("%H:%M:%S "); 491 strLog=strTime+strTo+"--->"+strFrom+" 接受加为好友"; 492 ::PostMessage(g_pPage3->m_hWnd,WM_NEWLOG,(WPARAM)(LPCTSTR)strLog,0); 493 //返回确认消息 494 vSQL="select * from imuser where ImNo='"+strFrom+"' "; 495 m_record=pThis->ado.GetRecordSet(vSQL); 496 if(!m_record->adoEOF) 497 { 498 strNo=(LPCTSTR)(_bstr_t)m_record->GetCollect("ImNo"); 499 strName=(LPCTSTR)(_bstr_t)m_record->GetCollect("ImName"); 500 strIp=(LPCTSTR)(_bstr_t)m_record->GetCollect("ImIp"); 501 strPort=(LPCTSTR)(_bstr_t)m_record->GetCollect("ImPort"); 502 strOnline=(LPCTSTR)(_bstr_t)m_record->GetCollect("ImOnline"); 503 strNo.TrimRight(" "); 504 strName.TrimRight(" "); 505 strIp.TrimRight(" "); 506 strPort.TrimRight(" "); 507 strOnline.TrimRight(" "); 508 //先给对方发送 509 if(bAllow) 510 { 511 vSQL="select * from friend where ImNo1='"+strTo+"' and ImNo2='"+strFrom+"' "; 512 m_record=pThis->ado.GetRecordSet(vSQL); 513 if(m_record->adoEOF) 514 { 515 vSQL="insert into friend values('"+strTo+"','"+strFrom+"')"; 516 pThis->ado.ExecuteSQL(vSQL); 517 CP2PMessage peerMsg={0}; 518 strcpy((char*)peerMsg.peer.ImNo,(LPCSTR)(LPCTSTR)strNo); 519 strcpy((char*)peerMsg.peer.ImName,(LPCSTR)(LPCTSTR)strName); 520 peerMsg.peer.ImOnline=atoi(strOnline); 521 peerMsg.nMessageType=ADDFRIENDACK; 522 ::sendto(pThis->g_s,(char*)&peerMsg,sizeof(CP2PMessage),0,(sockaddr*)&remoteAddr,sizeof(remoteAddr)); 523 } 524 } 525 // 526 vSQL="select * from friend where ImNo1='"+strFrom+"' and ImNo2='"+strTo+"' "; 527 m_record=pThis->ado.GetRecordSet(vSQL); 528 if(m_record->adoEOF) 529 { 530 vSQL="insert into friend values('"+strFrom+"','"+strTo+"')"; 531 pThis->ado.ExecuteSQL(vSQL); 532 } 533 //在给发送方发送确认信息 534 if(strOnline=="1" && strPort!="0") 535 { 536 537 pMsg->peer.ImOnline=1; 538 remoteAddr.sin_addr.S_un.S_addr=inet_addr(strIp); 539 remoteAddr.sin_port=htons(atoi(strPort)); 540 //直接转发就可以了,消息包中已经包含对方的信息 541 ::sendto(pThis->g_s,(char*)pMsg,sizeof(CP2PMessage),0,(sockaddr*)&remoteAddr,sizeof(remoteAddr)); 542 543 } 544 545 546 } 547 548 } 549 break; 550 551 //[9/15]服务器收到客户端节点发给服务器的消息///////////////////////////////////////////////////// 552 case P2PMESSAGE: 553 { 554 int nDataLen=dwRecv-sizeof(CP2PMessage)-sizeof(MessageInfo); 555 if(nDataLen>0) 556 { 557 //发送确认消息 558 CP2PMessage ackMsg; 559 ackMsg.nMessageType=P2PMESSAGEACK; 560 memcpy(&ackMsg.peer,&pThis->m_LocalPeer,sizeof(PEER_INFO)); 561 ::sendto(pThis->g_s,(char *)&ackMsg,sizeof(ackMsg),0,(sockaddr*)&remoteAddr,sizeof(remoteAddr)); 562 563 CString strText,strNo,strName; 564 strName=pMsg->peer.ImName; 565 strNo=pMsg->peer.ImNo; 566 strText=strName+"("+strNo+")"; 567 HWND hwnd=pThis->FindMessage(strText); 568 //找到消息窗口,如果消息窗口存在,则将消息直接传过去,否则弹出提示 569 if(!hwnd) 570 { 571 ::SendMessage(g_pPage1->m_hWnd,WM_NEWMESSAGE,(WPARAM)(pMsg+1),(LPARAM)(LPTSTR)(LPCTSTR)strText); 572 } 573 else 574 { 575 ::SendMessage(hwnd,WM_NEWMESSAGE,(WPARAM)(pMsg+1),(LPARAM)(LPTSTR)(LPCTSTR)strText); 576 } 577 578 } 579 } 580 break; 581 582 //[9/15]收到消息应答 583 case P2PMESSAGEACK: 584 { 585 pThis->m_bMessageACK=TRUE; 586 } 587 break; 588 589 //[10/15]语音连接应答 590 case GETVOIPACK: 591 { 592 //得到从对方返回的监听端口,如果为0.表示对方正在通话中 593 if(pMsg->peer.p2pAddr.nPort==0) 594 { 595 g_strVOIP="0.0.0.0"; 596 //AfxMessageBox("对不起,对方正在通话中,请稍后再拨!"); 597 } 598 else 599 { 600 //保存被叫方的IP和监听端口 601 g_strVOIP=::inet_ntoa(remoteAddr.sin_addr); 602 g_nVOIPPort=pMsg->peer.p2pAddr.nPort; 603 604 //CString str,str1; 605 //str.Format("对方的监听端口是:%d\r\n",g_nVOIPPort); 606 //str1.Format("本地的监听端口是:%d",g_nLocalPort); 607 //AfxMessageBox(str+str1); 608 } 609 } 610 break; 611 612 //[11/15]离线消息 613 case OFFP2PMESSAGE: 614 { 615 DWORD size=dwRecv-sizeof(CP2PMessage)-sizeof(MessageInfo)-MAX_USERNAME; //消息长,去掉对方的用户名后 616 MessageInfo *pInfo=(MessageInfo *)(pMsg+1); 617 char *pNo=(char *)(pInfo+1); 618 CString strFrom,strTo; 619 strFrom=pMsg->peer.ImNo; 620 strTo=pNo; 621 //写到日志列表中 622 time=COleDateTime::GetCurrentTime(); 623 strTime=time.Format("%H:%M:%S "); 624 strLog=strTime+strFrom+"--->"+strTo+" 离线消息"; 625 ::PostMessage(g_pPage3->m_hWnd,WM_NEWLOG,(WPARAM)(LPCTSTR)strLog,0); 626 //取得记录集 627 vSQL="select * from OfflineMessage"; 628 m_record=pThis->ado.GetRecordSet(vSQL); 629 m_record->AddNew(); /**////添加新记录 630 m_record->PutCollect("ImNo",_variant_t(pNo)); /**////为新记录填充ImNo字段 631 632 memcpy(pNo,pNo+MAX_USERNAME,size); 633 //将离线消息写到数据库 634 char *pBuf = buff; 635 VARIANT varBLOB; 636 SAFEARRAY *psa; 637 SAFEARRAYBOUND rgsabound[1]; 638 if(pBuf) 639 { 640 size=dwRecv-MAX_USERNAME; 641 rgsabound[0].lLbound = 0; 642 rgsabound[0].cElements = size; //存入的数据是去掉用户名的 643 psa = SafeArrayCreate(VT_UI1, 1, rgsabound); /**////创建SAFEARRAY对象 644 for (long i = 0; i <(long)size; i++) 645 SafeArrayPutElement (psa, &i, pBuf++); /**////将pBuf指向的二进制数据保存到SAFEARRAY对象psa中 646 647 varBLOB.vt = VT_ARRAY | VT_UI1; /**////将varBLOB的类型设置为BYTE类型的数组 648 varBLOB.parray = psa; /**////为varBLOB变量赋值 649 m_record->GetFields()->GetItem("ImMsg")->Value=varBLOB; /**////加入BLOB类型的数据 650 } 651 m_record->Update(); /**////保存我们的数据到库中 652 } 653 break; 654 655 //[12/15]删除好友/////////////////////////////////////////////////////////////////// 656 case DELETEFRIEND: 657 { 658 //int nPos=str.Find("("); 659 //CString strNo=str.Mid(nPos+1,str.GetLength()-nPos-2); 660 CString strFrom,strTo; 661 strFrom=pMsg->peer.ImNo; 662 strTo=(char *)(pMsg+1); //发过来的消息里含有用户名 663 int nPos=strTo.Find("("); 664 strTo=strTo.Mid(nPos+1,strTo.GetLength()-nPos-2); 665 666 vSQL="delete from friend where ImNo1='"+strFrom+"' and ImNo2='"+strTo+"'"; 667 if(pThis->ado.ExecuteSQL(vSQL)) 668 { 669 //写到日志列表中 670 671 time=COleDateTime::GetCurrentTime(); 672 strTime=time.Format("%H:%M:%S "); 673 strLog=strTime+strFrom+"--->"+strNo+" 删除好友"; 674 ::PostMessage(g_pPage3->m_hWnd,WM_NEWLOG,(WPARAM)(LPCTSTR)strLog,0); 675 676 pMsg->nMessageType=DELETEFRIENDACK; 677 ::sendto(pThis->g_s,(char*)pMsg,sizeof(CP2PMessage)+MAX_USERNAME*2,0,(sockaddr*)&remoteAddr,sizeof(remoteAddr)); 678 679 } 680 681 } 682 break; 683 684 //[13/15]得到用户自己信息////////////////////////////////////////////////////////// 685 case GETUSERINFO: 686 { 687 strNo=(char *)(pMsg+1); 688 vSQL="select * from imuser where ImNo='"+strNo+"'"; 689 m_record=pThis->ado.GetRecordSet(vSQL); 690 if(!m_record->adoEOF) 691 { 692 693 strName=(LPCTSTR)(_bstr_t)m_record->GetCollect("ImName"); 694 strIp=(LPCTSTR)(_bstr_t)m_record->GetCollect("ImIp"); 695 strPort=(LPCTSTR)(_bstr_t)m_record->GetCollect("ImPort"); 696 strPhone=(LPCTSTR)(_bstr_t)m_record->GetCollect("ImPhone"); 697 698 strName.TrimRight(" "); 699 strIp.TrimRight(" "); 700 strPort.TrimRight(" "); 701 strPhone.TrimRight(" "); 702 703 //登陆成功,并返回用户自己的信息 704 pMsg->nMessageType=GETUSERINFOACK; 705 strcpy((char*)pMsg->peer.ImName,(LPCSTR)(LPCTSTR)strName); 706 strcpy((char*)pMsg->peer.ImNo,(LPCSTR)(LPCTSTR)strNo); 707 strcpy((char*)pMsg->peer.ImPhone,(LPCSTR)(LPCTSTR)strPhone); 708 pMsg->peer.p2pAddr.dwIp=::inet_addr(strIp); 709 pMsg->peer.p2pAddr.nPort=::atoi(strPort); 710 pMsg->nMessageType=GETUSERINFOACK; 711 ::sendto(pThis->g_s,(char*)pMsg,sizeof(CP2PMessage),0,(sockaddr*)&remoteAddr,sizeof(remoteAddr)); 712 713 714 } 715 } 716 break; 717 718 //[14/15]群聊技术的实现:*关键技术*//////////////////////////////////////////////////////// 719 case GROUPMESSAGE: 720 { 721 strNo=pMsg->peer.ImNo; 722 vSQL="select ImIp,ImPort,ImOnline from imuser where ImNo!='"+strNo+"'and ImOnline=1"; //只要IP地址和端口号 723 m_record=pThis->ado.GetRecordSet(vSQL); 724 while(!m_record->adoEOF) 725 { 726 //要发送对象的地址 727 strIp=(LPCTSTR)(_bstr_t)m_record->GetCollect("ImIp"); 728 strPort=(LPCTSTR)(_bstr_t)m_record->GetCollect("ImPort"); 729 strOnline=(LPCTSTR)(_bstr_t)m_record->GetCollect("ImOnline"); 730 strIp.TrimRight(" "); 731 strPort.TrimRight(" "); 732 strOnline.TrimRight(" "); 733 734 remoteAddr.sin_addr.S_un.S_addr=inet_addr(strIp); 735 remoteAddr.sin_port=htons(atoi(strPort)); 736 if(strOnline=="1" && strPort!="0") 737 ::sendto(pThis->g_s,(char *)pMsg,dwRecv,0,(sockaddr *)&remoteAddr,sizeof(remoteAddr)); 738 m_record->MoveNext(); 739 } 740 741 CString strText,strMessage; 742 MessageInfo *pInfo=(MessageInfo *)(pMsg+1); 743 strNo=pMsg->peer.ImNo; 744 strName=pMsg->peer.ImName; 745 strText=strName+"("+strNo+") "; 746 strMessage=(char *)(pInfo+1); 747 748 PlaySound("wav\\msg.wav", NULL, SND_FILENAME | SND_ASYNC); 749 if(g_pDlg->m_pGroupMessage) 750 { 751 g_pDlg->m_pGroupMessage->AddName(FALSE,strText); 752 g_pDlg->m_pGroupMessage->AddText(strMessage+"\r\n",pInfo); 753 } 754 else 755 { 756 //群窗口没打开的话,则发送该消息 757 ::SendMessage(g_pDlg->m_hWnd,WM_NEWGROUPMESSAGE,(WPARAM)pMsg,(LPARAM)(LPTSTR)(LPCTSTR)strText); 758 759 } 760 761 } 762 break; 763 764 765 766 } 767 768 } 769 return 0; 770} 771 772 773 774 775//查找链表,返回用户名等于 str 的对话框句柄 776HWND CP2PServer::FindMessage(CString str) 777{ 778 critical_section.Lock(); 779 MessageUser user; 780 POSITION nPos=g_MessageList.GetHeadPosition(); 781 while(nPos) 782 { 783 user=g_MessageList.GetNext(nPos); 784 if(user.m_strText==str) 785 { 786 critical_section.Unlock(); 787 return user.m_hWnd; 788 } 789 790 } 791 critical_section.Unlock(); 792 return NULL; 793 794} 795
|