这段时间一直在学习C#, 以前一直搞网络的,还是从Ping程序的实现写起吧.
ping的调用方法如下:
Ping mPing=new Ping();
mPing.Pinging(“127.0.0.1“,255,65535);
mPing.Receive(); //成功接收返回true,timeout 返回false
全部源代码如下:
using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
namespace Ping
{
///
/// Summary description for Ping.
///
///
//
//
//IP Header
public class IPHDR
{
public byte VIHL
{
get{return mVIHL;}
set{mVIHL=value;}
}private byte mVIHL;
public byte TOS
{
get{return mTOS;}
set{mTOS=value;}
}private byte mTOS;
public short TotLen
{
get{return mTotLen;}
set{mTotLen=value;}
}private short mTotLen;
public short ID
{
get{return mID;}
set{mID=value;}
}private short mID;
public short FlagOff
{
get{return mFlagOff;}
set{mFlagOff=value;}
}private short mFlagOff;
public byte TTL
{
get{return mTTL;}
set{mTTL=value;}
}private byte mTTL;
public byte Protocol
{
get{return mProtocol;}
set{mProtocol=value;}
}private byte mProtocol;
public ushort Checksum
{
get{return mChecksum;}
set{mChecksum = value;}
}private ushort mChecksum;
public ulong iaSrc
{
get{return miaSrc;}
set{miaSrc=../../value;}
}private ulong miaSrc;
public ulong iaDst
{
get{return miaDst;}
set{miaDst=value;}
}private ulong miaDst;
public static string Address(ulong obj)
{
byte s1=(byte)obj;
byte s2=(byte)(obj>>8);
byte s3=(byte)(obj>>16);
byte s4=(byte)(obj>>24);
return String.Format("{0}.{1}.{2}.{3}",s1,s2,s3,s4);//s1+"."+s2+"."+s3+"."+s4;
}
public void Encode(BinaryWriter writer)
{
writer.Write(VIHL);
writer.Write(TOS);
writer.Write((Int16)TotLen);
writer.Write((Int16)ID);
writer.Write((Int16)FlagOff);
writer.Write(TTL);
writer.Write(Protocol);
writer.Write((UInt16)Checksum);
writer.Write((UInt32)iaSrc);
writer.Write((UInt32)iaDst);
}
public void Decode(BinaryReader reader)
{
VIHL=reader.ReadByte();
TOS=reader.ReadByte();
TotLen=reader.ReadInt16();
ID=reader.ReadInt16();
FlagOff=reader.ReadInt16();
TTL=reader.ReadByte();
Protocol=reader.ReadByte();
Checksum=reader.ReadUInt16();
iaSrc=../../reader.ReadUInt32();
iaDst=reader.ReadUInt32();
}
}
//ICMP Header;
public class ICMPHDR
{
public byte Type
{
get{return mType;}
set{mType=value;}
}private byte mType;
public byte Code
{
get{return mCode;}
set{mCode=value;}
}private byte mCode=0;
public ushort Checksum
{
get{return mChecksum;}
set{mChecksum=value;}
}private ushort mChecksum=0;
public ushort ID
{
get{return mID;}
set{mID=value;}
}private ushort mID;
public ushort Seq
{
get{return mSeq;}
set{mSeq=value;}
}private ushort mSeq;
public ulong tmSend
{
get{return mtmSend;}
set{mtmSend=value;}
}private ulong mtmSend;
public int nTaskId
{
get{return mnTaskId;}
set{mnTaskId=value;}
}private int mnTaskId;
public void Encode(BinaryWriter writer)
{
writer.Write(Type);
writer.Write(Code);
writer.Write((UInt16)Checksum);
writer.Write((UInt16)ID);
writer.Write((UInt16)Seq);
writer.Write((UInt32)tmSend);
writer.Write(nTaskId);
}
public void Decode(BinaryReader reader)
{
Type=reader.ReadByte();
Code=reader.ReadByte();
Checksum=reader.ReadUInt16();
ID=reader.ReadUInt16();
Seq=reader.ReadUInt16();
tmSend=reader.ReadUInt32();
nTaskId=reader.ReadInt32();
}
public uint Sum()
{
uint sum=0;
sum +=(ushort)(Type+(Code<<8));
sum +=(ushort)ID;
sum +=(ushort)Seq;
sum +=(ushort)tmSend;
sum +=(ushort)(tmSend>>16);
sum +=(ushort)nTaskId;
sum +=(ushort)(nTaskId>>16);
return sum;
}
}
public class ECHOREQUEST
{
private char[] mChar;
public ICMPHDR icmp=new ICMPHDR();
public ECHOREQUEST(int size,char nChar)
{
mChar=new Char[size];
for(int i=0;i mChar[i]=nChar; } public void Encode(BinaryWriter writer) { chksum(); icmp.Encode(writer); writer.Write(mChar); } /* public void Decode(BinaryReader reader) { icmp.Decode(reader); string s=reader.ReadString(); mChar=s.ToCharArray(); } */ private void chksum() { uint sum=icmp.Sum(); for(int i=0;i sum +=(ushort)(mChar[i]+(mChar[i+1]<<8)); // sum = (sum >> 16) + (sum & 0xffff); // add hi 16 to low 16 sum += (sum >> 16); // add carry short answer = (short)~sum; // truncate to 16 bits icmp.Checksum=(ushort)answer; } } //ICMP Echo Reply public class ECHOREPLY { public IPHDR ipHdr=null; public ICMPHDR icmpHdr=null; public char[] cFiller; public void Decode(BinaryReader reader) { ipHdr=new IPHDR(); ipHdr.Decode(reader); icmpHdr=new ICMPHDR(); icmpHdr.Decode(reader); int bytes=(int)reader.BaseStream.Length; // cFiller=reader.ReadChars(8); cFiller=reader.ReadChars(bytes-36); } } public class StateObject { public Socket workSocket = null; // Client socket. public const int BufferSize = 256; // Size of receive buffer. public byte[] buffer = new byte[BufferSize]; // Receive buffer. // public StringBuilder sb = new StringBuilder();// Received data string. } public class Ping { Socket socket=null; int m_id; uint m_taskid; uint m_seq; System.Threading.ManualResetEvent recvDone=null; DateTime m_dtSend; public Ping() { m_seq=0; recvDone=new System.Threading.ManualResetEvent(false); socket=new Socket(AddressFamily.InterNetwork,SocketType.Raw,ProtocolType.Icmp); // // TODO: Add constructor logic here // } public bool Pinging(string addr,int id, uint taskid) { try { m_id=id; m_taskid=taskid; Byte[] byReq =FillEchoReq(); //send to IPEndPoint lep = new IPEndPoint(IPAddress.Parse(addr), 0); socket.SendTo(byReq,lep); } catch(Exception e) { Console.WriteLine("Send error:"+e.ToString()); return false; } return true; } private Byte[] FillEchoReq() { m_seq++; if(m_seq>1000) m_seq=1; ECHOREQUEST req=new ECHOREQUEST(8,'E'); req.icmp.Type=8; req.icmp.Code=0; req.icmp.ID=(ushort)m_id; req.icmp.Seq=(ushort)m_seq; req.icmp.nTaskId=(int)m_taskid; m_dtSend=DateTime.Now; req.icmp.tmSend=(ulong)DateTime.Now.Ticks; MemoryStream stream=new MemoryStream(); BinaryWriter writer=new BinaryWriter(stream); req.Encode(writer); int toReads=(int)stream.Length; //get Byte array. Byte[] byReq=stream.ToArray(); stream.Close(); return byReq; } private static uint iocntlCheck(Socket s) { // Set up the input and output byte arrays. byte[] inValue = BitConverter.GetBytes(0); byte[] outValue = BitConverter.GetBytes(0); // Check how many bytes have been received. s.IOControl(0x4004667F, inValue, outValue); uint bytesAvail = BitConverter.ToUInt32(outValue, 0); return bytesAvail; } //used to check reply data by sync public bool checkReply() { uint byAvail=iocntlCheck(socket); if(byAvail<=0) return false; try { Byte[] recv=new Byte[byAvail]; socket.Receive(recv); return checkEchoReply(recv,(int)byAvail); } catch(Exception e) { Console.WriteLine(e.ToString()); return false; } } //Directly analyze the byte array. public bool checkEchoReply1(Byte[] recv,int len) { if(len<36) return false; int ttl=recv[8]; string src=../../recv[12]+"."+recv[13]+"."+recv[14]+"."+recv[15]; string dst=recv[16]+"."+recv[17]+"."+recv[18]+"."+recv[19]; int type=recv[20]; if(type !=0) return false; //24,25, id int id=recv[24]+(recv[25]<<8); if(id !=m_id) return false; //26,27, seq int seq=recv[26]+(recv[27]<<8); //32,33,34,35, task id int taskid=recv[32]+(recv[33]<<8)+(recv[34]<<16)+(recv[35]<<24); if(taskid !=m_taskid) return false; int bytes= len-36; TimeSpan ts=DateTime.Now-m_dtSend; Console.WriteLine("Reply from {0}: bytes={1},icmp_seq={2},TTL={3},time={4} ms", src,bytes,seq,ttl ,ts.Milliseconds ); return true; } //use IPHDR, ICMPHDR to analyze replyk data. public bool checkEchoReply(Byte[] recv,int len) { //20bytes ip pack. if(len<36) return false; MemoryStream stream=new MemoryStream(recv,0,len,false); BinaryReader reader=new BinaryReader(stream); ECHOREPLY reply=new ECHOREPLY(); reply.Decode(reader); stream.Close(); string dst,src; dst=IPHDR.Address(reply.ipHdr.iaDst); src=../../IPHDR.Address(reply.ipHdr.iaSrc); //type byte type=reply.icmpHdr.Type; //24,25 id int id=reply.icmpHdr.ID; //26,27,seq int seq=reply.icmpHdr.Seq ; // int bytes= len-36; //32,33,34,35, task id DateTime dt=new DateTime((long)reply.icmpHdr.tmSend); // Consdt.ToString(); uint taskid=(uint)reply.icmpHdr.nTaskId;//(uint)(recv[32]+(recv[33]<<8)+(recv[34]<<16)+(recv[35]<<24)); TimeSpan ts=DateTime.Now -m_dtSend;//dt; if(type == 0 && id == m_id && m_taskid==taskid) { Console.WriteLine("Reply from {0}: bytes={1},icmp_seq={2},TTL={3},time={4} ms", src,bytes,seq,reply.ipHdr.TTL ,ts.Milliseconds ); return true; } else { // Console.WriteLine("Unknown data,{0},{1},type={2},icmp_seq={3}", // src,dst,type,seq); } return false; } public bool Receive() { try { recvDone.Reset(); StateObject so=new StateObject(); so.workSocket=socket; // socket.SetSocketOption(SocketOptionLevel.Socket,SocketOptionName.ReceiveTimeout,5000); IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0); EndPoint tempRemoteEP = (EndPoint)sender; socket.BeginReceiveFrom(so.buffer,0,StateObject.BufferSize,0,ref tempRemoteEP,new AsyncCallback(receiveCallBack),so); if(!recvDone.WaitOne())//.WaitOne(1000,false)) {//receive timeout Console.WriteLine("Request timed out"); return false; } } catch(Exception e) { Console.WriteLine("Fail,{0}",e.ToString()); return false; } return true; } public void receiveCallBack(IAsyncResult ar) { try { StateObject obj=(StateObject)ar.AsyncState; Socket sock=obj.workSocket; IPEndPoint ep=new IPEndPoint(IPAddress.Any,0); EndPoint tempEP=(EndPoint)ep; int recvs=sock.EndReceiveFrom(ar,ref tempEP); if(checkEchoReply(obj.buffer,recvs)) recvDone.Set(); else sock.BeginReceiveFrom(obj.buffer,0,StateObject.BufferSize,0,ref tempEP,new AsyncCallback(receiveCallBack),obj); // Console.WriteLine("Address:{0}",((IPEndPoint)tempEP).Address); } catch(Exception e) { Console.WriteLine("CallBack Error:"+e.ToString()); } } public void clear() { socket.Close(); } } }

