多人在局域网上线,实现用户列表的步骤。
1、程序启动(初始化),单独只有自己。
2、发送广播,给其它用户。
3、接收其它用户发送的信息。
4、更新自己的用户列表
为了简化程序,用控制台实现,用户列表用字符串形式显示。
类 MultiSock 实现,主程序调用
头文件MultiSock.h
#include <list>
using namespace std;
#pragma comment(lib,"WS2_32")
struct hostinfo
{
string hostip;
string hostname;
};
class MultiSock
{
public:
MultiSock(void);
~MultiSock(void);
DWORD m_dwMultiAddr;
USHORT m_port;
SOCKET s;
sockaddr_in si;
hostinfo m_host;
list<string> m_listhost; //上线主机名列表
list<string> m_listip; //上线主机IP列表
void RecvPacket(void);//接收广播和发送自己信息到广播组
void DisplayHost(void);//显示主机名列表
};
类实现MultiSock.cpp
#include "stdafx.h"
#include "MultiSock.h"
#include <string>
using namespace std;
MultiSock::MultiSock(void)
{
WSADATA wsaData;
char hostname[255];
PHOSTENT hostinfo;
WORD sockVersion = MAKEWORD(2,2);
if (WSAStartup(sockVersion,&wsaData) != 0)
//载入动态库
{
return;
}
//获取自己本机的电脑名和IP
if (gethostname(hostname,sizeof(hostname)) == 0)
{
if ((hostinfo = gethostbyname(hostname)) !=NULL)
{
LPSTR ip = inet_ntoa(*(struct in_addr *)*hostinfo->h_addr_list);
m_host.hostip=ip;
m_host.hostname=hostname;
m_listhost.push_back(m_host.hostname);
m_listip.push_back(ip);
}
}
s=socket(AF_INET,SOCK_DGRAM,0);
BOOL bReuse=TRUE;
setsockopt(s,SOL_SOCKET, SO_REUSEADDR,(char*)&bReuse,sizeof(BOOL));
m_dwMultiAddr=inet_addr(m_host.hostip.c_str());
m_port=4567;
// m_dwMultiAddr=inet_addr("230.1.1.99");
si.sin_family = AF_INET;
si.sin_port = ntohs(m_port);
si.sin_addr.S_un.S_addr = INADDR_ANY;
// INADDR_ANY 监听所有IP
bind(s,(sockaddr*)&si, sizeof(si));
bool bopt=TRUE;
setsockopt(s, SOL_SOCKET, SO_BROADCAST, (char*)&bopt, sizeof(bopt));
int nTTL=64;
int nRet=setsockopt(s,IPPROTO_IP,IP_MULTICAST_TTL,(char*)&nTTL,sizeof(nTTL));
if (nRet==SOCKET_ERROR)
{
return;
}
ip_mreq mcast;
mcast.imr_interface.S_un.S_addr=INADDR_ANY;
mcast.imr_multiaddr.S_un.S_addr=m_dwMultiAddr;
setsockopt(s,IPPROTO_IP,IP_ADD_MEMBERSHIP,(char*)&mcast,sizeof(mcast));
sockaddr_in sRemote;
sRemote.sin_family=AF_INET;
sRemote.sin_port=htons(m_port);
//广播给所有地址
sRemote.sin_addr.S_un.S_addr=INADDR_BROADCAST;
int ret=sendto(s,m_host.hostname.c_str(),strlen(m_host.hostname.c_str()),0,(sockaddr*)&sRemote,sizeof(sRemote));
DisplayHost(); //发送后显示自己在线
}
MultiSock::~MultiSock(void)
{
sockaddr_in sRemote;
sRemote.sin_family=AF_INET;
sRemote.sin_port=htons(m_port);
sRemote.sin_addr.S_un.S_addr=INADDR_BROADCAST;
int ret=sendto(s,"Leave this party\r\n",strlen("Leave this party\r\n"),0,(sockaddr*)&sRemote,sizeof(sRemote));
ip_mreq mcast;
mcast.imr_interface.S_un.S_addr=INADDR_ANY;
mcast.imr_multiaddr.S_un.S_addr=m_dwMultiAddr;
setsockopt(s,IPPROTO_IP,IP_DROP_MEMBERSHIP,(char*)&mcast,sizeof(mcast));
int nRecvBuf=32*1024;
setsockopt(s,SOL_SOCKET,SO_RCVBUF,(const char*)&nRecvBuf,sizeof(int));
int nSendBuf=32*1024;
setsockopt(s,SOL_SOCKET,SO_SNDBUF,(const char*)&nSendBuf,sizeof(int));
WSACleanup();
}
void MultiSock::RecvPacket(void)
{
MessageBox(NULL,TEXT("程序开始接收"),TEXT("接收"),MB_OK);
char buf[10280];
char err[10];
int nAddrLen = sizeof(si);
PHOSTENT hostinfo;
while(TRUE)
{
Sleep(50);
int nRet = ::recvfrom(s,buf,sizeof(buf),0,(sockaddr*)&si,&nAddrLen);
bool bflag=false;
if (nRet != SOCKET_ERROR)
{
buf[nRet]='\0';
if ((strcmp(buf,m_host.hostname.c_str())))
{
//列表中主机名不在加入列表,避免重复上线
for (list<string>::iterator l_host=m_listhost.begin();l_host!=m_listhost.end();++l_host)
{
bflag=false;
if (strcmp(buf,l_host->c_str()))
{
bflag=true;
}
}
if (bflag)
{
m_listhost.push_back(buf);
if (gethostname(buf,sizeof(buf)) == 0)
{
if ((hostinfo = gethostbyname(buf)) !=NULL)
{
LPSTR ip = inet_ntoa(*(struct in_addr *)*hostinfo->h_addr_list);
m_listip.push_back(ip);
m_dwMultiAddr=inet_addr(ip);
sockaddr_in sRemote;
sRemote.sin_family=AF_INET;
sRemote.sin_port=htons(m_port);
sRemote.sin_addr.S_un.S_addr=INADDR_BROADCAST;
//发送自己的主机名给其它人员
int ret=sendto(s,m_host.hostname.c_str(),strlen(m_host.hostname.c_str()),0,(sockaddr*)&sRemote,sizeof(sRemote));
}
}
DisplayHost(); //有新加入的成员重新刷新列表
}
}
// MessageBox(NULL,buf,TEXT("數據"),MB_OK);
}
else
{
int n=::WSAGetLastError();
itoa(n,err,10);
MessageBox(NULL,err,TEXT("數據"),MB_OK);
break;
}
}
}
//显示列表
void MultiSock::DisplayHost(void)
{
string display;
for (list<string>::iterator l_host=m_listhost.begin();l_host!=m_listhost.end();++l_host)
{
display.append(*l_host);
}
MessageBox(NULL,display.c_str(),TEXT("在線"),MB_OK);
}
主程序main.cpp
#include "stdafx.h"
#include "MultiSock.h"
int _tmain(int argc, _TCHAR* argv[])
{
MultiSock mySock;
mySock.RecvPacket();
getchar();
return 0;
}