1. 程式人生 > >關於埠和程序的對映

關於埠和程序的對映

    網上的那些所謂的談埠和程序對映的例子都不能使用,後來買了這本書,找到了好用的例子。真不明白那些人為什麼要把沒有用的了例子放到網上去噁心人,自己連試也不試就放到了網上,真的很讓人噁心。
    這個例子是《visusl c++網路程式設計例項詳解》(人民郵電)第七章裡面的最後一個例子,很好用,所以放到網上來和大家分享一下。
    使用下面的程式碼的前提是要安裝windows2003的PlatformSDK,可以到這裡下載http://www.microsoft.com/msdownload/platformsdk/sdkupdate/psdk-full.htm
//////////////////////////////////////////////////////////////////////
// netstate.cpp檔案


#include <stdio.h>
#include <windows.h>
#include <Iphlpapi.h>
#include <tlhelp32.h>

#pragma comment(lib, "Iphlpapi.lib")
#pragma comment(lib, "WS2_32.lib")


typedef struct
{
  DWORD   dwState;         // 連線狀態
  DWORD   dwLocalAddr;     // 本地地址
  DWORD   dwLocalPort;     // 本地埠
  DWORD   dwRemoteAddr;    // 遠端地址
  DWORD   dwRemotePort;    // 遠端埠
  DWORD   dwProcessId;  // 程序ID號
} MIB_TCPEXROW, *PMIB_TCPEXROW;

typedef struct
{
 DWORD   dwNumEntries;
 MIB_TCPEXROW table[ANY_SIZE];
} MIB_TCPEXTABLE, *PMIB_TCPEXTABLE;

typedef struct
{
  DWORD   dwLocalAddr;     // 本地地址
  DWORD   dwLocalPort;     // 本地埠
  DWORD   dwProcessId;  // 程序ID號
} MIB_UDPEXROW, *PMIB_UDPEXROW;

typedef struct
{
 DWORD   dwNumEntries;
 MIB_UDPEXROW table[ANY_SIZE];
} MIB_UDPEXTABLE, *PMIB_UDPEXTABLE;


// 擴充套件函式原型
typedef DWORD (WINAPI *PFNAllocateAndGetTcpExTableFromStack)(
  PMIB_TCPEXTABLE *pTcpTable,
  BOOL bOrder,            
  HANDLE heap,
  DWORD zero,
  DWORD flags
);

typedef DWORD (WINAPI *PFNAllocateAndGetUdpExTableFromStack)(
  PMIB_UDPEXTABLE *pUdpTable, 
  BOOL bOrder,             
  HANDLE heap,
  DWORD zero,
  DWORD flags
);


PCHAR ProcessPidToName(HANDLE hProcessSnap, DWORD ProcessId, PCHAR ProcessName);

