用c#编写一个dhcp服务
一、DHCP是什么?
DHCP(Dynamic Host Configuration Protocol,动态主机配置协议)通常被应用在大型的局域网络环境中,主要作用是集中的管理、分配IP地址,使网络环境中的主机动态的获得IP地址、Gateway地址、DNS服务器地址等信息,并能够提升地址的使用率。
说白了,每台网络设备想要上网必须要有ip地址,但是现在的互联网ip4地址资源有限,无法让这么多的设备没人一个互联网地址,于是路由器就出现了,路由器的作用就是将局域网的数据包转发到广域网上,使局域网内机器也能访问互联网,局域网可使用的网段(私网地址段)有三大段:
10.0.0.0~10.255.255.255(A类)
172.16.0.0~172.31.255.255(B类)
192.168.0.0~192.168.255.255(C类)
机器地址的获取可以通过dhcp进行分配,以免出现同一个地址被多台设备使用的情况
那么今天我们来用c#实现一个小型的dhcp服务器
二、c#编写dhcp
客户机与dhcp服务器之间的报文交换可以看上图
1、客户机发送dhcp discovery报文
2、dhcp接收到报文后发送dhcp offer报文
3、客户机收到后发送请求报文
4、dhcp发送确认报文(包含分配的ip地址)
5、客户机如果释放ip地址也会发送一个释放报文给dhcp
dhcp默认使用UDP进行报文传输,报文的格式如下
下面我来用c#编写一个dhcp服务器
原理很简单,就是创建一个UDPclient,监听67,68端口,进行报文的发送与接收
#region Copyright Information /* * (C) 2005-2007, Marcello Cauchi Savona * * For terms and usage, please see the LICENSE file * provided alongwith or contact marcello_c@hotmail.com * http://www.cheekyneedle.com * * */ #endregion /* * clsUDP * shall start a listner, and raise an event every time data arrives on a port * shall also be able to send data via udp protocol * .Dispose shall remove all resources associated with the class */ using System; using System.Collections.Generic; using System.Text; using System.Net; using System.Net.Sockets; using System.IO; using System.Threading; using Microsoft.Win32; namespace SmallDHCPServer_C { class clsUDP { #region "Class Variables" private Int32 PortToListenTo, PortToSendTo = 0; private string rcvCardIP; public bool IsListening; // call backs for send/recieve! public UdpState s; #endregion #region "Class Events" public delegate void DataRcvdEventHandler(byte[] DData, IPEndPoint RIpEndPoint); public event DataRcvdEventHandler DataRcvd; public delegate void ErrEventHandler(string Msg); #endregion //class constructors public clsUDP() { IsListening = false; } //overrides pass the port to listen to/sendto and startup public clsUDP(Int32 PortToListenTo,Int32 PortToSendTo, string rcvCardIP) { try { IsListening = false; this.PortToListenTo = PortToListenTo; this.PortToSendTo = PortToSendTo; this.rcvCardIP = rcvCardIP; StartListener(); } catch(Exception ex) { Console.WriteLine (ex.Message); } } //string property to contain the class name private string ClassName { get {return "clsUDP"; } } //function to send data as a byte stream to a remote socket // modified to work as a callback rather than a block public void SendData(byte[] Data) { try { s.u.BeginSend(Data, Data.Length, "255.255.255.255", PortToSendTo, new AsyncCallback(OnDataSent), s); //s.u.Send(Data, Data.Length, "255.255.255.255", PortToSendTo); } catch (Exception ex) { Console.WriteLine(ex.Message); } } // This is the call back function, which will be invoked when a client is connected public void OnDataSent(IAsyncResult asyn) { try { //get the data UdpClient ii = (UdpClient)asyn; ii.EndSend(asyn); // stop the send call back } catch (Exception ex) { if (IsListening == true) Console.WriteLine(ex.Message); } } //function to start the listener call back everytime something is recieved private void IniListnerCallBack() { try { // start teh recieve call back method s.u.BeginReceive(new AsyncCallback(OnDataRecieved), s); } catch (Exception ex) { if (IsListening == true) Console.WriteLine(ex.Message); } } // This is the call back function, which will be invoked when a client is connected public void OnDataRecieved(IAsyncResult asyn) { Byte[] receiveBytes; UdpClient u; IPEndPoint e; try { u = (UdpClient)((UdpState)(asyn.AsyncState)).u; e = (IPEndPoint)((UdpState)(asyn.AsyncState)).e; receiveBytes = u.EndReceive(asyn, ref e); //raise the event with the data recieved DataRcvd(receiveBytes, e); } catch (Exception ex) { if (IsListening == true) Console.WriteLine(ex.Message); } finally { u = null; e = null; receiveBytes = null; // recall the call back IniListnerCallBack(); } } //function to start the listener //if the the listner is active, destroy it and restart // shall mark the flag that the listner is active private void StartListener() { // byte[] receiveBytes; // array of bytes where we shall store the data recieved IPAddress ipAddress; IPEndPoint ipLocalEndPoint; try { IsListening = false; //resolve the net card ip address ipAddress = IPAddress.Parse(rcvCardIP); //get the ipEndPoint ipLocalEndPoint = new IPEndPoint(ipAddress, PortToListenTo); // if the udpclient interface is active destroy if (s.u != null) s.u.Close(); s.u = null; s.e = null; //re initialise the udp client s = new UdpState(); s.e = ipLocalEndPoint; s.u = new UdpClient(ipLocalEndPoint); IsListening = true; // set to start listening // wait for data IniListnerCallBack(); } catch (Exception ex) { if (IsListening == true) Console.WriteLine(ex.Message); } finally { if (s.u == null) { Thread.Sleep(1000); StartListener(); } else { ipAddress = null; ipLocalEndPoint = null; } } } //stop the listener thread public void StopListener() { try { IsListening = false; if (s.u != null) s.u.Close(); s.u = null; s.e = null; } catch (Exception ex) { Console.WriteLine(ex.Message); } } //dispose of all resources ~clsUDP() { try { StopListener(); if (s.u != null) s.u.Close(); s.u = null; s.e = null; rcvCardIP = null; } catch (Exception ex) { Console.WriteLine(ex.Message); } } //class that shall hold the reference of the call backs public struct UdpState { public IPEndPoint e; //define an end point public UdpClient u; //define a client } } }
完整的项目示例可以下载
一、源码下载
网友评论0