IPV4アドレスの正当性判定を実現するC言語プログラミング
私のことを知っている友人なら、印象に残っているかもしれませんが、N年前にブログでこの話題を書きました. 作業が終わったら、この問題を解決するコードを追加しようと思っていましたが、数年間ハトでした。現在、コードのこの部分が公開されており、誰でもダウンロードしてテストできます。
記事ディレクトリ
1 前に書いた
私のことを知っている友人なら、印象に残っているかもしれませんが、N年前にブログでこの話題を書きました. 作業が終わったら、この問題を解決するコードを追加しようと思っていましたが、数年間ハトでした。現在、コードのこの部分が公開されており、誰でもダウンロードしてテストできます。
コードに問題がある場合は、プライベート メッセージでご連絡ください。
2 需要分析
実際、このトピックの要件は非常に単純です。つまり、文字列を入力して、それが正当な IPv4 アドレスかどうかを判断します。機能の観点から見ると、非常にシンプルに見えますが、完璧にするには多少の努力が必要です。信じられない場合は、以下の分解をご覧ください。
3 シンプルバージョン
簡単なバージョンから始めて、コードを直接見てみましょう。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
int is_valid_ipv4(const char *ip_address)
{
int num, dots = 0;
char *ptr;
if (ip_address == NULL) {
return 0;
}
ptr = strtok((char *)ip_address, ".");
if (ptr == NULL) {
return 0;
}
while (ptr) {
if (!isdigit(*ptr)) {
return 0;
}
num = atoi(ptr);
if (num < 0 || num > 255) {
return 0;
}
ptr = strtok(NULL, ".");
if (ptr != NULL) {
dots++;
}
}
if (dots != 3) {
return 0;
}
return 1;
}
int check_is_valid_ipv4(const char *ip)
{
int ret = 0;
ret = is_valid_ipv4(ip);
return ret;
}
int main(int argc, const char *argv[])
{
const char *ip = argv[1];
printf("check %s\n", ip);
printf("ret %d\n", check_is_valid_ipv4(ip));
}
コンパイルして実行すると、「192.168.0.1」などの一般的な ipv4 アドレスを入力しても問題ありませんが、不正な文字を入力するとエラーが報告されます。
~/ipv4]$gcc -o test ipv4.c
~/ipv4]$./test 192.168.0.1
check 192.168.0.1
ret 1
~/ipv4]$./test
check 192.168.w.2
ret 0
ただし、制限を追加すると、IPV4アドレスが正当なホスト?
たとえば、これは「238.171.84.41」であり、その判断はまだ正当ですが、実際にはこれは正当なホスト。
~/ipv4]$./test 238.171.84.41
check 238.171.84.41
ret 1
もう 1 つ、上記のコードが検出されない場合、「0192.168.1.1」と入力します。
~/ipv4]$./test 0192.168.1.1
check 0192.168.1.1
ret 1
したがって、最適化する必要があります。
4 上級
上記で分析したように、コードを最適化する必要があります。
まず、「.」で区切られた数値フィールドが「0」文字で始まることはできないと判断する必要があります。
while (ptr) {
if (!isdigit(*ptr)) {
return 0;
}
if (*ptr == '0') {
//check start with '0'
return 0;
}
num = atoi(ptr);
if (num < 0 || num > 255) {
return 0;
}
ptr = strtok(NULL, ".");
if (ptr != NULL) {
dots++;
}
}
~/ipv4]$./test 0192.168.1.1
check 0192.168.1.1
ret 0
IPv4 アドレスの分類によると、次のようになります。
-
クラス A: (1.0.0.1-126.255.255.254) (デフォルトのサブネット マスク: 255.0.0.0 または 0xFF000000) 最初のバイトはネットワーク番号で、最後の 3 バイトはホスト番号で、ネットワーク – ホスト – ホスト – ホストとして表されます。 . このタイプの IP アドレスの最初の部分は「0」であるため、アドレスのネットワーク番号は 1 から 126 の範囲です。合計で 16777214 個のホスト アドレスがあり、一般に大規模なネットワークで使用されます。
-
タイプ B: (128.1.0.1-191.254.255.254) (デフォルトのサブネット マスク: 255.255.0.0 または 0xFFFF0000) 最初の 2 バイトはネットワーク番号で、最後の 2 バイトはホスト番号です。このタイプの IP アドレスの最初の部分は「10」であるため、アドレスのネットワーク番号は 128 から 191 の範囲です。合計で 65534 個のホスト アドレスがあり、一般的に中規模のネットワークで使用されます。
-
タイプ C: (192.0.1.1-223.255.254.254) (サブネットマスク: 255.255.255.0 または 0xFFFFFF00) 最初の 3 バイトはネットワーク番号で、最後のバイトはホスト番号です。このタイプの IP アドレスの最初の部分は「110」であるため、アドレスのネットワーク番号は 192 から 223 の範囲になります。合計 254 個のホスト アドレスがあり、一般に小規模なネットワークで使用されます。
-
クラス D: マルチキャスト アドレスです。(224.0.0.1-239.255.255.254) このタイプの IP アドレスの最初の 4 桁は「1110」であるため、ネットワーク番号の範囲は 224 から 239 で、最後の 28 桁はマルチキャスト アドレス ID です。これは特別に予約されたアドレスです。特定のネットワークを指すものではなく、現在、このタイプのアドレスはマルチキャストで使用されています。マルチキャスト アドレスは、コンピュータのグループを一度にアドレス指定するために使用され、同じプロトコルを共有するコンピュータのグループを識別します。
-
クラス E: 予約アドレスであり、将来の使用のために予約されています。(240.0.0.0—255.255.255.254) このタイプの IP アドレスの最初の部分は「1111」であるため、ネットワーク番号の値は 240 ~ 255 です。
通常の IPv4 ホスト アドレスが満たされる場合、それはタイプ A、B、または C のみであり、タイプ D または E ではないことがわかります。
したがって、判断するときは、IPv4 アドレスのカテゴリ判断を増やす必要があります。
上記の判定が戻る前に、判定を追加します。
if (atoi(ip_address) >= 1 && atoi(ip_address) <= 126) {
printf("This is a Class A IP address.\n");
return 1;
} else if (atoi(ip_address) >= 128 && atoi(ip_address) <= 191) {
printf("This is a Class B IP address.\n");
return 1;
} else if (atoi(ip_address) >= 192 && atoi(ip_address) <= 223) {
printf("This is a Class C IP address.\n");
return 1;
} else {
printf("This is not a Class A, B, or C IP address.\n");
return 0;
}
完全なコードは次のとおりです。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
int is_valid_ipv4(const char *ip_address)
{
int num, dots = 0;
char *ptr;
if (ip_address == NULL) {
return 0;
}
ptr = strtok((char *)ip_address, ".");
if (ptr == NULL) {
return 0;
}
while (ptr) {
if (!isdigit(*ptr)) {
return 0;
}
if (*ptr == '0') {
//check start '0'
return 0;
}
num = atoi(ptr);
if (num < 0 || num > 255) {
return 0;
}
ptr = strtok(NULL, ".");
if (ptr != NULL) {
dots++;
}
}
if (dots != 3) {
return 0;
}
if (atoi(ip_address) >= 1 && atoi(ip_address) <= 126) {
printf("This is a Class A IP address.\n");
return 1;
} else if (atoi(ip_address) >= 128 && atoi(ip_address) <= 191) {
printf("This is a Class B IP address.\n");
return 1;
} else if (atoi(ip_address) >= 192 && atoi(ip_address) <= 223) {
printf("This is a Class C IP address.\n");
return 1;
} else {
printf("This is not a Class A, B, or C IP address.\n");
return 0;
}
return 1;
}
int check_is_valid_ipv4(const char *ip)
{
int ret = 0;
ret = is_valid_ipv4(ip);
return ret;
}
int main(int argc, const char *argv[])
{
const char *ip = argv[1];
printf("check %s\n", ip);
printf("ret %d\n", check_is_valid_ipv4(ip));
}
この時点で、以前の非 A/B/C IPv4 アドレスを試してみましょう。
~/ipv4]$./test 238.171.84.41
check 238.171.84.41
This is not a Class A, B, or C IP address.
ret 0
~/ipv4]$./test 192.168.2.3
check 192.168.2.3
This is a Class C IP address.
ret 1
これまでのところ、基本的には比較的完璧な判断が得られていますが、抜け穴はありますか? 読者に任せて、自分で理解してください。
5 上級版
経験豊富なプログラムは、上記の判断が非常に面倒であることに気付くはずです。
このようにすべてのケースを比較して判断する必要があり、非常に手間がかかります。
もっとさわやかな高レベルの方法はありますか?
もちろん、答えはイエスです。現時点では、正規表現を理解する必要があります。
主流のプログラミング言語の多くは正規表現をサポートする標準ライブラリを持っていますが、C言語にはあるのでしょうか?
実はC言語でも正規表現が使えるのですが、ここはサスペンスにして、次の章で分解して聞いてみましょう。
プレビューへようこそ:正規表現言語 - クイック リファレンス | Microsoft Learn
6 つの完全なテスト ケース
このセクションでは、コードのテストに役立つことを期待して、さまざまなテスト ケースを追加します。
合法的测试输入
192.168.0.1
10.0.0.1
172.16.0.1
255.255.255.255
非法的测试输入
256.0.0.1
192.168.0.0.1
192.168.0
192.168.0.1.2
非法的测试输入
256.0.0.1
192.168.0.0.1
192.168.0
192.168.0.1.2
300.300.300.300
1.2.3
1.2.3.4.5
1.2.3.4.
.1.2.3.4
1..2.3.4
テスト ケースは常に充実しており、誰でも追加できます。