如何搜索局域网中开放同一端口的机器IP 形如在SQL中,在使用导入导出向导的时候SQL会把局域网中所有的可用SQL服务器列出,即查找局域网内所有开放1433端口的机器,现在想实现这个功能,如何实现?请教各位。 解决方案 » 免费领取超大流量手机卡,每月29元包185G流量+100分钟通话, 中国电信官方发货 主要思想是:广播数据报,如果有回复,则进行解析并得出结果。或者通过建立socket连接的成功与否来判断,但是不知道Java如何实现,如new socket("192.168.1."+i,8001); 先获取当前的IP,然后根据子网掩码得出所有子网内的IP范围。 然后就是尝试连接。好一点,不光TCP,还要看udp等 利用socket编程发送一个广播,根据响应获取相应的IP地址 头文件: /* 扫描局域网活动主机端口类 LanActiveHost */ #include <winsock.h> #pragma comment(lib, "ws2_32.lib") class LanActiveHost { public: //建议线程 不超过200 毫秒超时设置 最好大于1秒 小于1秒结果不可靠 LanActiveHost(short _MaxThread,short _Port,DWORD _TimeOutValue); ~LanActiveHost(); BOOL GetHostIP(); BOOL GetIP3(); BOOL InitIPList(); static BOOL Try3_ConnSelect(fd_set r,struct timeval tm); static BOOL Try3_SendSelect(fd_set r,struct timeval tm); static BOOL Try3_RecvSelect(fd_set r,struct timeval tm); static BOOL CFG_DP(); static BOOL Chk_ServMsg(int id); static BOOL SetMsgRec(BOOL flag,int id); static DWORD WINAPI DoScanPort(LPVOID lpParam); static DWORD WINAPI StartScan(LPVOID lpParam); static BOOL GetServerMSG(char ServerMsg[256][34]); BOOL StartListServer(); BOOL EndListServer(); BOOL Get_IPIndex(char ip[256][16],char index[256]); private: HANDLE Handle; //父线程句柄 static DWORD TimeOutValue ; //连接超时时间,以ms计 static short ThreadCount; //当前正在扫描的进程数 static short Port; //端口 static char IP[256][16]; //局域网IP列表 static char Index[256]; //局域网活动服务器 是1 否0 static char send_str[5]; //发送数据缓存 static char recv_str[256][40]; //接收数据缓存 static int send_len; static int recv_len; static char RecvMsg[256][34]; //收到每个主机返回的信息 32 GSP 1 Num short MaxThread; //最大允许的扫描线程数,不宜大于200 char HostIP[16]; //本机IP char IP3[16]; //IP前3段 }; 用c++搞过,但没有用java搞过 实现文件 .cpp #include "LanHost.h" DWORD LanActiveHost::TimeOutValue ; short LanActiveHost::ThreadCount ; short LanActiveHost::Port ; char LanActiveHost::IP[256][16] ; char LanActiveHost::Index[256] ; char LanActiveHost::send_str[5] ; char LanActiveHost::recv_str[256][40] ; int LanActiveHost::send_len ; int LanActiveHost::recv_len ; char LanActiveHost::RecvMsg[256][34]; //构造函数 LanActiveHost::LanActiveHost(short _MaxThread,short _Port,DWORD _TimeOutValue) { MaxThread = _MaxThread; Port = _Port; TimeOutValue = _TimeOutValue; //配置数据协议 LanActiveHost::CFG_DP(); } //析构函数 LanActiveHost::~LanActiveHost() { } //获取本机IP地址 BOOL LanActiveHost::GetHostIP() { char HostName[128]; LPSTR Addr; struct hostent FAR *HostEnt; //获取主机名称 -1错误 0成功 if( gethostname(HostName, sizeof(HostName)) == SOCKET_ERROR ) return FALSE; //获取名称结构 HostEnt = gethostbyname (HostName); //主机名称可能有多个IP地址 在此默认第一个地址 Addr = HostEnt->h_addr_list[0]; //IP -> XXX.XXX.XXX.XXX if (!Addr) return FALSE; else { struct in_addr inAddr; memmove (&inAddr, Addr, 4); strcpy(HostIP,inet_ntoa (inAddr)); } return TRUE; } // 得到IP前3段 XXX.XXX.XXX.XXX -> XXX.XXX.XXX. --------------------- BOOL LanActiveHost::GetIP3() { int i=0,j=0; while(1) { IP3[i]=HostIP[i]; if(HostIP[i]=='.') j++; if(j==3) break; i++; } IP3[i+1]='\0'; return TRUE; } //初始化局域网 IP列表 BOOL LanActiveHost::InitIPList() { int i; char IP4[4]; //获取本机IP if( !LanActiveHost::GetHostIP() ) return FALSE; //获取IP前三段 LanActiveHost::GetIP3(); //初始化局域网IP for(i=1;i <=255;i++) { strcpy(IP[i],IP3); itoa(i,IP4,10); strcat(IP[i],IP4); IP[i][strlen(IP[i])]='\0'; } return TRUE; } //配置网络数据协议 BOOL LanActiveHost::CFG_DP() { send_str[0] = 'A'; send_str[1] = 'M'; send_str[2] = CMSG_See; send_str[3] = '\0'; send_len = 5; recv_len = 40; return TRUE; } //检查接收内容是否正确 BOOL LanActiveHost::Chk_ServMsg(int id) { if( recv_str[id][0]=='A' && recv_str[id][1]=='M' && (unsigned char)recv_str[id][2]==SMSG_Server ) return TRUE; else return FALSE; } //设置接收信息记录 BOOL LanActiveHost::SetMsgRec(BOOL flag,int id) { if(flag==TRUE) { //记录 Index[id]=1; DataCopy(recv_str[id]+3,RecvMsg[id],33); RecvMsg[id][33]='\0'; } else { //清零 Index[id]=0; memset(RecvMsg[id],0,sizeof(RecvMsg[id])); } return TRUE; } //连接监听尝试3次 成功返回1 失败返回0 BOOL LanActiveHost::Try3_ConnSelect(fd_set r,struct timeval tm) { int num = 1; //尝试第一1次 int ret = select(0, NULL, &r, NULL, &tm); //若失败再尝试2次 while( ret <=0 && num <3 ) { ret = select(0, NULL, &r, NULL, &tm); num++; } //返回结果 if( ret>0 ) return TRUE; else return FALSE; } //发送监听尝试3次 成功返回1 失败返回0 BOOL LanActiveHost::Try3_SendSelect(fd_set r,struct timeval tm) { int num = 1; //尝试第一1次 int ret = select(0, NULL, &r, NULL, &tm); //若失败再尝试2次 while( ret <=0 && num <3 ) { ret = select(0, NULL, &r, NULL, &tm); num++; } //返回结果 if( ret>0 ) return TRUE; else return FALSE; } //接收监听尝试3次 成功返回1 失败返回0 BOOL LanActiveHost::Try3_RecvSelect(fd_set r,struct timeval tm) { int num = 1; //尝试第一1次 int ret = select(0, &r, NULL, NULL, &tm); //若失败再尝试2次 while( ret <=0 && num <3 ) { ret = select(0, &r, NULL, NULL, &tm); num++; } //返回结果 if( ret>0 ) return TRUE; else return FALSE; } //对外接口 提供接收的服务器信息 BOOL LanActiveHost::GetServerMSG(char Msg[256][34]) { int i; //Msg清零 memset(Msg,0,sizeof(Msg)); //如果是服务器 提交信息 for(i=1;i <=255;i++) if(Index[i]==1) DataCopy(RecvMsg[i],Msg[i],33); return TRUE; } //扫描局域网存活主机 子线程函数 DWORD WINAPI LanActiveHost::DoScanPort(LPVOID lpParam) { int id = (int)lpParam; //创建套接字 SOCKET sock = socket(AF_INET, SOCK_STREAM, 0); //创建套接字失败 if(sock == INVALID_SOCKET) { ThreadCount --; return 0; } //创建套接字成功 else { //强制关闭,不经历TIME_WAIT过程 BOOL bDontLinger = FALSE; setsockopt(sock,SOL_SOCKET,SO_DONTLINGER,(const char*)&bDontLinger,sizeof(BOOL)); //设置非阻塞socket unsigned long flag = 1; int ret = ioctlsocket(sock, FIONBIO, (unsigned long*)&flag); //设置失败 if( ret == SOCKET_ERROR ) { ThreadCount --; return 0; } //主机地址 sockaddr_in Addr; Addr.sin_family = AF_INET; Addr.sin_port = htons(Port); Addr.sin_addr.S_un.S_addr =inet_addr(IP[id]); //连接主机 connect(sock, (sockaddr*)&Addr, sizeof(Addr)); //超时设置 struct fd_set mask; FD_ZERO(&mask); FD_SET(sock, &mask); struct timeval timeout; timeout.tv_sec = TimeOutValue/1000; //秒 timeout.tv_usec = (TimeOutValue%1000)*1000; //微秒 //连接成功 if( LanActiveHost::Try3_ConnSelect(mask,timeout) == TRUE ) //监听发送 if( LanActiveHost::Try3_SendSelect(mask,timeout) == TRUE ) send(sock,send_str,send_len,0); strcpy(recv_str[id],"NULL\0"); //监听接收 if( LanActiveHost::Try3_RecvSelect(mask,timeout) == TRUE ) recv(sock,recv_str[id],recv_len,0); //接收内容正确 if( LanActiveHost::Chk_ServMsg(id) == TRUE ) LanActiveHost::SetMsgRec(TRUE,id); else LanActiveHost::SetMsgRec(FALSE,id); //断开连接 shutdown(sock,0); closesocket(sock); sock = -1; } ThreadCount --; return 1; } //扫描局域网存活主机 父线程函数 DWORD WINAPI LanActiveHost::StartScan(LPVOID lpParam) { DWORD ThreadId; unsigned short i; for(i=1; i <=255; i++) if (CreateThread(NULL, 0,LanActiveHost::DoScanPort, (LPVOID)i, 0, &ThreadId) != NULL) ThreadCount ++; //等待所有子线程退出 while (ThreadCount > 0) Sleep(20); return 1; } //扫描局域网存活主机 BOOL LanActiveHost::StartListServer() { //初始化局域网 IP列表与索引 if( !LanActiveHost::InitIPList() ) return FALSE; //线程计数器初始化 ThreadCount = 0; //创建扫描父线程,该线程包含多个子线程 DWORD ThreadId; Handle = CreateThread(NULL, 0,LanActiveHost::StartScan, NULL, 0, &ThreadId); //线程创建成功 if( Handle ) return TRUE; //线程创建失败 else return FALSE; } //等待扫描线程安全退出 BOOL LanActiveHost::EndListServer() { //等待子线程退出 while( ThreadCount>0 ) Sleep(20); //等待父线程退出 Sleep(100); return TRUE; } //外部接口提供服务器IP列表 存活索引 BOOL LanActiveHost::Get_IPIndex(char ip_list[256][16],char ip_index[256]) { int i; for(i=1;i <=255;i++) if(Index[i]==1) { strcpy(ip_list[i],IP[i]); ip_index[i] = Index[i]; } else ip_index[i] = 0; return TRUE; } 主机端 应答 头文件 class LanServer { public: //客户端最大15 最小1 LanServer(int _Port,int _Max_Client,int _TimeOut,int _HeartTimeOut); ~LanServer(); BOOL InitServer(); BOOL Listen(short blockbuf); BOOL GetPlayer(int id); static BOOL Try3_SendSelect(fd_set r,struct timeval tm); static BOOL Try3_RecvSelect(fd_set r,struct timeval tm); // BOOL ClientMSG_PRC(int id,char recv[],PLAYER_DATA player_data); BOOL EndSock(int id); static UINT ServerThread(LPVOID p); static BOOL GetFreeSock(int &id,int &num); private: int Port; int PlayerPos[16]; static int TimeOut; static int HeartTimeOut; static SOCKET Socket[17]; static sockaddr_in Addr; static int AddrLen; static int Max_Client; }; 实现文件 //主机端 #include "Server.h" int LanServer::TimeOut; int LanServer::HeartTimeOut; int LanServer::Max_Client; int LanServer::AddrLen=0; SOCKET LanServer::Socket[17]; sockaddr_in LanServer::Addr; char StrGet[300]; //构造函数 LanServer::LanServer(int _Port,int _Max_Client,int _TimeOut,int _HeartTimeOut) { Port = _Port; Max_Client = _Max_Client; TimeOut = _TimeOut; HeartTimeOut = _HeartTimeOut; } //析构函数 LanServer::~LanServer() { LanServer::EndSock(-1); } //初始化服务器 绑定端口 BOOL LanServer::InitServer() { int i; //所有套接字初始化 for (i=0;i <=Max_Client+1;i++) Socket[i] = -1; //设定地址 Addr.sin_addr.s_addr= htonl(INADDR_ANY); Addr.sin_family = AF_INET; Addr.sin_port = htons(Port); AddrLen = sizeof(Addr); //创建socket Socket[0] =socket(AF_INET,SOCK_STREAM,0); //创建socket失败 if( Socket[0] == INVALID_SOCKET ) return FALSE; //强制关闭,不经历TIME_WAIT过程 BOOL bDontLinger = FALSE; setsockopt(Socket[0],SOL_SOCKET,SO_DONTLINGER,(const char*)&bDontLinger,sizeof(BOOL)); //绑定成功 if ( bind(Socket[0],(sockaddr*)&Addr,sizeof(Addr)) ==0) return TRUE; //绑定失败 else return FALSE; } //开始监听 BOOL LanServer::Listen(short blockbuf) { listen(Socket[0],blockbuf); return TRUE; } //获取空闲套接字 BOOL LanServer::GetFreeSock(int &id,int &num) { int i; id = 0; num = 0; for(i=Max_Client+1;i>=1;i--) if (Socket[i]==-1) { id = i; num ++ ; } return TRUE; } //终止连接 BOOL LanServer::EndSock(int id) { int i; //非法操作 if(id <-1 || id>15) return FALSE; //若索引为0-15 则终止该索引对应的套接字 if(id>=0 && Socket[id]!=-1) { closesocket(Socket[id]); Socket[id]=-1; } //若索引为 -1 则终止所有 套接字 else if(id==-1) for(i=0;i <=Max_Client;i++) { closesocket(Socket[id]); Socket[id]=-1; } return TRUE; } //尝试3次接收监听 成功返回1 失败返回0 BOOL LanServer::Try3_RecvSelect(fd_set r,struct timeval tm) { int num = 1; //尝试第一1次 int ret = select(0, &r, NULL, NULL, &tm); //若失败再尝试2次 while( ret <=0 && num <3 ) { ret = select(0, &r, NULL, NULL, &tm); num++; } //返回结果 if( ret>0 ) return TRUE; else return FALSE; } //尝试3次接收监听 成功返回1 失败返回0 BOOL LanServer::Try3_SendSelect(fd_set r,struct timeval tm) { int num = 1; //尝试第一1次 int ret = select(0, NULL, &r, NULL, &tm); //若失败再尝试2次 while( ret <=0 && num <3 ) { ret = select(0, NULL, &r, NULL, &tm); num++; } //返回结果 if( ret>0 ) return TRUE; else return FALSE; } //服务器工作线程 UINT LanServer::ServerThread(LPVOID p) { int id,num; //获得客户端数量 LanServer::GetFreeSock(id,num); while( num==1 ) { //终止线程 Sleep(20); LanServer::GetFreeSock(id,num); } //接受连接 Socket[id]=accept(Socket[0],(sockaddr*)&Addr,&AddrLen); //强制关闭,不经历TIME_WAIT过程 BOOL bDontLinger = FALSE; setsockopt(Socket[id],SOL_SOCKET,SO_DONTLINGER,(const char*)&bDontLinger,sizeof(BOOL)); //开启新线程 AfxBeginThread(LanServer::ServerThread,0); CAMatchDlg *dlg= (CAMatchDlg *)AfxGetApp()->GetMainWnd(); if ( Socket[id]!=INVALID_SOCKET ) //连接正确 { //设置非阻塞方式 unsigned long ul = 1; ioctlsocket(Socket[id], FIONBIO, (unsigned long*)&ul); fd_set r; FD_ZERO(&r); FD_SET(Socket[id], &r); struct timeval tm; tm.tv_sec = TimeOut/1000 ; tm.tv_usec = (TimeOut%1000)*1000; while(1) { //尝试3次接收监听 if( LanServer::Try3_RecvSelect(r,tm) == FALSE ) break; //接收数据 if( recv(Socket[id],StrGet,230,0) <=0 ) break; //处理接收数据 ClientMSG_Processing(id,msg_data.StrGet,client_data); //处理发送数据 int Ret = ClientMSG_Put(id, msg_data.StrGet, am_skin, client_data, am_game, msg_data.StrPut); //发送数据 if( (Ret==2 || Ret==3) && LanServer::Try3_SendSelect(r,tm) == TRUE ) { if( send(Socket[id], msg_data.StrPut, 50,0) <=0 ) send(Socket[id], msg_data.StrPut, 50,0); } //关闭套接字 if( Ret==0 || Ret==2 ) break; } } closesocket(Socket[id]); Socket[id]=-1; ::AfxMessageBox("服务器断开",0,0); //终止线程 AfxEndThread(0); return 0; } //处理客户端信息 TRUE 保持 FALSE 断开 BOOL LanServer::ClientMSG_PRC(int id,char recv[],PLAYER_DATA player_data,char Msg[]) { //非法数据不处理 if( !(recv[0]=='A' && recv[1]=='M') ) return TRUE; //依据协议 为即将发送的数据 添加数据头 memset(Msg,0,sizeof(Msg)); Msg[0]='A'; Msg[1]='M'; //获取消息类型 int MSG_ID = (unsigned char)recv[2]; //依据类型处理 switch( MSG_ID ) { //查询服务器信息 case CMSG_See: { Msg[2] = SMSG_Server; DataCopy(player_data.GSP,Msg+3,32); int i,num=0; for(i=0;i <16;i++) if( client_data.Flag[i] ) num++; Msg[35] = num; Msg[36] = '\0'; return TRUE; } //申请加入服务器 case CMSG_Ask: { //拷贝玩家名称 char sname[17]; DataCopy(recv+3,sname,16); //增加玩家信息 AddPlayer(id, sname, player_data.Live, player_data.Flag, player_data.Name[id]); return TRUE; } //准备完毕 等待开始 case CMSG_Ready: { //拷贝初始化棋盘数据 DataCopy(recv+3, player_data.Init[id], 216); return TRUE; } //游戏进度 case CMSG_Game: { //数据包次序 int PackID = (unsigned char)recv[3]; //对比次序 判断是否丢失严重 100 210 321 432 543 if( PackID - (unsigned char)palyer_data.PID[id] >= 3 ) return FALSE; //更新数据包次序 palyer_data.PID[id] = PackID; //拷贝销毁点 与 交换点 DataCopy(recv+4, player_data.SP[id], 3); DataCopy(recv+7, player_data.EP[id], 3); return TRUE; } //离开游戏 case CMSG_Leave: { //删除玩家信息 DeletePlayer(id, player_data.Live, player_data.Flag, player_data.Name[id]); return FALSE; } //保持信号 case CMSG_Keep: { //心跳包计数器 增加 player_data.Signal[id] ++; return TRUE; } //默认不处理 default : return TRUE; } } 和这个帖子比较相似http://topic.csdn.net/u/20091121/15/1a817a3b-e903-4413-aa19-b280b4bf303a.html list的删除 问一个问题,我有一个byte数组,我要将它转成字符串,我如何控制,才能不让它在最后一位产生乱码 哈希表的输出 利用流操作文件,并保存到数据库的代码 java的JSpinner 用Socket写的实现Smtp的邮件发送端。 求各位一段java小程序.... 使用被弃用的方法到底对程序有没有影响? timer問題,請教 如何不用设置DSN,使用jdbc连接远端Internet数据库 用java 读取硬盘的序列号 this是干什么用的?
头文件:
/*
扫描局域网活动主机端口类 LanActiveHost
*/
#include <winsock.h>
#pragma comment(lib, "ws2_32.lib") class LanActiveHost
{
public:
//建议线程 不超过200 毫秒超时设置 最好大于1秒 小于1秒结果不可靠
LanActiveHost(short _MaxThread,short _Port,DWORD _TimeOutValue);
~LanActiveHost();
BOOL GetHostIP();
BOOL GetIP3();
BOOL InitIPList();
static BOOL Try3_ConnSelect(fd_set r,struct timeval tm);
static BOOL Try3_SendSelect(fd_set r,struct timeval tm);
static BOOL Try3_RecvSelect(fd_set r,struct timeval tm); static BOOL CFG_DP();
static BOOL Chk_ServMsg(int id);
static BOOL SetMsgRec(BOOL flag,int id); static DWORD WINAPI DoScanPort(LPVOID lpParam);
static DWORD WINAPI StartScan(LPVOID lpParam);
static BOOL GetServerMSG(char ServerMsg[256][34]);
BOOL StartListServer();
BOOL EndListServer();
BOOL Get_IPIndex(char ip[256][16],char index[256]);
private:
HANDLE Handle; //父线程句柄
static DWORD TimeOutValue ; //连接超时时间,以ms计
static short ThreadCount; //当前正在扫描的进程数
static short Port; //端口
static char IP[256][16]; //局域网IP列表
static char Index[256]; //局域网活动服务器 是1 否0
static char send_str[5]; //发送数据缓存
static char recv_str[256][40]; //接收数据缓存
static int send_len;
static int recv_len;
static char RecvMsg[256][34]; //收到每个主机返回的信息 32 GSP 1 Num short MaxThread; //最大允许的扫描线程数,不宜大于200
char HostIP[16]; //本机IP
char IP3[16]; //IP前3段
}; 用c++搞过,但没有用java搞过
实现文件 .cpp
#include "LanHost.h" DWORD LanActiveHost::TimeOutValue ;
short LanActiveHost::ThreadCount ;
short LanActiveHost::Port ;
char LanActiveHost::IP[256][16] ;
char LanActiveHost::Index[256] ;
char LanActiveHost::send_str[5] ;
char LanActiveHost::recv_str[256][40] ;
int LanActiveHost::send_len ;
int LanActiveHost::recv_len ;
char LanActiveHost::RecvMsg[256][34]; //构造函数
LanActiveHost::LanActiveHost(short _MaxThread,short _Port,DWORD _TimeOutValue)
{
MaxThread = _MaxThread;
Port = _Port;
TimeOutValue = _TimeOutValue;
//配置数据协议
LanActiveHost::CFG_DP();
}
//析构函数
LanActiveHost::~LanActiveHost()
{
}
//获取本机IP地址
BOOL LanActiveHost::GetHostIP()
{
char HostName[128];
LPSTR Addr;
struct hostent FAR *HostEnt;
//获取主机名称 -1错误 0成功
if( gethostname(HostName, sizeof(HostName)) == SOCKET_ERROR )
return FALSE; //获取名称结构
HostEnt = gethostbyname (HostName); //主机名称可能有多个IP地址 在此默认第一个地址
Addr = HostEnt->h_addr_list[0]; //IP -> XXX.XXX.XXX.XXX
if (!Addr)
return FALSE;
else
{
struct in_addr inAddr;
memmove (&inAddr, Addr, 4);
strcpy(HostIP,inet_ntoa (inAddr));
}
return TRUE;
}
// 得到IP前3段 XXX.XXX.XXX.XXX -> XXX.XXX.XXX. ---------------------
BOOL LanActiveHost::GetIP3()
{
int i=0,j=0;
while(1)
{
IP3[i]=HostIP[i];
if(HostIP[i]=='.')
j++;
if(j==3)
break;
i++;
}
IP3[i+1]='\0';
return TRUE;
}
//初始化局域网 IP列表
BOOL LanActiveHost::InitIPList()
{
int i;
char IP4[4]; //获取本机IP
if( !LanActiveHost::GetHostIP() )
return FALSE;
//获取IP前三段
LanActiveHost::GetIP3(); //初始化局域网IP
for(i=1;i <=255;i++)
{
strcpy(IP[i],IP3);
itoa(i,IP4,10);
strcat(IP[i],IP4);
IP[i][strlen(IP[i])]='\0';
}
return TRUE;
} //配置网络数据协议
BOOL LanActiveHost::CFG_DP()
{
send_str[0] = 'A';
send_str[1] = 'M';
send_str[2] = CMSG_See;
send_str[3] = '\0';
send_len = 5;
recv_len = 40;
return TRUE;
} //检查接收内容是否正确
BOOL LanActiveHost::Chk_ServMsg(int id)
{
if( recv_str[id][0]=='A' && recv_str[id][1]=='M' && (unsigned char)recv_str[id][2]==SMSG_Server )
return TRUE;
else
return FALSE;
}
//设置接收信息记录
BOOL LanActiveHost::SetMsgRec(BOOL flag,int id)
{
if(flag==TRUE)
{
//记录
Index[id]=1;
DataCopy(recv_str[id]+3,RecvMsg[id],33);
RecvMsg[id][33]='\0';
}
else
{
//清零
Index[id]=0;
memset(RecvMsg[id],0,sizeof(RecvMsg[id]));
}
return TRUE;
}
//连接监听尝试3次 成功返回1 失败返回0
BOOL LanActiveHost::Try3_ConnSelect(fd_set r,struct timeval tm)
{
int num = 1; //尝试第一1次
int ret = select(0, NULL, &r, NULL, &tm); //若失败再尝试2次
while( ret <=0 && num <3 )
{
ret = select(0, NULL, &r, NULL, &tm);
num++;
} //返回结果
if( ret>0 )
return TRUE;
else
return FALSE;
} //发送监听尝试3次 成功返回1 失败返回0
BOOL LanActiveHost::Try3_SendSelect(fd_set r,struct timeval tm)
{
int num = 1; //尝试第一1次
int ret = select(0, NULL, &r, NULL, &tm); //若失败再尝试2次
while( ret <=0 && num <3 )
{
ret = select(0, NULL, &r, NULL, &tm);
num++;
} //返回结果
if( ret>0 )
return TRUE;
else
return FALSE;
} //接收监听尝试3次 成功返回1 失败返回0
BOOL LanActiveHost::Try3_RecvSelect(fd_set r,struct timeval tm)
{
int num = 1; //尝试第一1次
int ret = select(0, &r, NULL, NULL, &tm); //若失败再尝试2次
while( ret <=0 && num <3 )
{
ret = select(0, &r, NULL, NULL, &tm);
num++;
} //返回结果
if( ret>0 )
return TRUE;
else
return FALSE;
} //对外接口 提供接收的服务器信息
BOOL LanActiveHost::GetServerMSG(char Msg[256][34])
{
int i;
//Msg清零
memset(Msg,0,sizeof(Msg)); //如果是服务器 提交信息
for(i=1;i <=255;i++)
if(Index[i]==1)
DataCopy(RecvMsg[i],Msg[i],33);
return TRUE;
}
//扫描局域网存活主机 子线程函数
DWORD WINAPI LanActiveHost::DoScanPort(LPVOID lpParam)
{
int id = (int)lpParam; //创建套接字
SOCKET sock = socket(AF_INET, SOCK_STREAM, 0); //创建套接字失败
if(sock == INVALID_SOCKET)
{
ThreadCount --;
return 0;
} //创建套接字成功
else
{
//强制关闭,不经历TIME_WAIT过程
BOOL bDontLinger = FALSE;
setsockopt(sock,SOL_SOCKET,SO_DONTLINGER,(const char*)&bDontLinger,sizeof(BOOL));
//设置非阻塞socket
unsigned long flag = 1;
int ret = ioctlsocket(sock, FIONBIO, (unsigned long*)&flag); //设置失败
if( ret == SOCKET_ERROR )
{
ThreadCount --;
return 0;
} //主机地址
sockaddr_in Addr;
Addr.sin_family = AF_INET;
Addr.sin_port = htons(Port);
Addr.sin_addr.S_un.S_addr =inet_addr(IP[id]); //连接主机
connect(sock, (sockaddr*)&Addr, sizeof(Addr)); //超时设置
struct fd_set mask;
FD_ZERO(&mask);
FD_SET(sock, &mask);
struct timeval timeout;
timeout.tv_sec = TimeOutValue/1000; //秒
timeout.tv_usec = (TimeOutValue%1000)*1000; //微秒 //连接成功
if( LanActiveHost::Try3_ConnSelect(mask,timeout) == TRUE ) //监听发送
if( LanActiveHost::Try3_SendSelect(mask,timeout) == TRUE )
send(sock,send_str,send_len,0); strcpy(recv_str[id],"NULL\0"); //监听接收
if( LanActiveHost::Try3_RecvSelect(mask,timeout) == TRUE )
recv(sock,recv_str[id],recv_len,0); //接收内容正确
if( LanActiveHost::Chk_ServMsg(id) == TRUE )
LanActiveHost::SetMsgRec(TRUE,id);
else
LanActiveHost::SetMsgRec(FALSE,id);
//断开连接
shutdown(sock,0);
closesocket(sock);
sock = -1;
}
ThreadCount --;
return 1;
}
//扫描局域网存活主机 父线程函数
DWORD WINAPI LanActiveHost::StartScan(LPVOID lpParam)
{
DWORD ThreadId;
unsigned short i; for(i=1; i <=255; i++)
if (CreateThread(NULL, 0,LanActiveHost::DoScanPort, (LPVOID)i, 0, &ThreadId) != NULL)
ThreadCount ++; //等待所有子线程退出
while (ThreadCount > 0)
Sleep(20);
return 1;
}
//扫描局域网存活主机
BOOL LanActiveHost::StartListServer()
{
//初始化局域网 IP列表与索引
if( !LanActiveHost::InitIPList() )
return FALSE; //线程计数器初始化
ThreadCount = 0; //创建扫描父线程,该线程包含多个子线程
DWORD ThreadId;
Handle = CreateThread(NULL, 0,LanActiveHost::StartScan, NULL, 0, &ThreadId); //线程创建成功
if( Handle )
return TRUE; //线程创建失败
else
return FALSE;
}
//等待扫描线程安全退出
BOOL LanActiveHost::EndListServer()
{
//等待子线程退出
while( ThreadCount>0 )
Sleep(20);
//等待父线程退出
Sleep(100);
return TRUE;
}
//外部接口提供服务器IP列表 存活索引
BOOL LanActiveHost::Get_IPIndex(char ip_list[256][16],char ip_index[256])
{
int i;
for(i=1;i <=255;i++)
if(Index[i]==1)
{
strcpy(ip_list[i],IP[i]);
ip_index[i] = Index[i];
}
else
ip_index[i] = 0;
return TRUE;
}
主机端 应答
头文件
class LanServer
{
public:
//客户端最大15 最小1
LanServer(int _Port,int _Max_Client,int _TimeOut,int _HeartTimeOut);
~LanServer();
BOOL InitServer();
BOOL Listen(short blockbuf);
BOOL GetPlayer(int id);
static BOOL Try3_SendSelect(fd_set r,struct timeval tm);
static BOOL Try3_RecvSelect(fd_set r,struct timeval tm);
// BOOL ClientMSG_PRC(int id,char recv[],PLAYER_DATA player_data);
BOOL EndSock(int id);
static UINT ServerThread(LPVOID p);
static BOOL GetFreeSock(int &id,int &num);
private:
int Port;
int PlayerPos[16];
static int TimeOut;
static int HeartTimeOut;
static SOCKET Socket[17];
static sockaddr_in Addr;
static int AddrLen;
static int Max_Client;
}; 实现文件
//主机端
#include "Server.h" int LanServer::TimeOut;
int LanServer::HeartTimeOut;
int LanServer::Max_Client;
int LanServer::AddrLen=0;
SOCKET LanServer::Socket[17];
sockaddr_in LanServer::Addr; char StrGet[300];
//构造函数
LanServer::LanServer(int _Port,int _Max_Client,int _TimeOut,int _HeartTimeOut)
{
Port = _Port;
Max_Client = _Max_Client;
TimeOut = _TimeOut;
HeartTimeOut = _HeartTimeOut;
} //析构函数
LanServer::~LanServer()
{
LanServer::EndSock(-1);
} //初始化服务器 绑定端口
BOOL LanServer::InitServer()
{
int i; //所有套接字初始化
for (i=0;i <=Max_Client+1;i++)
Socket[i] = -1; //设定地址
Addr.sin_addr.s_addr= htonl(INADDR_ANY);
Addr.sin_family = AF_INET;
Addr.sin_port = htons(Port);
AddrLen = sizeof(Addr); //创建socket
Socket[0] =socket(AF_INET,SOCK_STREAM,0); //创建socket失败
if( Socket[0] == INVALID_SOCKET )
return FALSE; //强制关闭,不经历TIME_WAIT过程
BOOL bDontLinger = FALSE;
setsockopt(Socket[0],SOL_SOCKET,SO_DONTLINGER,(const char*)&bDontLinger,sizeof(BOOL));
//绑定成功
if ( bind(Socket[0],(sockaddr*)&Addr,sizeof(Addr)) ==0)
return TRUE; //绑定失败
else
return FALSE;
} //开始监听
BOOL LanServer::Listen(short blockbuf)
{
listen(Socket[0],blockbuf);
return TRUE;
} //获取空闲套接字
BOOL LanServer::GetFreeSock(int &id,int &num)
{
int i;
id = 0;
num = 0;
for(i=Max_Client+1;i>=1;i--)
if (Socket[i]==-1)
{
id = i;
num ++ ;
}
return TRUE;
}
//终止连接
BOOL LanServer::EndSock(int id)
{
int i; //非法操作
if(id <-1 || id>15)
return FALSE; //若索引为0-15 则终止该索引对应的套接字
if(id>=0 && Socket[id]!=-1)
{
closesocket(Socket[id]);
Socket[id]=-1;
} //若索引为 -1 则终止所有 套接字
else if(id==-1)
for(i=0;i <=Max_Client;i++)
{
closesocket(Socket[id]);
Socket[id]=-1;
} return TRUE;
} //尝试3次接收监听 成功返回1 失败返回0
BOOL LanServer::Try3_RecvSelect(fd_set r,struct timeval tm)
{
int num = 1; //尝试第一1次
int ret = select(0, &r, NULL, NULL, &tm); //若失败再尝试2次
while( ret <=0 && num <3 )
{
ret = select(0, &r, NULL, NULL, &tm);
num++;
} //返回结果
if( ret>0 )
return TRUE;
else
return FALSE;
} //尝试3次接收监听 成功返回1 失败返回0
BOOL LanServer::Try3_SendSelect(fd_set r,struct timeval tm)
{
int num = 1; //尝试第一1次
int ret = select(0, NULL, &r, NULL, &tm); //若失败再尝试2次
while( ret <=0 && num <3 )
{
ret = select(0, NULL, &r, NULL, &tm);
num++;
} //返回结果
if( ret>0 )
return TRUE;
else
return FALSE;
}
//服务器工作线程
UINT LanServer::ServerThread(LPVOID p)
{
int id,num; //获得客户端数量
LanServer::GetFreeSock(id,num); while( num==1 )
{
//终止线程
Sleep(20);
LanServer::GetFreeSock(id,num);
} //接受连接
Socket[id]=accept(Socket[0],(sockaddr*)&Addr,&AddrLen); //强制关闭,不经历TIME_WAIT过程
BOOL bDontLinger = FALSE;
setsockopt(Socket[id],SOL_SOCKET,SO_DONTLINGER,(const char*)&bDontLinger,sizeof(BOOL)); //开启新线程
AfxBeginThread(LanServer::ServerThread,0); CAMatchDlg *dlg= (CAMatchDlg *)AfxGetApp()->GetMainWnd(); if ( Socket[id]!=INVALID_SOCKET ) //连接正确
{
//设置非阻塞方式
unsigned long ul = 1;
ioctlsocket(Socket[id], FIONBIO, (unsigned long*)&ul); fd_set r;
FD_ZERO(&r);
FD_SET(Socket[id], &r); struct timeval tm;
tm.tv_sec = TimeOut/1000 ;
tm.tv_usec = (TimeOut%1000)*1000;
while(1)
{
//尝试3次接收监听
if( LanServer::Try3_RecvSelect(r,tm) == FALSE )
break; //接收数据
if( recv(Socket[id],StrGet,230,0) <=0 )
break; //处理接收数据
ClientMSG_Processing(id,msg_data.StrGet,client_data); //处理发送数据
int Ret = ClientMSG_Put(id, msg_data.StrGet, am_skin, client_data, am_game, msg_data.StrPut);
//发送数据
if( (Ret==2 || Ret==3) && LanServer::Try3_SendSelect(r,tm) == TRUE )
{
if( send(Socket[id], msg_data.StrPut, 50,0) <=0 )
send(Socket[id], msg_data.StrPut, 50,0);
}
//关闭套接字
if( Ret==0 || Ret==2 )
break;
}
}
closesocket(Socket[id]);
Socket[id]=-1;
::AfxMessageBox("服务器断开",0,0);
//终止线程
AfxEndThread(0);
return 0;
}
//处理客户端信息 TRUE 保持 FALSE 断开
BOOL LanServer::ClientMSG_PRC(int id,char recv[],PLAYER_DATA player_data,char Msg[])
{
//非法数据不处理
if( !(recv[0]=='A' && recv[1]=='M') )
return TRUE; //依据协议 为即将发送的数据 添加数据头
memset(Msg,0,sizeof(Msg));
Msg[0]='A';
Msg[1]='M'; //获取消息类型
int MSG_ID = (unsigned char)recv[2]; //依据类型处理
switch( MSG_ID )
{
//查询服务器信息
case CMSG_See:
{
Msg[2] = SMSG_Server;
DataCopy(player_data.GSP,Msg+3,32);
int i,num=0;
for(i=0;i <16;i++)
if( client_data.Flag[i] )
num++;
Msg[35] = num;
Msg[36] = '\0';
return TRUE;
}
//申请加入服务器
case CMSG_Ask:
{
//拷贝玩家名称
char sname[17];
DataCopy(recv+3,sname,16); //增加玩家信息
AddPlayer(id, sname, player_data.Live, player_data.Flag, player_data.Name[id]);
return TRUE;
}
//准备完毕 等待开始
case CMSG_Ready:
{
//拷贝初始化棋盘数据
DataCopy(recv+3, player_data.Init[id], 216);
return TRUE;
} //游戏进度
case CMSG_Game:
{
//数据包次序
int PackID = (unsigned char)recv[3]; //对比次序 判断是否丢失严重 100 210 321 432 543
if( PackID - (unsigned char)palyer_data.PID[id] >= 3 )
return FALSE; //更新数据包次序
palyer_data.PID[id] = PackID; //拷贝销毁点 与 交换点
DataCopy(recv+4, player_data.SP[id], 3);
DataCopy(recv+7, player_data.EP[id], 3);
return TRUE;
}
//离开游戏
case CMSG_Leave:
{
//删除玩家信息
DeletePlayer(id, player_data.Live, player_data.Flag, player_data.Name[id]);
return FALSE;
} //保持信号
case CMSG_Keep:
{
//心跳包计数器 增加
player_data.Signal[id] ++;
return TRUE;
} //默认不处理
default :
return TRUE;
}
}