スイッチのレイヤ 2 およびレイヤ 3 プロトコルとその詳細なソリューション
概要
スイッチはネットワーク デバイスの一種で、主に複数のネットワーク デバイスを接続してネットワーク通信とデータ送信を実現するために使用されます。スイッチのプロトコルは 2 層プロトコルと 3 層プロトコルに分かれます。
レイヤ2プロトコル
レイヤ 2 プロトコルはデータリンク層プロトコルとも呼ばれ、一般的なプロトコルには次のようなものがあります。
- イーサネット プロトコル: イーサネットは、物理層とデータ リンク層でデータを送信する方法を定義する、広く使用されているローカル エリア ネットワーク (LAN) テクノロジです。
- トークン リング プロトコル: トークン リングは、トークン パッシング メカニズムを使用してネットワークへのアクセスを制御し、競合や衝突を防ぐもう 1 つの LAN テクノロジです。
- MAC ベース スイッチング プロトコル (MAC-Based Switching Protocol): MAC アドレスに基づいてスイッチングするためのプロトコル。データ パケット転送の効率を向上させることができます。
レイヤ3プロトコル
3 層プロトコルはネットワーク層プロトコルとも呼ばれ、一般的なものには次のものがあります。
- IP プロトコル (インターネット プロトコル): IP は、インターネット上のデータ通信の基本プロトコルであり、送信元アドレスから宛先アドレスへデータ パケットを送信するために使用されます。
- ARP プロトコル (アドレス解決プロトコル): ARP プロトコルは、データ パケットがターゲット デバイスに正しく送信できるように、MAC アドレスと IP アドレスの間のマッピング関係を解決するために使用されます。
- ICMP プロトコル (Internet Control Message Protocol): ICMP プロトコルはネットワークのエラー検出と診断に使用され、たとえば ping コマンドは ICMP プロトコルを使用して実装されます。
- OSPF プロトコル (Open Shortest Path First): OSPF は、データ パケットの送信に使用可能な複数のパスの中から最短のパスを選択するために使用されるルーティング プロトコルです。
イーサネットプロトコル
イーサネットは、コンピュータがローカル エリア ネットワーク上で通信する方法を定義するローカル エリア ネットワーク プロトコルです。ここでは、イーサネット プロトコルの詳細をいくつか説明します。
物理層
イーサネット物理層は、ケーブル、コネクタ、および信号の特性を定義します。一般的に使用されるイーサネット ケーブルには、ツイスト ペア、同軸ケーブル、光ファイバーが含まれ、コネクタには RJ45、BNC、SC などがあります。
データ リンク層
イーサネット データ リンク層は、論理リンク コントロール (LLC) サブレイヤとメディア アクセス コントロール (MAC) サブレイヤの 2 つのサブレイヤで構成されます。LLC サブレイヤは、上位層プロトコルがさまざまなタイプのネットワークと通信できるようにする統合インターフェイスを提供します。MAC サブレイヤはイーサネット プロトコルの中核であり、データ フレームを LAN に送信する方法を定義します。
データ フレームの形式
イーサネット プロトコルのデータ フレームは次の部分で構成されます。
プリアンブル: データ フレーム クロックを同期するために使用されます。
宛先アドレスと送信元アドレス: 各イーサネット アダプターには一意の MAC アドレスがあり、データ パケットの送信者と受信者を識別するために使用されます。
タイプ/長さフィールド: データ フレーム内のデータのタイプまたは長さを指定します。
データ セクション: データ フレーム内の実際のデータ。
フレーム チェック シーケンス (FCS): 送信中にデータ フレームにエラーがあるかどうかを検出するために使用されます。
MAC アドレス
すべてのイーサネット アダプタには一意の MAC アドレスがあり、これは 6 バイトで構成され、通常は 12 桁の 16 進数で表されます。最初の 3 バイトはベンダー ID を表し、最後の 3 バイトはアダプターのシリアル番号を表します。
データ伝送
イーサネットでは、データ伝送には CSMA/CD 協定、つまりキャリア センス マルチポイント アクセス/衝突検出協定が採用されています。ノードがデータを送信したい場合、まずネットワークをリッスンし、他のノードがデータを送信していなければ、データを送信できます。2 つのノードが同時にデータを送信して衝突が発生した場合、ノードは送信を停止し、ランダムな時間待機してからデータの送信を再試行します。
上記は、ローカル エリア ネットワークに信頼性の高い通信方法を提供するイーサネット プロトコルの詳細な説明です。
サンプルコード
以下は、フレームの生成、解析、送信を含む、Python で実装された簡単なイーサネット プロトコルの例です。
import struct
# 生成以太网帧
def create_ethernet_frame(dest_mac, src_mac, data):
# 以太网帧格式:目的MAC地址+源MAC地址+类型+数据+校验和
frame = struct.pack("!6s6sH", dest_mac, src_mac, len(data)) + data
return frame
# 解析以太网帧
def parse_ethernet_frame(frame):
dest_mac, src_mac, length = struct.unpack("!6s6sH", frame[:14])
data = frame[14:]
return (dest_mac, src_mac, length, data)
# 发送以太网帧
```bash
def send_ethernet_frame(frame):
print("Sending ethernet frame:", frame)
# 测试代码
def test():
dest_mac = b"\x00\x11\x22\x33\x44\x55"
src_mac = b"\x66\x77\x88\x99\xaa\xbb"
data = b"Hello, world!"
# 生成帧
frame = create_ethernet_frame(dest_mac, src_mac, data)
print("Created ethernet frame:", frame)
# 解析帧
dest_mac, src_mac, length, data = parse_ethernet_frame(frame)
print("Parsed ethernet frame: dest_mac =", dest_mac.hex(), ", src_mac =", src_mac.hex(), ", length =", length, ", data =", data)
# 发送帧
send_ethernet_frame(frame)
test()
上記のコードでは、
create_ethernet_frame() 関数が、宛先 MAC アドレス、送信元 MAC アドレス、データ長、およびデータを含むイーサネット フレームを生成します。
parse_ethernet_frame() 関数は、イーサネット フレームを解析し、宛先 MAC アドレス、送信元 MAC アドレス、データ長およびデータを返します。send_ethernet_frame() 関数は、イーサネット フレームを送信するために使用されます。
Python の struct モジュールを使用して、バイナリ データのパックとアンパックを処理しました。create_ethernet_frame() 関数では、struct.pack() 関数を使用してイーサネット フレームのさまざまなフィールドをバイナリ文字列にパックし、それらをつなぎ合わせて完全なイーサネット フレームを取得します。parse_ethernet_frame() 関数では、struct.unpack() 関数を使用してイーサネット フレームのフィールドを解凍し、その値を返します。
test() 関数では、宛先 MAC アドレス、送信元 MAC アドレス、およびデータを含むイーサネット フレームを生成し、出力します。次に、イーサネット フレームを解析し、解析結果を出力します。最後に、このイーサネット フレームを送信し、出力します。
上記のコードは単なる単純な例であり、完全なイーサネット プロトコルを実装しているわけではないことに注意してください。実際のプロジェクトでイーサネット プロトコルを使用する必要がある場合は、より完全で信頼性の高い実装を使用してください。
CSMA/CD協定
CSMA/CD はローカル エリア ネットワーク用のマルチポイント アクセス プロトコルで、複数のノードが同時にデータを送信する場合の衝突を制御するために使用されます。以下に、CSMA/CD プロトコルの詳細な説明と、簡単な Python コード例を示します。
キャリアセンス (CS)
ノードがデータを送信したい場合、最初にネットワークをリッスンして、他のノードがデータを送信しているかどうかを確認します。ネットワーク上でデータ送信がない場合、ノードはデータの送信を開始できます。
衝突検出 (CD)
2 つ以上のノードが同時にデータの送信を開始すると、ネットワーク上で衝突が発生します。ノードはネットワーク上で衝突を検出すると、データの送信を停止し、ランダムな時間待機してから再試行します。
バックオフ アルゴリズム
バックオフ アルゴリズムは、ネットワーク競合が発生したときにノードが同時にデータを再送信するのを防ぐために使用されます。各ノードは、衝突の可能性を減らすために、データを再送信する前にランダムな時間待機します。
サンプルコード
以下は、キャリア センス、衝突検出、バックオフ アルゴリズムを含む、Python で実装された単純な CSMA/CD アルゴリズムの例です。
import random
# 载波监听
def cs(listening):
if listening:
print("No other nodes transmitting data, start transmitting...")
else:
print("Network is busy, wait until idle.")
# 碰撞检测
def cd():
print("Collision detected, stop transmitting and wait for random time...")
# 生成1-10之间的随机数
random_time = random.randint(1, 10)
print("Wait for", random_time, "seconds before retrying...")
# 退避算法
def backoff(time):
print("Wait for another", time, "seconds before retrying...")
# 生成一个更长的等待时间
new_time = 2 * time
return new_time
# 测试数据传输
def test():
# 生成一个随机的0或1
node1 = random.randint(0, 1)
node2 = random.randint(0, 1)
# 如果节点1和节点2都没有在发送数据,则开始发送数据
if node1 == 0 and node2 == 0:
cs(True)
# 如果只有一个节点在发送数据,则该节点可以继续发送数据
elif node1 == 0:
cs(False)
elif node2 == 0:
cs(False)
# 如果两个节点都在发送数据,则发生碰撞
else:
cd()
# 等待一个随机时间后,使用退避算法计算下一个等待时间
time = backoff(random.randint(1, 10))
# 等待下一个时间段后再次尝试发送数据
test(time)
test()
上記のコードでは、test() 関数は、キャリア センス、衝突検出、バックオフ計算など、2 つのノードがデータを送信するときの状況をシミュレートします。
IPプロトコル
IP (インターネット プロトコル) プロトコルは、インターネット上のデータ送信の基本プロトコルの 1 つであり、主にデータ パケットの送信とルーティングを担当します。
IP プロトコルはコネクションレスで信頼性の低いプロトコルであり、データ伝送の保証はなく、最も基本的なデータ伝送サービスのみを提供します。データ送信プロセス中、IP プロトコルは、送信元アドレスと宛先アドレスをデータ パケットに追加することで、データが宛先に到達できることを保証します。このプロセスはルーティングと呼ばれます。
IP プロトコルのアドレスは 32 ビットの数値で、通常は 4 つの数値として記述され、各数値はドットで区切られます。例: 192.168.0.1。
IP プロトコルは、データ パケットを送信元アドレスから宛先アドレスに送信する方法を定義しており、このプロセス中に、中間ルーターはデータ パケット内の宛先アドレスに応じてデータ パケットの転送方法を決定します。ルーターがパケットのルーティング パスを決定できない場合、パケットはデフォルト ゲートウェイに送信されます。
IP プロトコルは、いくつかのオプションを通じてその機能を拡張することもでき、たとえば、IP プロトコルは、プロトコル番号フィールドを通じてさまざまな伝送プロトコル (TCP、UDP、ICMP など) をサポートできます。IP プロトコルは、いくつかのフラグ フィールドを使用して、パケットの断片化、再構成、タイムスタンプなどの機能をサポートすることもできます。
一般に、IP プロトコルはインターネットの基本プロトコルの 1 つであり、データ送信とルーティング サービスを提供し、上位プロトコルの基本サービスを提供します。
サンプルコード
以下は、パケットの生成、解析、送信を含む、Python で実装された IP プロトコルの簡単な例です。
import struct
import socket
# 生成IP数据包
def create_ip_packet(source_ip, dest_ip, data):
# IP数据包格式:版本+首部长度+区分服务+总长度+标识+标志+片偏移+生存时间+协议+校验和+源IP地址+目标IP地址+数据
version = 4
ihl = 5
tos = 0
total_length = len(data) + 20
identification = 0
flags = 0
fragment_offset = 0
ttl = 255
protocol = socket.IPPROTO_TCP
header_checksum = 0
ip_header = struct.pack("!BBHHHBBH4s4s", (version << 4) + ihl, tos, total_length, identification, (flags << 13) + fragment_offset, ttl, protocol, header_checksum, socket.inet_aton(source_ip), socket.inet_aton(dest_ip))
header_checksum = calculate_checksum(ip_header)
ip_header = struct.pack("!BBHHHBBH4s4s", (version << 4) + ihl, tos, total_length, identification, (flags << 13) + fragment_offset, ttl, protocol, header_checksum, socket.inet_aton(source_ip), socket.inet_aton(dest_ip))
packet = ip_header + data
return packet
# 解析IP数据包
def parse_ip_packet(packet):
ip_header = packet[:20]
version_ihl, tos, total_length, identification, flags_fragment_offset, ttl, protocol, header_checksum, source_ip, dest_ip = struct.unpack("!BBHHHBBH4s4s", ip_header)
version = version_ihl >> 4
ihl = version_ihl & 0x0f
flags = flags_fragment_offset >> 13
fragment_offset = flags
ip_header_length = ihl * 4
data = packet[ip_header_length:]
return version, ihl, tos, total_length, identification, flags, fragment_offset, ttl, protocol, header_checksum, socket.inet_ntoa(source_ip), socket.inet_ntoa(dest_ip), data
计算IP数据包首部校验和
def calculate_checksum(header):
length = len(header)
if length % 2 == 1:
header += b'\0'
length += 1
checksum = 0
for i in range(0, length, 2):
word = (header[i] << 8) + header[i + 1]
checksum += word
while checksum >> 16:
checksum = (checksum & 0xffff) + (checksum >> 16)
checksum = ~checksum & 0xffff
return checksum
发送IP数据包
def send_ip_packet(packet, dest_ip):
s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_RAW)
s.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1)
s.sendto(packet, (dest_ip, 0))
测试IP协议代码
def test():
source_ip = "192.168.1.100"
dest_ip = "192.168.1.1"
data = b"Hello, world!"
packet = create_ip_packet(source_ip, dest_ip, data)
print("IP packet:", packet)
version, ihl, tos, total_length, identification, flags, fragment_offset, ttl, protocol, header_checksum, source_ip, dest_ip, data = parse_ip_packet(packet)
print("Version:", version)
print("IHL:", ihl)
print("TOS:", tos)
print("Total Length:", total_length)
print("Identification:", identification)
print("Flags:", flags)
print("Fragment Offset:", fragment_offset)
print("TTL:", ttl)
print("Protocol:", protocol)
print("Header Checksum:", header_checksum)
print("Source IP:", source_ip)
print("Destination IP:", dest_ip)
print("Data:", data)
send_ip_packet(packet, dest_ip)
print("Packet sent.")
test()
上記のコードでは、Python のソケット モジュールを使用して IP パケットを送受信します。create_ip_packet() 関数では、まず IP パケットの形式に従って各フィールドの値を定義し、次に struct.pack() 関数を使用してそれらをバイナリ文字列にパックし、ヘッダーのチェックサムを計算します。最後に、IP ヘッダーとデータを結合して、完全な IP パケットを取得します。
parse_ip_packet() 関数では、struct.unpack() 関数を使用して IP パケットのさまざまなフィールドを解凍し、その値を返します。Calculate_checksum() 関数では、IP パケットのヘッダー チェックサムを計算して、パケットの整合性を保証します。send_ip_packet() 関数では、ソケット モジュールの生のソケットを使用して IP パケットを送信します。
test() 関数では、送信元 IP アドレス、宛先 IP アドレス、およびデータを含む IP パケットを生成し、出力します。次に、IP パケットを解析し、解析結果を出力します。最後に、この IP パケットを送信します。