这是一个用VC++写的P2P聊天程序,客户端连接服务器的时候连接不上(这个服务器只是记录着连接服务器的客户端的信息,与C/S结构的服务器不同),哪位好心人能帮忙看一下,哪里出错了???万分感谢了!!!!服务器的部分代码:
BOOL CP2PServerDlg::OnInitDialog()
{
.................................
// TODO: Add extra initialization here
//创建套接字,绑定到本地端口
g_s=::WSASocket(AF_INET,SOCK_DGRAM,IPPROTO_UDP,NULL,0,WSA_FLAG_OVERLAPPED);
sockaddr_in sin;
sin.sin_family=AF_INET;
sin.sin_port=htons(SERVER_PORT);
sin.sin_addr.S_un.S_addr=INADDR_ANY;
if(::bind(g_s,(LPSOCKADDR)&sin,sizeof(sin))==SOCKET_ERROR)
{
MessageBox("绑定套接字失败!");
return;
}
//下面这段代码用来显示服务器绑定的终端
::gethostname(szHost,256);
hostent *pHost=::gethostbyname(szHost);
for(int i=0;;i++)
{
char *p=pHost->h_addr_list[i];
if(p==NULL)
break;
memcpy(&addr.S_un.S_addr,p,pHost->h_length);
SetDlgItemText(IDC_EDIT1,::inet_ntoa(addr));
SetDlgItemText(IDC_EDIT2,"4567");
}
SetDlgItemText(IDC_EDIT3,"P2P服务器连接成功!\n\n");
::InitializeCriticalSection(&g_PeerListLock); PARAM *pParam=new PARAM;
pParam->socket=g_s;
pParam->hwnd=m_hWnd;
s_hThread=::CreateThread(NULL,0,IOThreadProc,(LPVOID)pParam,0,NULL);
return TRUE;
}
DWORD WINAPI CP2PServerDlg::IOThreadProc(LPVOID lpParam)
{
SOCKET socket=((PARAM*)lpParam)->socket;
HWND hwnd=((PARAM*)lpParam)->hwnd;
char buff[MAX_PACKET_SIZE];
sockaddr_in remoteAddr;
int nRecv,nAddrLen=sizeof(remoteAddr);
while(TRUE)
{
nRecv=::recvfrom(socket,buff,MAX_PACKET_SIZE,0,(sockaddr*)&remoteAddr,&nAddrLen);
if(nRecv==SOCKET_ERROR)
break;
if(nRecv<sizeof(CP2PMessage))
break;
//防止用户发送错误的用户名
CP2PMessage *pMsg=(CP2PMessage*)buff;
pMsg->peer.szUserName[MAX_USERNAME]='\0';
switch(pMsg->nMessageType)
{
case USERLOGIN:
{
pMsg->peer.addr[pMsg->peer.AddrNum].dwIp=remoteAddr.sin_addr.S_un.S_addr;
pMsg->peer.addr[pMsg->peer.AddrNum].nPort=ntohs(remoteAddr.sin_port);
pMsg->peer.AddrNum++;
pMsg->peer.dwLastActiveTime=::GetTickCount();
::EnterCriticalSection(&g_PeerListLock);
BOOL bOK=g_PeerList.AddAPeer(&pMsg->peer);
::LeaveCriticalSection(&g_PeerListLock);
char tempBuf[200];
if(bOK)
{
pMsg->nMessageType=USERLOGACK;
::sendto(socket,(char*)pMsg,sizeof(CP2PMessage),0,(sockaddr*)&remoteAddr,sizeof(remoteAddr));
sprintf(tempBuf,"登录服务器成功");
::PostMessage(hwnd,WM_LOGIN,0,(LPARAM)tempBuf);
}
}
break;
case USERLOGOUT:
{
::EnterCriticalSection(&g_PeerListLock);
g_PeerList.DeleteAPeer(pMsg->peer.szUserName);
::LeaveCriticalSection(&g_PeerListLock);
//SetDlgItemText(IDC_EDIT3,"有个用户退出");
}
break;
}
}
return 0;
}void CP2PServerDlg::OnLogin(WPARAM wParam,LPARAM lParam)
{
CString str=(char*)lParam;
CString strTemp;
GetDlgItemText(IDC_EDIT3,strTemp);
str+="\r\n";
str+=strTemp;
SetDlgItemText(IDC_EDIT3,str);}客户端的部分代码:
DWORD WINAPI CP2PClientDlg::RecvThreadProc(LPVOID lpParam)
{
CP2PClientDlg *pThis=(CP2PClientDlg*)lpParam;
char buff[MAX_PACKET_SIZE];
sockaddr_in remoteAddr;
int nAddrLen=sizeof(remoteAddr);
WSABUF wsaBuf;
wsaBuf.buf=buff;
wsaBuf.len=MAX_PACKET_SIZE;
//接收处理到来的消息
while(TRUE)
{
DWORD dwRecv,dwFlags=0;
int nRet=::WSARecvFrom(pThis->m_s,&wsaBuf,1,&dwRecv,&dwFlags,(sockaddr*) &remoteAddr,&nAddrLen,&pThis->m_ol,NULL);
if(nRet==SOCKET_ERROR&&::WSAGetLastError()==WSA_IO_PENDING)
{
::WSAGetOverlappedResult(pThis->m_s,&pThis->m_ol,&dwRecv,TRUE,&dwFlags); }
//首先查看是否要退出
if(pThis->m_bThreadExit) break;
//调用HandleIO函数来处理这个消息
pThis->HandleIO(buff,dwRecv,(sockaddr*)&remoteAddr,nAddrLen);
}
return 0;}void CP2PClientDlg::HandleIO(char *pBuf, int nBufLen, sockaddr *addr, int nAddrLen)
{
CP2PMessage *pMsg=(CP2PMessage*)pBuf;
if(nBufLen<sizeof(CP2PMessage))
return;
switch(pMsg->nMessageType)
{
case USERLOGACK: //接收到服务器发来的登录确认
{
memcpy(&m_LocalPeer,&pMsg->peer,sizeof(PEER_INFO));
m_bLogin=TRUE;
}
break;
......
}
}
void CP2PClientDlg::OnBtnLink()
{
// TODO: Add your control notification handler code here
char szServerIp[20];
char szUserName[MAX_USERNAME];
GetDlgItem(IDC_EDIT_SERVERIP)->GetWindowText(szServerIp,20);
GetDlgItem(IDC_EDIT_USERNAME)->GetWindowText(szUserName,15); if(m_bLogin||strlen((char*)szUserName)>MAX_USERNAME-1)
MessageBox("连接失败");
//保存参数
m_dwServerIp=::inet_addr((char*)szServerIp);
strncpy(m_LocalPeer.szUserName,(char*)szUserName,strlen((char*)szUserName));
//服务器名称
sockaddr_in serverAddr;
serverAddr.sin_family=AF_INET;
serverAddr.sin_addr.S_un.S_addr=m_dwServerIp;
serverAddr.sin_port=htons(SERVER_PORT);
//向服务发送本用户信息
CP2PMessage logMsg;
logMsg.nMessageType=USERLOGIN;
memcpy(&logMsg.peer,&m_LocalPeer,sizeof(PEER_INFO));
for(int i=0;i<MAX_TRY_NUMBER;i++)
{
::sendto(m_s,(char*)&logMsg,sizeof(logMsg),0,(sockaddr*)&serverAddr,sizeof(serverAddr));
for(int j=0;j<10;j++)
{
if(m_bLogin)
return ;
::Sleep(300);
}
}
return ;
}
BOOL CP2PServerDlg::OnInitDialog()
{
.................................
// TODO: Add extra initialization here
//创建套接字,绑定到本地端口
g_s=::WSASocket(AF_INET,SOCK_DGRAM,IPPROTO_UDP,NULL,0,WSA_FLAG_OVERLAPPED);
sockaddr_in sin;
sin.sin_family=AF_INET;
sin.sin_port=htons(SERVER_PORT);
sin.sin_addr.S_un.S_addr=INADDR_ANY;
if(::bind(g_s,(LPSOCKADDR)&sin,sizeof(sin))==SOCKET_ERROR)
{
MessageBox("绑定套接字失败!");
return;
}
//下面这段代码用来显示服务器绑定的终端
::gethostname(szHost,256);
hostent *pHost=::gethostbyname(szHost);
for(int i=0;;i++)
{
char *p=pHost->h_addr_list[i];
if(p==NULL)
break;
memcpy(&addr.S_un.S_addr,p,pHost->h_length);
SetDlgItemText(IDC_EDIT1,::inet_ntoa(addr));
SetDlgItemText(IDC_EDIT2,"4567");
}
SetDlgItemText(IDC_EDIT3,"P2P服务器连接成功!\n\n");
::InitializeCriticalSection(&g_PeerListLock); PARAM *pParam=new PARAM;
pParam->socket=g_s;
pParam->hwnd=m_hWnd;
s_hThread=::CreateThread(NULL,0,IOThreadProc,(LPVOID)pParam,0,NULL);
return TRUE;
}
DWORD WINAPI CP2PServerDlg::IOThreadProc(LPVOID lpParam)
{
SOCKET socket=((PARAM*)lpParam)->socket;
HWND hwnd=((PARAM*)lpParam)->hwnd;
char buff[MAX_PACKET_SIZE];
sockaddr_in remoteAddr;
int nRecv,nAddrLen=sizeof(remoteAddr);
while(TRUE)
{
nRecv=::recvfrom(socket,buff,MAX_PACKET_SIZE,0,(sockaddr*)&remoteAddr,&nAddrLen);
if(nRecv==SOCKET_ERROR)
break;
if(nRecv<sizeof(CP2PMessage))
break;
//防止用户发送错误的用户名
CP2PMessage *pMsg=(CP2PMessage*)buff;
pMsg->peer.szUserName[MAX_USERNAME]='\0';
switch(pMsg->nMessageType)
{
case USERLOGIN:
{
pMsg->peer.addr[pMsg->peer.AddrNum].dwIp=remoteAddr.sin_addr.S_un.S_addr;
pMsg->peer.addr[pMsg->peer.AddrNum].nPort=ntohs(remoteAddr.sin_port);
pMsg->peer.AddrNum++;
pMsg->peer.dwLastActiveTime=::GetTickCount();
::EnterCriticalSection(&g_PeerListLock);
BOOL bOK=g_PeerList.AddAPeer(&pMsg->peer);
::LeaveCriticalSection(&g_PeerListLock);
char tempBuf[200];
if(bOK)
{
pMsg->nMessageType=USERLOGACK;
::sendto(socket,(char*)pMsg,sizeof(CP2PMessage),0,(sockaddr*)&remoteAddr,sizeof(remoteAddr));
sprintf(tempBuf,"登录服务器成功");
::PostMessage(hwnd,WM_LOGIN,0,(LPARAM)tempBuf);
}
}
break;
case USERLOGOUT:
{
::EnterCriticalSection(&g_PeerListLock);
g_PeerList.DeleteAPeer(pMsg->peer.szUserName);
::LeaveCriticalSection(&g_PeerListLock);
//SetDlgItemText(IDC_EDIT3,"有个用户退出");
}
break;
}
}
return 0;
}void CP2PServerDlg::OnLogin(WPARAM wParam,LPARAM lParam)
{
CString str=(char*)lParam;
CString strTemp;
GetDlgItemText(IDC_EDIT3,strTemp);
str+="\r\n";
str+=strTemp;
SetDlgItemText(IDC_EDIT3,str);}客户端的部分代码:
DWORD WINAPI CP2PClientDlg::RecvThreadProc(LPVOID lpParam)
{
CP2PClientDlg *pThis=(CP2PClientDlg*)lpParam;
char buff[MAX_PACKET_SIZE];
sockaddr_in remoteAddr;
int nAddrLen=sizeof(remoteAddr);
WSABUF wsaBuf;
wsaBuf.buf=buff;
wsaBuf.len=MAX_PACKET_SIZE;
//接收处理到来的消息
while(TRUE)
{
DWORD dwRecv,dwFlags=0;
int nRet=::WSARecvFrom(pThis->m_s,&wsaBuf,1,&dwRecv,&dwFlags,(sockaddr*) &remoteAddr,&nAddrLen,&pThis->m_ol,NULL);
if(nRet==SOCKET_ERROR&&::WSAGetLastError()==WSA_IO_PENDING)
{
::WSAGetOverlappedResult(pThis->m_s,&pThis->m_ol,&dwRecv,TRUE,&dwFlags); }
//首先查看是否要退出
if(pThis->m_bThreadExit) break;
//调用HandleIO函数来处理这个消息
pThis->HandleIO(buff,dwRecv,(sockaddr*)&remoteAddr,nAddrLen);
}
return 0;}void CP2PClientDlg::HandleIO(char *pBuf, int nBufLen, sockaddr *addr, int nAddrLen)
{
CP2PMessage *pMsg=(CP2PMessage*)pBuf;
if(nBufLen<sizeof(CP2PMessage))
return;
switch(pMsg->nMessageType)
{
case USERLOGACK: //接收到服务器发来的登录确认
{
memcpy(&m_LocalPeer,&pMsg->peer,sizeof(PEER_INFO));
m_bLogin=TRUE;
}
break;
......
}
}
void CP2PClientDlg::OnBtnLink()
{
// TODO: Add your control notification handler code here
char szServerIp[20];
char szUserName[MAX_USERNAME];
GetDlgItem(IDC_EDIT_SERVERIP)->GetWindowText(szServerIp,20);
GetDlgItem(IDC_EDIT_USERNAME)->GetWindowText(szUserName,15); if(m_bLogin||strlen((char*)szUserName)>MAX_USERNAME-1)
MessageBox("连接失败");
//保存参数
m_dwServerIp=::inet_addr((char*)szServerIp);
strncpy(m_LocalPeer.szUserName,(char*)szUserName,strlen((char*)szUserName));
//服务器名称
sockaddr_in serverAddr;
serverAddr.sin_family=AF_INET;
serverAddr.sin_addr.S_un.S_addr=m_dwServerIp;
serverAddr.sin_port=htons(SERVER_PORT);
//向服务发送本用户信息
CP2PMessage logMsg;
logMsg.nMessageType=USERLOGIN;
memcpy(&logMsg.peer,&m_LocalPeer,sizeof(PEER_INFO));
for(int i=0;i<MAX_TRY_NUMBER;i++)
{
::sendto(m_s,(char*)&logMsg,sizeof(logMsg),0,(sockaddr*)&serverAddr,sizeof(serverAddr));
for(int j=0;j<10;j++)
{
if(m_bLogin)
return ;
::Sleep(300);
}
}
return ;
}
{
......
if(m_s!=INVALID_SOCKET)
return FALSE;
//创建用于P2P通信的UDP套接字,进行绑定
m_s=::WSASocket(AF_INET,SOCK_DGRAM,IPPROTO_UDP,NULL,0,WSA_FLAG_OVERLAPPED);
sockaddr_in localAddr;
localAddr.sin_family=AF_INET;
localAddr.sin_port=htons(SERVER_PORT);
localAddr.sin_addr.S_un.S_addr=INADDR_ANY;
if(::bind(m_s,(LPSOCKADDR)&localAddr,sizeof(localAddr))==SOCKET_ERROR)
{
::closesocket(m_s);
m_s=INVALID_SOCKET;
return FALSE;
}
int nLen=sizeof(localAddr);
::getsockname(m_s,(sockaddr*)&localAddr,&nLen); //获取本地机器的IP地址,得到当前用户的私有终端
char szHost[256];
::gethostname(szHost,256);
hostent *pHost=::gethostbyname(szHost);
memset(&m_LocalPeer,0,sizeof(m_LocalPeer));
for(int i=0;i<MAX_ADDR_NUMBER-1;i++)
{
char *p=pHost->h_addr_list[i];
if(p==NULL)
break;
memcpy(&m_LocalPeer.addr[i].dwIp,&p,pHost->h_length);
m_LocalPeer.addr[i].nPort=SERVER_PORT;
m_LocalPeer.AddrNum++;
}
//创建接收服务线程
m_bThreadExit=FALSE;
c_hThread=::CreateThread(NULL,0,RecvThreadProc,this,0,NULL);
return TRUE; // return TRUE unless you set the focus to a control
}
WSADATA wsaData;
int err;
wVersionRequested = MAKEWORD( 1, 1 );
int nRet;
err = WSAStartup( wVersionRequested, &wsaData );
if ( err != 0 ) {
return 0;
}
if ( LOBYTE( wsaData.wVersion ) != 1 ||
HIBYTE( wsaData.wVersion ) != 1 ) {
WSACleanup( );
return 0;
}