int main()
{
 // 定義擴充套件函式指標
 PFNAllocateAndGetTcpExTableFromStack pAllocateAndGetTcpExTableFromStack;
 PFNAllocateAndGetUdpExTableFromStack pAllocateAndGetUdpExTableFromStack;

 // 獲取擴充套件函式的入口地址
 HMODULE hModule = ::LoadLibrary("iphlpapi.dll");
 pAllocateAndGetTcpExTableFromStack =
   (PFNAllocateAndGetTcpExTableFromStack)::GetProcAddress(hModule,
         "AllocateAndGetTcpExTableFromStack");
 
 pAllocateAndGetUdpExTableFromStack =
   (PFNAllocateAndGetUdpExTableFromStack)::GetProcAddress(hModule,
         "AllocateAndGetUdpExTableFromStack");

 if(pAllocateAndGetTcpExTableFromStack == NULL || pAllocateAndGetUdpExTableFromStack == NULL)
 {
  printf(" Ex APIs are not present /n ");
  // 說明你應該呼叫普通的IP幫助API去獲取TCP連線表和UDP監聽表
  return 0;
 }

 // 呼叫擴充套件函式,獲取TCP擴充套件連線表和UDP擴充套件監聽表

 PMIB_TCPEXTABLE pTcpExTable;
 PMIB_UDPEXTABLE pUdpExTable;

 // pTcpExTable和pUdpExTable所指的緩衝區自動由擴充套件函式在程序堆中申請
 if(pAllocateAndGetTcpExTableFromStack(&pTcpExTable, TRUE, GetProcessHeap(), 2, 2) != 0)
 {
   printf(" Failed to snapshot TCP endpoints./n");
   return -1;
 }
 if(pAllocateAndGetUdpExTableFromStack(&pUdpExTable, TRUE, GetProcessHeap(), 2, 2) != 0)
 {
   printf(" Failed to snapshot UDP endpoints./n");
   return -1;
 }

 // 給系統內的所有程序拍一個快照
 HANDLE hProcessSnap = ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
 if(hProcessSnap == INVALID_HANDLE_VALUE)
 {
  printf(" Failed to take process snapshot. Process names will not be shown./n/n");
  return -1;
 }

 printf(" Active Connections /n/n");
 char szLocalAddr[128];
 char szRemoteAddr[128];
 char szProcessName[128];
 in_addr inadLocal, inadRemote;
 char    strState[128];
 DWORD   dwRemotePort = 0;

 // 列印TCP擴充套件連線表資訊
 for(UINT i = 0; i < pTcpExTable->dwNumEntries; ++i)
 {
  // 狀態
  switch (pTcpExTable->table[i].dwState)
  {
  case MIB_TCP_STATE_CLOSED:
   strcpy(strState, "CLOSED");
   break;
  case MIB_TCP_STATE_TIME_WAIT:
   strcpy(strState, "TIME_WAIT");
   break;
  case MIB_TCP_STATE_LAST_ACK:
   strcpy(strState, "LAST_ACK");
   break;
  case MIB_TCP_STATE_CLOSING:
   strcpy(strState, "CLOSING");
   break;
  case MIB_TCP_STATE_CLOSE_WAIT:
   strcpy(strState, "CLOSE_WAIT");
   break;
  case MIB_TCP_STATE_FIN_WAIT1:
   strcpy(strState, "FIN_WAIT1");
   break;
  case MIB_TCP_STATE_ESTAB:
   strcpy(strState, "ESTAB");
   break;
  case MIB_TCP_STATE_SYN_RCVD:
   strcpy(strState, "SYN_RCVD");
   break;
  case MIB_TCP_STATE_SYN_SENT:
   strcpy(strState, "SYN_SENT");
   break;
  case MIB_TCP_STATE_LISTEN:
   strcpy(strState, "LISTEN");
   break;
  case MIB_TCP_STATE_DELETE_TCB:
   strcpy(strState, "DELETE");
   break;
  default:
   printf("Error: unknown state!/n");
   break;
  }
  // 本地IP地址
  inadLocal.s_addr = pTcpExTable->table[i].dwLocalAddr;
 
  // 遠端埠
  if(strcmp(strState, "LISTEN") != 0)
  {
   dwRemotePort = pTcpExTable->table[i].dwRemotePort;
  }
  else
   dwRemotePort = 0;

  // 遠端IP地址
  inadRemote.s_addr = pTcpExTable->table[i].dwRemoteAddr;
 

  sprintf(szLocalAddr, "%s:%u", inet_ntoa(inadLocal),
     ntohs((unsigned short)(0x0000FFFF & pTcpExTable->table[i].dwLocalPort)));
  sprintf(szRemoteAddr, "%s:%u", inet_ntoa(inadRemote),
     ntohs((unsigned short)(0x0000FFFF & dwRemotePort)));

  // 打印出此入口的資訊
  printf("%-5s %s:%d/n      State:   %s/n", "[TCP]",
   ProcessPidToName(hProcessSnap, pTcpExTable->table[i].dwProcessId, szProcessName),
   pTcpExTable->table[i].dwProcessId,
   strState);

  printf("      Local:   %s/n      Remote:  %s/n",
   szLocalAddr, szRemoteAddr);
 }

 // 列印UDP監聽表資訊
 for(i = 0; i < pUdpExTable->dwNumEntries; ++i)
 {
  // 本地IP地址
  inadLocal.s_addr = pUdpExTable->table[i].dwLocalAddr;

  sprintf(szLocalAddr,  "%s:%u", inet_ntoa(inadLocal),
    ntohs((unsigned short)(0x0000FFFF & pUdpExTable->table[i].dwLocalPort)));

  // 打印出此入口的資訊
  printf("%-5s %s:%d/n", "[UDP]",
   ProcessPidToName(hProcessSnap, pUdpExTable->table[i].dwProcessId, szProcessName),
   pUdpExTable->table[i].dwProcessId );
  printf("      Local:   %s/n      Remote:  %s/n",
   szLocalAddr, "*.*.*.*:*" );
 }
 
 
 ::CloseHandle(hProcessSnap);
 ::LocalFree(pTcpExTable);
 ::LocalFree(pUdpExTable);
 ::FreeLibrary(hModule);
 return 0;
}


// 將程序ID號(PID)轉化為程序名稱
PCHAR ProcessPidToName(HANDLE hProcessSnap, DWORD ProcessId, PCHAR ProcessName)
{
 PROCESSENTRY32 processEntry;
 processEntry.dwSize = sizeof(processEntry);
 // 找不到的話,預設程序名為“???”
 strcpy(ProcessName, "???");
 if(!::Process32First(hProcessSnap, &processEntry))
  return ProcessName;
 do
 {
  if(processEntry.th32ProcessID == ProcessId) // 找到和id相對應的程序名稱
  {
   strcpy(ProcessName, processEntry.szExeFile);
   break;
  }
 }
 while(::Process32Next(hProcessSnap, &processEntry));
 return ProcessName;
}
   做這個工程的時候,網上的很多朋友,尤其是csdn裡面的很多朋友給了很大的幫助,所以我覺得有了好的程式碼也應該拿出來,這樣才能共同進步,還是希望那些亂貼所謂的談埠程序對映的偽君子以後注意一點,不要把沒有用的東西放到網上,浪費大家的時間,而且還讓人噁心。
   這篇文章和程式碼任何看到的人都可以隨意複製,不過希望大家儘量註明出處(visusl c++網路程式設計例項詳解》(人民郵電)張越),以便尊重作者。有需要的朋友可以和我聯絡,我可以提供原始碼,我的QQ251552062.