015_实验室计算机的IP地址自动设置程序—服务器端
1.无需注册登录,支付后按照提示操作即可获取该资料.
2.资料以网页介绍的为准,下载后不会有水印.资料仅供学习参考之用.
密 惠 保
3.1 总体设计
3.1.1 系统结构设计
系统的主要功能需求为:配置分配的IP地址范围,接收客户端的请求,处理请求为客户端分配IP地址,将应答信息发送给客户端。
根据系统需求可以将系统划分为以下主要模块。
模块名称:配置系统信息
功能描述:配置服务器为客户端分配的IP地址范围,服务器保留的IP地址,网关,子网掩码等信息。
实现方式: 服务器并不是每次启动都需要配置IP信息,配置模块在单独的进程中实现。有对话框界面进行人机交互,将配置信息保存到系统盘的Windows目录下的一个配置文件中,主程序运行时从配置文件中读取配置信息。
模块名称:接收请求
功能描述:接收网络发送来的请求包,验证请求包的正确性和完整性,并将请求信息保存。
实现方式: 功能在单独的线程中实现。虽然客户端与服务器物理上在一个局域网内,但并不能保证逻辑上在一个网段内,所以客户端不知道服务器所在。为了使客户端发出的请求服务器能够正确接收,客户端采用数据链路层广播的方式发送请求。收到客户端请求后,通过验证包头信息判断请求包的正确性,将请求信息写入请求队列,没有请求到达线程在接收请求处阻塞。网络请求的接收采用Windows套接字编程实现。互斥资源的访问采用信号量机制。 【买计算机毕业论文就到计算机毕业论文网】 think58
模块名称:处理请求
功能描述:从请求队列中读取请求信息,根据请求信息为客户端分配IP地址,将应答信息写入发送队列。
实现方式:功能在单独的线程中实现。从配置文件中读取配置信息,判断管理员是否重新配置过,如果重新配置过则清空数据库记录。从请求队列中读取请求信息,判断是一次请求还是二次请求。一次请求,从数据库中根据网卡地址查找分配给其的IP地址,找到则把分配的IP地址写入发送队列,找不到则将最小的IP地址分配给其并写入数据库和发送队列,最小IP地址向上递增。二次请求,将最大IP地址分配给其但不写入数据库,写入发送队列,最大IP地址递减。互斥资源的访问采用信号量机制。
模块名称:发送应答
功能描述:从发送队列中读取应答信息,将子网掩码,网关等信息封装为应答包,发送给客户端。
实现方式:功能在单独的线程中实现。从配置文件中读取分配的子网掩码和网关。从发送队列中读取客户端的IP地址和分配给其的IP地址。因为不确定客户端和服务器是否在同一网段,所以还是采用广播的方式发送应答信息包。将子网掩码和网关封装进应答包以广播的形式发送出去。网络应答的发送采用Windows套接字编程实现,互斥资源的访问采用信号量机制。
系统的结构如图: 本文来自think58 [资料来源:www.THINK58.com]
图1 系统模块结构 copyright think58 [资料来源:http://www.THINK58.com]
copyright think58
[来源:http://www.think58.com]
3.1.2 通信协议
客户端和服务器都不知道彼此的网络配置信息,网络通信采用数据链路层广播的形式,请求包和应答包均可到达目的地。
网络通信协议定义如下:
一次请求包:
包头(reqip:)+包体(网卡地址:计算机名)
二次请求包:
包头(REQIP:)+包体(网卡地址:计算机名)
应答包:
包头(repip:)+包体(客户端原IP地址:分配给客户端的IP地址:子网掩码:网关)
3.1.3 数据库设计
系统数据库只记录客户端的网卡地址、分配给客户端的IP地址和客户端的计算机名。数据库设计如下:
数据库名称:IpAddr
表名:IPaddress
表1 数据库表结构
字段名称 数据类型 说明
mac 文本 网卡地址
ip 文本 ip地址
pcname 文本 计算机名
3.2 编码实现
3.2.1 配置模块
配置模块的主要功能是配置为客户端分配的IP地址范围、保留的IP地址、子网掩码和网关。
模块流程图如下: [版权所有:http://think58.com]
think58
图2 配置模块流程图
主要实现代码为:
//得到用户输入信息
m_maxIp.GetWindowText(maxIp);
m_minIp.GetWindowText(minIp);
m_netmask.GetWindowText(netMask);
m_netgate.GetWindowText(netGate);
//判定用户输入的合法性
if(maxIp.IsEmpty()||minIp.IsEmpty())
{
MessageBox("输入的ip地址范围不能为空");
return;
}
if(netMask.IsEmpty()||netGate.IsEmpty())
{
MessageBox("子网掩码或网关不能为空!");
return;
}
if(!cmpIPaddr((char*)(LPCTSTR)minIp,(char*)(LPCTSTR)maxIp))
{
MessageBox("地址段范围不合法!");
return;
}
//将配置信息写入配置文件
WritePrivateProfileString("FLAG","flag","true","IPaddrSer.ini");//写修改标志位
WritePrivateProfileString("MAXIP","maxip",maxIp,"IPaddrSer.ini");//写最大IP地址
WritePrivateProfileString("MINIP","minip",minIp,"IPaddrSer.ini");//写最小IP地址 think58好,好think58 [资料来源:http://THINK58.com]
WritePrivateProfileString("DISABLEIP",NULL,NULL,"IPaddrSer.ini");//清空保留IP地址
//重写保留IP地址
maxDisIpNo=m_disip.GetCount();
while(item<maxDisIpNo)
{
m_disip.GetText(item,disIp);
WritePrivateProfileString("DISABLEIP",disIp,"0","IPaddrSer.ini");
item++;
}
WritePrivateProfileString("NETMASK","netmask",netMask,"IPaddrSer.ini");//子网掩码
WritePrivateProfileString("NETGATE","netgate",netGate,"IPaddrSer.ini");//写网关
Return true;
} 本文来自think58
[资料来源:http://THINK58.com]
think58.com [来源:http://think58.com]
3.2.2 接收请求模块
接收请求模块的主要功能是监听网络上的广播请求,验证请求包的正确性,将请求信息写入请求队列。
模块流程图如下:
图3 接受请求模块流程图 think58好,好think58
主要实现代码:
if((nbSize=recvfrom(sockListener,buf,sizeof(buf),0,(SOCKADDR FAR *)&saClient,&nSize))==SOCKET_ERROR) //没有数据到达,线程将在此处阻塞
{
MessageBox(NULL,"receive package fail!","Error!",MB_OK);
Log.WriteLog("receive package fail!");
continue;
}
char temp[6];//用于提取包头
memcpy(temp,buf,5);
temp[5]=0;
if(strcmp(temp,(char*)(LPCTSTR)PakHead)==0)//为第一次请求包
{
//请求信息写入结点
memcpy(&pak,buf,npak);
memcpy(addr.mac,pak.macaddr,12);
addr.mac[12]=0;
strcpy(addr.pcname,pak.body);
strcpy(addr.ip,inet_ntoa(saClient.sin_addr));
CString macaddr="receive a request, the Macaddress is ";
CString s=addr.mac;
macaddr=macaddr+s;
Log.WriteLog((char*)(LPCTSTR)macaddr);//写日志
if(Write()==false)//将请求信息存放在结点后写入请求队列
{
MessageBox(NULL,"write to queue fail!","Error!",MB_OK); [资料来源:http://THINK58.com]
Log.WriteLog("write to queue fail!");
}
recptr->AddString(macaddr); //控件上显示请求信息
}
if(strcmp(temp,"REQIP")==0)//二次请求包
{
//请求信息写入结点
memcpy(&pak,buf,npak);
strcpy(addr.mac,"0");
strcpy(addr.pcname,pak.body);
strcpy(addr.ip,inet_ntoa(saClient.sin_addr));
CString macaddr="warning ! receive a request, the Macaddress is ";
CString s=pak.macaddr;
macaddr=macaddr+s;
Log.WriteLog((char*)(LPCTSTR)macaddr);
if(Write()==false)//将请求信息写入队列
{
MessageBox(NULL,"write to queue fail!","Error!",MB_OK);
Log.WriteLog("write to queue fail!");
}
recptr->AddString(macaddr); //控件上显示请求信息
3.2.3 处理请求模块
处理模块请求主要功能是为客户端分配对应的IP地址,通过查询数据库为客户端分配固定的IP地址。
模块流程图如下: think58好,好think58 [版权所有:http://think58.com]
图4 处理请求模块流程图
主要实现代码如下:
GetPrivateProfileString("FLAG","flag","000",flag,sizeof(flag),"IPaddrSer.ini");//读取修改标志位
if(strcmp(flag,"true")==0)//判断管理员是否重新配置过
{
if(!DeleteAll())//清空数据库记录
{
MessageBox(NULL,"delete DB record fail ","Error!",MB_OK);
Log.WriteLog("delete DB record fail ");
return false;
}
WritePrivateProfileString("FLAG","flag","false","IPaddrSer.ini");//写入flag标志为false
}
GetPrivateProfileString("MAXIP","maxip","0",MaxIp,sizeof(MaxIp),"IPaddrSer.ini");//初始化最大ip地址
GetPrivateProfileString("MINIP","minip","0",MinIp,sizeof(MinIp),"IPaddrSer.ini");//初始化最小ip地址
while(threadFlag)
{
if(Read()==false)//请求队列为空
{
Sleep(100); think58好,好think58 [资料来源:www.THINK58.com]
continue;
}
if(strcmp(req.mac,"0"))//一次请求包
{
mac=req.mac;
strcpy(rep.ipsend,req.ip);
if(Search(mac,ip))//根据网卡地址数据库中查找ip地址并找到
{
strcpy(rep.ipallot,(char*)(LPCTSTR)ip);
if(!Write())//将应答信息写入发送队列
{
MessageBox(NULL,"Fail to write ipaddress to the queue! ","Error!",MB_OK);
Log.WriteLog("Fail to write ipaddress to the queue! ");
continue;
}
}
else//没有找到要分配的ip地址
{
if(ipcmp(MinIp,MaxIp)==0)//判断是否有剩余的ip地址分配
{
MessageBox(NULL,"ipaddress is not enough! ","Error!",MB_OK);
Log.WriteLog("ipaddress is not enough! ");
continue;
}
else
{
strcpy(rep.ipallot,MinIp);//将最小ip分配
if(!Write())//应答信息写入发送队列
{
MessageBox(NULL,"Fail to write ipaddress to the queue! ","Error!",MB_OK);
Log.WriteLog("Fail to write ipaddress to the queue! "); 本文来自think58 [资料来源:http://THINK58.com]
continue;
}
if(!AddRecord(mac,MinIp,req.pcname))//记录分配结果以备下次查询时分配相同的ip
{
MessageBox(NULL,"add ip fail","Error",MB_OK);
Log.WriteLog("add ip fail");
}
if(AddMinIP(MinIp)==false)//最小ip增加
{
MessageBox(NULL,"ipaddress is not enough! ","Error!",MB_OK);
Log.WriteLog("ipaddress is not enough! ");
continue;
}
WritePrivateProfileString("MINIP","minip",MinIp,"IPaddrSer.ini");//最小ip写入配置文件
}
}
}
else//如果是二次请求
{
strcpy(rep.ipallot,MaxIp);//分配给最大ip
if(!Write())
{
MessageBox(NULL,"Fail to write ipaddress to the queue! ","Error!",MB_OK);
Log.WriteLog("Fail to write ipaddress to the queue! ");
continue;
}
SubMaxip(MaxIp,MinIp);//最大ip减小并不记录进配置文件
}
copyright think58