这次有个Server端,可以消息广播.50秒没有心跳删除一个客户端地址.客户端没有绑定端口,只能与服务端进行通信.没有检测包是否到达以及是否正确 server: // UDPServer.cpp : 定义控制台应用程序的入口点。 // #include "stdafx.h" #include <winsock.h> #include <iostream> #pragma comment(lib,"ws2_32.lib") using namespace std; #define MAXUSER 10 SOCKET s; SOCKADDR_IN sclient_addr[MAXUSER]; char client_ip[MAXUSER][100]; u_short client_port[MAXUSER]; u_short client_heart[MAXUSER]; int rightclient; void SaveAddr(SOCKADDR_IN& sfrom); void CheckHeart(SOCKADDR_IN& sfrom); void SendAllUser(SOCKADDR_IN& sfrom,char *buf); DWORD CALLBACK OnTimer(HWND hwnd,UINT uMsg,UINT_PTR idEvent,DWORD dwTime) { //让每个连接的这个数目加,如果++到10都还没有收到清0的心跳包,就删除这个人的ip for(int i=0;i<MAXUSER;i++) { if(client_port[i]!=0) { //对于存在呢 client_heart[i]++; if(client_heart[i]>=10) { //删除 client_port[i]=0; rightclient--; cout<<"del index=["<<i<<"] user"<<endl; } } } return 0; } DWORD WINAPI HeartThread(void) { UINT timeId=SetTimer(NULL,1,5000,(TIMERPROC)OnTimer); MSG msg; while(GetMessage(&msg,NULL,0,0)) { if(msg.message==WM_TIMER) { DispatchMessage(&msg); } } KillTimer(NULL,timeId); return 0; } int _tmain(int argc, _TCHAR* argv[]) { //初始化 rightclient=0; for(int i=0;i<10;i++) { ZeroMemory(client_ip[i],100); client_port[i]=0; } WSADATA wsaData; WORD dv=MAKEWORD(2,2); WSAStartup(dv,&wsaData); s=socket(AF_INET,SOCK_DGRAM,0); SOCKADDR_IN sin; sin.sin_addr.S_un.S_addr=htonl(INADDR_ANY); sin.sin_family=AF_INET; sin.sin_port=htons(2008); int iMode = 1; ioctlsocket(s,FIONBIO,(u_long FAR*)&iMode);//设置模式 bind(s,(SOCKADDR*)&sin,sizeof(sin)); //开始心跳线程 DWORD lpThreadId2; CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)HeartThread,NULL,0,&lpThreadId2); fd_set fd_read; int len=sizeof(SOCKADDR_IN); SOCKADDR_IN sfrom; char buf[1024]; ZeroMemory(buf,1024); int ret=0; cout<<"start"<<endl; while(1) { ZeroMemory(buf,1024); FD_ZERO(&fd_read); FD_SET(s,&fd_read); select(0,&fd_read,NULL,NULL,NULL); if(FD_ISSET(s,&fd_read)) { recvfrom(s,buf,1024,0,(SOCKADDR*)&sfrom,&len); switch(buf[0]) { case 1://Client启动 { SaveAddr(sfrom); } break; case 9://Client心跳 { CheckHeart(sfrom); } break; case 10://聊天内容 { SendAllUser(sfrom,&buf[1]); } break; } } } closesocket(s); return 0; } void SendAllUser(SOCKADDR_IN& sfrom,char *buf) { char restr[1024]; strcpy(restr,inet_ntoa(sfrom.sin_addr)); char *mao=" : "; strcat(restr,mao); strcat(restr,buf); for(int i=0;i<MAXUSER;i++) { if(client_port[i]!=0) { sendto(s,restr,strlen(restr)+1,0,(SOCKADDR*)&sclient_addr[i],sizeof(sclient_addr[i])); } } } void CheckHeart(SOCKADDR_IN& sfrom) { for(int i=0;i<MAXUSER;i++) { if(client_port[i]!=0) { char fromip[100]; u_short fromport; strcpy(fromip,inet_ntoa(sfrom.sin_addr)); fromport=sfrom.sin_port; if(client_port[i]==fromport&&strcmp(fromip,client_ip[i])==0) { client_heart[i]=0; return; } } } } void SaveAddr(SOCKADDR_IN& sfrom) { if(rightclient>=9) { //超过最大连接数 char *buf="超过最大连接数"; sendto(s,buf,sizeof(buf),0,(SOCKADDR*)&sfrom,sizeof(sfrom)); return; } for(int i=0;i<MAXUSER;i++) { if(client_port[i]==0) { char fromip[100]; strcpy(fromip,inet_ntoa(sfrom.sin_addr)); memcpy(client_ip[rightclient],fromip,sizeof(fromip));//记录ip client_port[i]=sfrom.sin_port;//记录端口 memcpy(&sclient_addr[i],&sfrom,sizeof(sfrom));//记录地址 client_heart[i]=0; rightclient++; cout<<"have a new user ip connected index="<<i<<" ["<<fromip<<"]"<<" port:"<<ntohs(sfrom.sin_port)<<" nowusertotal="<<rightclient<<endl; return; } } } 客户端: // UDPClient.cpp : 定义控制台应用程序的入口点。 // #include "stdafx.h" #include <winsock.h> #include <iostream> #pragma comment(lib,"ws2_32.lib") using namespace std; SOCKET s; SOCKADDR_IN sin; u_long ul_heart; DWORD WINAPI RecvThread(LPVOID lpParam); DWORD WINAPI HeartThread(void); DWORD CALLBACK OnTimer(HWND hwnd,UINT uMsg,UINT_PTR idEvent,DWORD dwTime); int _tmain(int argc, _TCHAR* argv[]) { WSADATA wsaData; WORD dv=MAKEWORD(2,2); WSAStartup(dv,&wsaData); //input connect ip cout<<"input ip:"<<endl; char ip[100]; cin>>ip; s=socket(AF_INET,SOCK_DGRAM,0); sin.sin_addr.S_un.S_addr=inet_addr(ip); sin.sin_family=AF_INET; sin.sin_port=htons(2008); DWORD lpThreadId; CreateThread(NULL,0,RecvThread,NULL,0,&lpThreadId); DWORD lpThreadId2; CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)HeartThread,NULL,0,&lpThreadId2); //启动的时候先发送 char start=1; sendto(s,&start,1,0,(SOCKADDR*)&sin,sizeof(sin)); while(1) { char buf[1024]; ZeroMemory(buf,1024); cin>>buf; char buffer[1024]; ZeroMemory(buffer,1024); buffer[0]=10; strcpy(&buffer[1],buf); if(sendto(s,buffer,strlen(buf)+1+1,0,(SOCKADDR*)&sin,sizeof(sin))==SOCKET_ERROR) { cout<<"send fail"<<endl; //cout<<"send ok"<<" send to:"<<inet_ntoa(sin.sin_addr)<<" port:"<<ntohs(sin.sin_port)<<endl; } } return 0; } DWORD CALLBACK OnTimer(HWND hwnd,UINT uMsg,UINT_PTR idEvent,DWORD dwTime) { //printf("send heart %d/n/t %d",ul_heart,uMsg); char buf; buf=9; sendto(s,&buf,1,0,(SOCKADDR*)&sin,sizeof(sin)); ul_heart++; return 0; } DWORD WINAPI HeartThread(void) { UINT timeId=SetTimer(NULL,1,5000,(TIMERPROC)OnTimer); MSG msg; while(GetMessage(&msg,NULL,0,0)) { if(msg.message==WM_TIMER) { DispatchMessage(&msg); } } KillTimer(NULL,timeId); return 0; } //ntohl,ntohs,htonl,htons,ntoa DWORD WINAPI RecvThread(LPVOID lpParam) { fd_set fd_read; char buf[1024]; ZeroMemory(buf,1024); int len=sizeof(sin); while(1) { FD_ZERO(&fd_read); FD_SET(s,&fd_read); select(0,&fd_read,NULL,NULL,NULL); if(FD_ISSET(s,&fd_read)) { recvfrom(s,buf,1024,0,(SOCKADDR*)&sin,&len); cout<<buf<<endl; } } return 0; }