这段时间一直在学习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>
/// summary description for ping.
/// </summary>
///
//
//
//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<size;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<mchar.length;i+=2)
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();
}
}
}