程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C >> 關於C >> C語言實現IP地址合法性檢測和子網匹配

C語言實現IP地址合法性檢測和子網匹配

編輯:關於C
#include 
#include 
#ifdef WIN32
#include 
#else
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#include  
#include  
#include  
#include  
#include  
#include  

#ifdef WIN32
#pragma comment(lib,"wsock32.lib")
#endif

/*參數UINT32都為網絡字節順序。*/

/*IP地址是否合法, 合法返回TURE,失敗返回FALSE*/
int netIpIsValid(_UINT32 IP)
{
    int i;
    struct in_addr addr;
    addr.s_addr = IP;
    
    i = inet_addr(inet_ntoa(addr));

    if((i == 0)||(i == 0xffffffff))
        return FALSE;
    else
        return TRUE;
}
   
/*MASK子網掩碼是否合法, 合法返回TURE,失敗返回FALSE*/
int netMaskIsValid(_UINT32 mask)
{
    int i;
    unsigned long ii;
    i = netIpIsValid(mask);
    if(i==TRUE)
    {
        ii = ntohl(mask);
        if((ii|ii-1)==0xffffffff)
        {
            return TRUE;
        }
    }
    
    return FALSE;
}

/*MASK子網掩碼是否合法, 合法返回TURE,失敗返回FALSE*/
int netMaskAndIpIsValid(_UINT32 IP, _UINT32 mask)
{
    int i;
    int a, b=0, c;
    i = netIpIsValid(IP);
    if(i!=TRUE)
        return FALSE;
    i = netMaskIsValid(mask);
    if(i!=TRUE)
        return FALSE;

    a = IP&0x000000ff;
    b = ntohl(mask);

    /*首先與默認子網掩碼比較*/
    if(a>0&&a<127)
    {
        if(mask<0x000000ff)
            return FALSE;
        if(mask>0x000000ff)
            b-=0xff000000;
    }
    if(a>=128&&a<=191)
    {
        if(mask<0x0000ffff)
            return FALSE;
        if(mask>0x0000ffff)
            b-=0xffff0000;
    }
    if(a>=192&&a<=223)
    {
        if(mask<0x00ffffff)
            return FALSE;
        if(mask>0x00ffffff)
            b-=0xffffff00;
    }

    /*每個子網段的第一個是網絡地址,用來標志這個網絡,最後一個是廣播地址,用來代表這個網絡上的所有主機.這兩個IP地址被TCP/IP保留,不可分配給主機使用.*/
    c = ~ntohl(mask)&ntohl(IP);
    if(c==0||c==~ntohl(mask))
        return FALSE;

    /*RFC 1009中規定劃分子網時,子網號不能全為0或1,會導致IP地址的二義性*/
    if(b>0)
    {
        c = b&(ntohl(IP));
        if(c==0||c==b)
            return FALSE;
    }

    return TRUE;
}

/*測試主網和子網是否匹配,也可測試兩個主機IP是否在同一網段內*/
int netIPAndSubnetValid(_UINT32 IP, _UINT32 subIP, _UINT32 mask)
{
    int i;
    int addr1, addr2;
    i = netMaskAndIpIsValid(IP, mask);
    if(i!=TRUE)
    	return FALSE;
    i = netMaskAndIpIsValid(subIP, mask);
    if(i!=TRUE)
    	return FALSE;

    addr1 = IP&mask;
    addr2 = subIP&mask;

    if(addr1!=addr2)
    	return FALSE;

    return TRUE;
}


技術實現及功能:
1. 用C語言實現
2. 判斷IP地址是否合法
3. 判斷MASK是否合法
4. 判斷MASK和IP地址組合是否合法

測試:

