C#如何使用GetTcpTable API获取TCP/IP连接信息

  • Post author:
  • Post category:其他


来自:http://blog.csdn.net/yulinlover/article/details/3868824


C#中如何使用GetTcpTable API函数来取得本机的连接信息




代码已经加了详细注释,我想有需要的同志一定会看得明白了


public class NativeFunc
{
    [StructLayout(LayoutKind.Sequential)]
    public class MIB_TCPROW
    {
        public int dwState;
        public int dwLocalAddr;
        public int dwLocalPort;
        public int dwRemoteAddr;
        public int dwRemotePort;
    }

    [StructLayout(LayoutKind.Sequential)]
    public class MIB_TCPTABLE
    {
        public int dwNumEntries;
        public MIB_TCPROW[] table;
    }

    [DllImport("Iphlpapi.dll")]
    static extern int GetTcpTable(IntPtr pTcpTable, ref int pdwSize, bool bOrder);

    [DllImport("Iphlpapi.dll")]
    static extern int SendARP(Int32 DestIP, Int32 SrcIP, ref Int64 MacAddr, ref Int32 PhyAddrLen);

    [DllImport("Ws2_32.dll")]
    static extern Int32 inet_addr(string ipaddr);

    [DllImport("Ws2_32.dll")]
    static extern ushort ntohs(ushort netshort);

    //SendArp获取MAC地址
    public static string GetMacAddress(string macip)
    {
        StringBuilder strReturn = new StringBuilder();
        try
        {
            Int32 remote = inet_addr(macip);

            Int64 macinfo = new Int64();
            Int32 length = 6;
            SendARP(remote, 0, ref macinfo, ref length);

            string temp = System.Convert.ToString(macinfo, 16).PadLeft(12, '0').ToUpper();

            int x = 12;
            for (int i = 0; i < 6; i++)
            {
                if (i == 5) { strReturn.Append(temp.Substring(x - 2, 2)); }
                else { strReturn.Append(temp.Substring(x - 2, 2) + ":"); }
                x -= 2;
            }

            return strReturn.ToString();
        }
        catch
        {
            return string.Empty;
        }
    }

    public static bool IsHostAlive(string strHostIP)
    {
        string strHostMac = GetMacAddress(strHostIP);
        return !string.IsNullOrEmpty(strHostMac);
    }

    public static MIB_TCPTABLE GetTcpTableInfo()
    {
        //声明一个指针准备接受Tcp连接信息
        IntPtr hTcpTableData = IntPtr.Zero;

        //声明hTcpTableData指针所指向的内存缓冲区大小
        int iBufferSize = 0;

        //声明MIB_TCPTABLE对象,作为返回值
        MIB_TCPTABLE tcpTable = new MIB_TCPTABLE();
        
        //声明一个List对象来临时存放MIB_TCPROW对象
        List<MIB_TCPROW> lstTcpRows = new List<MIB_TCPROW>();
        
        //调用API来获得真正的缓冲区大小,iBufferSize默认为0,
        //这时调用API GetTcpTable会触发一个异常ERROR_INSUFFICIENT_BUFFER
        //通过这个异常系统会把真正的缓冲长度返回
        GetTcpTable(hTcpTableData, ref iBufferSize, false);

        //为托管指针在堆上分配内存
        hTcpTableData = Marshal.AllocHGlobal(iBufferSize);

        //求得MIB_TCPROW对象的内存字节数
        int iTcpRowLen = Marshal.SizeOf(typeof(MIB_TCPROW));

        //根据上面得到的缓冲区大小来推算MIB_TCPTABLE里的MIB_TCPROW数组长度
        //下面用缓冲长度-sizeof(int)也就是去掉MIB_TCPTABLE里的成员dwNumEntries所占用的内存字节数
        int aryTcpRowLength = (int)Math.Ceiling((double)(iBufferSize - sizeof(int)) / iTcpRowLen);

        //重新取得TcpTable的数据
        GetTcpTable(hTcpTableData, ref iBufferSize, false);

        //下面是关键,由于MIB_TCPTABLE里的成员有一个是数组,而这个数组长度起初我们是不能确定的
        //所以这里我们只能根据分配的指针来进行一些运算来推算出我们所要的数据
        for (int i = 0; i < aryTcpRowLength; i++)
        {
            //hTcpTableData是指向MIB_TCPTABLE缓冲区的内存起始区域,由于其成员数据在内存中是顺序排列
            //所以我们可以推断hTcpTableData+4(也就是sizeof(dwNumEntries)的长度)后就是MIB_TCPROW数组的第一个元素
            IntPtr hTempTableRow = new IntPtr(hTcpTableData.ToInt32() + 4 + i * iTcpRowLen);
            MIB_TCPROW tcpRow = new MIB_TCPROW();
            tcpRow.dwLocalAddr = 0;
            tcpRow.dwLocalPort = 0;
            tcpRow.dwRemoteAddr = 0;
            tcpRow.dwRemotePort = 0;
            tcpRow.dwState = 0;

            //把指针数据拷贝到我们的结构对象里。
            Marshal.PtrToStructure(hTempTableRow, tcpRow);
            lstTcpRows.Add(tcpRow);
        }

        tcpTable.dwNumEntries = lstTcpRows.Count;
        tcpTable.table = new MIB_TCPROW[lstTcpRows.Count];
        lstTcpRows.CopyTo(tcpTable.table);
        return tcpTable;
    }

    public static string GetIpAddress(long ipAddrs)
    {
        try
        {
            System.Net.IPAddress ipAddress = new System.Net.IPAddress(ipAddrs);
            return ipAddress.ToString();
        }
        catch { return ipAddrs.ToString(); }
        
    }

    public static ushort GetTcpPort(int tcpPort)
    {
        return ntohs((ushort)tcpPort);
    }

    public static bool IsPortBusy(int port)
    {
        MIB_TCPTABLE tcpTableData = GetTcpTableInfo();
        return false;
    }
}


下面我再把调用的方式顺便写一下




private void button1_Click(object sender, EventArgs e)
{
    NativeFunc.MIB_TCPTABLE tcpTableData = new NativeFunc.MIB_TCPTABLE();
    tcpTableData = NativeFunc.GetTcpTableInfo();
    for (int i = 0; i < tcpTableData.dwNumEntries; i++)
    {
        this.richTextBox1.AppendText(string.Format("{0}:{1}-->>{2}:{3}/n",
            NativeFunc.GetIpAddress(tcpTableData.table[i].dwLocalAddr),
            NativeFunc.GetTcpPort(tcpTableData.table[i].dwLocalPort).ToString(),
            NativeFunc.GetIpAddress(tcpTableData.table[i].dwRemoteAddr),
            NativeFunc.GetTcpPort(tcpTableData.table[i].dwRemotePort).ToString()));
    }
}