測試環境:win7 VC++;
測試結果:
1、測試IP是否合法:
輸入IP為0xFFFFFFFF即255.255.255.255,結果為不合法;
輸入IP為0x00000000即0.0.0.0,結果為不合法;
輸入IP為0x00000000--0xFFFFFFFF即在0.0.0.0--255.255.255.255之間(全0和全1除外),結果為合法。
2、測試子網掩碼是否合法:
輸入0x00C0FFFF(1111 1111.1111 1111.1100 0000),結果合法;
輸入一個無符號int型數,二進制形式為 左邊為全1右邊為全0,結果合法,其余形式不合法。
3、測試子網掩碼和IP是否匹配:
輸入IP為0x410AA8C0即192.168.10.65(C類IP),輸入子網掩碼為0xC0FFFFFF,結果匹配,輸入小於0x00FFFFFF的子網掩碼時不匹配;
輸入IP為0x0141A885即133.168.65.1(B類IP),輸入子網掩碼為0x00C0FFFF,結果匹配,輸入小於0x0000FFFF的子網掩碼時不匹配;
輸入IP為0x0100413F即63.65.0.1(A類IP),輸入子網掩碼為0x0000C0FF,結果匹配,輸入小於0x000000FF的子網掩碼時不匹配。
子網段內第一個和最後一個IP不可分配;子網號全0或全1的子網不可用,此時的結果都為不匹配。
4、測試兩個IP是否在同一子網段:
輸入兩個IP為0x0C81C480 0x118FC480,輸入子網掩碼為0x00C0FFFF,結果為兩個IP在同一網段;
輸入兩個IP為0x0C81C480 0x117FC480,輸入子網掩碼為0x00C0FFFF,結果兩個IP不在同一網段。

備注:測試數據為無符號int型,網絡字節順序。

補充知識:

一般的,32位的IP地址分為兩部分,即網絡號和主機號,我們分別把他們叫做IP地址的“網間網部分”和“本地部分”。子網編址技術將本地部分進一步劃分為“物理網絡”部分和“主機”部分,其中“物理網絡”用於標識同一IP網絡地址下的不同物理網絡,即是“子網”。

A類IP段  0.0.0.0 到127.255.255.255

 B類IP段  128.0.0.0 到191.255.255.255

 C類IP段  192.0.0.0 到223.255.255.255

XP默認分配的子網掩碼每段只有255或0

  A類的默認子網掩碼 255.0.0.0     一個子網最多可以容納1677萬多台電腦

  B類的默認子網掩碼 255.255.0.0    一個子網最多可以容納6萬台電腦

  C類的默認子網掩碼 255.255.255.0   一個子網最多可以容納254台電腦
以C類地址為例。IP地址中的前3個字節表示網絡號,後一個字節既表明子網號,又說明主機號,還說明兩個IP地址是否屬於一個網段。如果屬於同一網絡區間,這兩個地址間的信息交換就不通過路由器。如果不屬同一網絡區間,也就是子網號不同,兩個地址的信息交換就要通過路由器進行。

看一個例子:
A的IP地址:11000000,10101000,00000000,00000101
子網掩碼:11111111,11111111,11111111,00000000
B的IP地址:11000000,10101000,00000000,00010110

看上邊的內容,子網掩碼在左邊一共有24位為1,那這樣的意思就是如果兩個IP地址的前24位都相同的話,那這兩個IP地址就是在同一個網段內,看到我紅色標記的A和B的地址都相同,那這就說明A和B在同一個網段內。

再看一個例子,如果還是A地址的數據發到C地址,C的IP地址為192.168.56.21
A的IP地址:11000000,10101000,00000000,00000101
子網掩碼:11111111,11111111,11111111,00000000
C的IP地址:11000000,10101000,00111000,00010101

看上邊的A和C,按照子網掩碼的要求,如果C的前24位和A的前24位都相同的話,那麼A和C才是同一網段的,看上邊C的地址,我用藍色來標注不同的位數,這樣A 和C就不在同一個網段內,路由器就不能直接把A要發給C的數據直接經過一個路由器給發送過去,這樣路由器就要先將A的數據轉發到另外一個路由器(一個不行就繼續往下發),然後再發到C上。

● 字節序轉換函數
htons 把 unsigned short 類型從主機序轉換到網絡序
htonl 把 unsigned long 類型從主機序轉換到網絡序
ntohs 把 unsigned short 類型從網絡序轉換到主機序
ntohl 把 unsigned long 類型從網絡序轉換到主機序
這幾個函數很好記,比如htons中hton代表host to network, s代表unsigned short
char FAR * inet_ntoa( struct in_addr in);
將一個IP轉換成一個互聯網標准點分格式的字符串。
in_addr_t inet_addr(const char *cp);
將一個點分十進制的IP轉換成一個長整數型數(u_long類型)。返回值已是網絡字節順序,可以直接作為internet 地址

一個函數返回值為TRUE或FALSE 只有這兩種返回值時 在判斷返回值時不用 if(i==TRUE)或if(i==FALSE),而用if(i) if(!i) 編程規范。

inet_ntoa()返回的字符串是臨時裝在一個靜態分配的緩沖區裡面,下一次調用此函數的時候緩沖區會被重寫

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved