三、网络故障模拟(TCP、UDP抓包分析)

本文介绍了如何在Linux虚拟机中进行网络通信实验,包括TCP和UDP的数据抓包与分析。内容涵盖从下载虚拟机到安装tqdm,再到Windows与虚拟机之间的文件传输。此外,还详细展示了TCP与UDP客户端和服务端的Python实现,以及使用tshark进行数据包抓取和分析,以确保可靠的数据传输。最后,探讨了在UDP中实现可靠传输的方法和开源库。
摘要由CSDN通过智能技术生成

lab4-1 (siat.ac.cn)

目录

虚拟机下载zip文件

Windows下安装tqdm

将虚拟机上的文件下载到电脑上

将Windows文件上传到虚拟机

数据抓包与分析

TCP抓包分析

 Python数据分析

TCP客户端

TCP服务端

UDP抓包分析

UDP客户端

UDP服务端


虚拟机下载zip文件

wget https://cc.siat.ac.cn/networks/exp4-tshark_socket.zip --no-check-certificate

下载unzip

sudo apt install unzip 

下载python模块

apt install python3-pip

pip3 install tqdm

解压

unzip exp4-tshark_socket

cd exp4-tshark_socket

vim sending-files-servers.py

编辑

vim 文件名

i        进入编辑模式

esc   退出编辑模式

:wq    保存并退出

Windows下安装tqdm

python -m pip install -U pip

pip install tqdm

将虚拟机上的文件下载到电脑上

Windows命令行操作

sftp ee@10.1.131.73:/home/ee/exp4-tshark_socket/output.csv C:\Users\lenovo\Downloads\Compressed\exp4-tshark_socket\exp4-tshark_socket

将Windows文件上传到虚拟机

Windows命令行操作

scp C:\Users\lenovo\Downloads\Compressed\exp4-tshark_socket\exp4-tshark_socket\my_socket-client-UDP.py ee@10.1.131.73:/home/ee/exp4-tshark_socket 

Socket 程序启动

服务端与客户端需要在不同的机器。

  • 启动服务端
  • 在客户端机器启动tc故障模拟
  • 启动抓包
  • 启动客户端发送数据

数据抓包与分析

  • 在发送端进行网络故障模拟

    tc qdisc add dev eno1 root netem loss 10%
    
  • 使用tshark进行抓包

    tshark -i eno1 -f 'port 65432' -w test.pcap
  • 过滤器提取关键特征数据

    tshark -r test.pcap -T fields -E header=y -E separator=, -E quote=d -E occurrence=f -e ip.version -e ip.hdr_len -e ip.tos -e ip.id -e ip.flags -e ip.flags.rb -e ip.flags.df -e ip.flags.mf -e ip.frag_offset -e ip.ttl -e ip.proto -e ip.checksum -e ip.src -e ip.dst -e ip.len -e ip.dsfield -e tcp.srcport -e tcp.dstport -e tcp.seq -e tcp.ack -e tcp.len -e tcp.hdr_len -e tcp.flags -e tcp.flags.fin -e tcp.flags.syn -e tcp.flags.reset -e tcp.flags.push -e tcp.flags.ack -e tcp.flags.urg -e tcp.flags.cwr -e tcp.window_size -e tcp.checksum -e tcp.urgent_pointer -e tcp.options.mss_val > output.csv
  • 分析output.csv数据

    • 按照TCP的重传理念进行分析;
    • 找到重传的数据包;

TCP抓包分析

 Python数据分析

import pandas as pd

df = pd.read_csv(r"C:\Users\lenovo\Downloads\Compressed\exp4-tshark_socket\TCPoutput.csv")
a = dict.fromkeys(df["tcp.ack"],0)

for i in range(1,len(df)):
    a[df.loc[i,"tcp.ack"]] += 1

ls = {}
count = 0
for key,value in a.items():
    if value > 3:
        ls[key] = value
        count += 1;
print(ls)
print(r"tcp_ack大于3的次数:", count)

TCP客户端

# pip3 install tqdm

import socket
import tqdm
import os

SEPARATOR = "<SEPARATOR>"
BUFFER_SIZE = 1024 # send 4096 bytes each time step
# the name of file we want to send, make sure it exists
filename = "test.mp4"
# the ip address or hostname of the server, the receiver
host = "10.1.128.75"
# the port, let's use 65432
port = 65432

# get the file size
filesize = os.path.getsize(filename)
if filesize == 0:
    print("File is empty")
    exit()
print(f"The file size is {filesize} bytes")

s = socket.socket()
print(f"[+] Connecting to {host}:{port}")
s.connect((host, port))
print("[+] Connected.")
s.send(f"{filename}{SEPARATOR}{filesize}".encode())
progress = tqdm.tqdm(range(filesize), f"Sending {filename}", unit="B", unit_scale=True, unit_divisor=1024)
with open(filename, "rb") as f:
    while True:
        # read the bytes from the file
        bytes_read = f.read(BUFFER_SIZE)
        if not bytes_read:
            # file transmitting is done
            break
        # we use sendall to assure transimission in 
        # busy networks
        s.sendall(bytes_read)
        # update the progress bar
        progress.update(len(bytes_read))
s.close()

TCP服务端

import socket
import tqdm
import os
# device's IP address
SERVER_HOST = "0.0.0.0"
SERVER_PORT = 65432
# receive 4096 bytes each time
BUFFER_SIZE = 4096
SEPARATOR = "<SEPARATOR>"

def enable_server():
    # create the server socket
    # TCP socket
    s = socket.socket()
    print(f"[*] Socket created")
    # bind the socket to our local address
    s.bind((SERVER_HOST, SERVER_PORT))
    print(f"[*] Socket binded to {SERVER_HOST}:{SERVER_PORT}")
    # enabling our server to accept connections
    # 5 here is the number of unaccepted connections that
    # the system will allow before refusing new connections
    s.listen(5)
    print(f"[*] Listening as {SERVER_HOST}:{SERVER_PORT}")

    # accept connection if there is any
    client_socket, address = s.accept() 
    # if below code is executed, that means the sender is connected
    print(f"[+] {address} is connected.")
    # receive the file infos
    # receive using client socket, not server socket
    received = client_socket.recv(BUFFER_SIZE).decode()
    filename, filesize = received.split(SEPARATOR)
    # remove absolute path if there is
    filename = os.path.basename(filename)
    # convert to integer
    filesize = int(filesize)
    # start receiving the file from the socket
    # and writing to the file stream    
    progress = tqdm.tqdm(range(filesize), f"Receiving {filename}", unit="B", unit_scale=True, unit_divisor=1024)
    with open(filename+'-recived', "wb") as f:
        while True:
            # read 1024 bytes from the socket (receive)
            bytes_read = client_socket.recv(BUFFER_SIZE)
            if not bytes_read:    
                # nothing is received
                # file transmitting is done
                print("nothing is received")
                break
            # write to the file the bytes we just received
            f.write(bytes_read)
            # update the progress bar
            progress.update(len(bytes_read))

    # close the client socket
    # client_socket.close()
    # close the server socket
    # s.close()


if __name__ == "__main__":
  enable_server()

UDP抓包分析

客户端client发送文件:

服务器servers接受文件

18个筛选信息只剩下三个,再加上wireshark上的一些特征,提取如下

tshark -r testUDP.pcap -T fields -E header=y -E separator=, -E quote=d -E occurrence=f -e ip.version -e ip.hdr_len -e ip.tos -e ip.id -e ip.flags -e ip.flags.rb -e ip.flags.df -e ip.flags.mf -e ip.frag_offset -e ip.ttl -e ip.proto -e ip.checksum -e ip.src -e ip.dst -e ip.len -e ip.dsfield  -e udp.length -e udp.stream -e udp.port -e udp.srcport -e udp.dstport -e udp.checksum > UDPoutput.csv

故障模拟后,client发送完数据后,服务器server收到的数据文件大小,跟发送的文件大小不一致,丢弃接受的数据文件,然后发消息告诉发送端client重新发送文件数据,直到服务器server检查收到的数据文件大小和发送端client发送的文件大小一致,服务器server就成功接收到文件数据了。

UDP它不属于连接型协议,因而具有资源消耗小,处理速度快的优点,所以通常音频、视频和普通数据在传送时使用UDP较多,因为它们即使偶尔丢失一两个数据包,也不会对接收结果产生太大影响。

传输层无法保证数据的可靠传输,只能通过应用层来实现了。实现的方式可以参照tcp可靠性传输的方式,只是实现不在传输层,实现转移到了应用层。

实现确认机制、重传机制、窗口确认机制。

如果你不利用linux协议栈以及上层socket机制,自己通过抓包和发包的方式去实现可靠性传输,那么必须实现如下功能:

发送:包的分片、包确认、包的重发

接收:包的调序、包的序号确认

目前有如下开源程序利用udp实现了可靠的数据传输。分别为RUDP、RTP、UDT。

UDP客户端

# pip3 install tqdm

import socket
import tqdm
import os

SEPARATOR = "<SEPARATOR>"
BUFFER_SIZE = 1024 # send 4096 bytes each time step
# the name of file we want to send, make sure it exists
filename = "test.mp4"
# the ip address or hostname of the server, the receiver
# the port, let's use 65432

addr = ("10.1.128.75",65432)

# get the file size
filesize = os.path.getsize(filename)
if filesize == 0:
    print("File is empty")
    exit()
print(f"The file size is {filesize} bytes")

s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
print(f"[+] Connecting to {addr[0]}:{addr[1]}")
              
s.sendto(f"{filename}{SEPARATOR}{filesize}".encode(),addr)
progress = tqdm.tqdm(range(filesize), f"Sending {filename}", unit="B", unit_scale=True, unit_divisor=1024)
with open(filename, "rb") as f:
    while True:
        # read the bytes from the file
        bytes_read = f.read(BUFFER_SIZE)
        if not bytes_read:
            # file transmitting is done
            break
        # we use sendto to assure transimission in 
        # busy networks
        s.sendto(bytes_read,addr)
        # update the progress bar
        progress.update(len(bytes_read))
s.close()

UDP服务端

import socket
import tqdm
import os
# device's IP address
SERVER_HOST = "0.0.0.0"
SERVER_PORT = 65432
# receive 4096 bytes each time
BUFFER_SIZE = 4096
SEPARATOR = "<SEPARATOR>"

def enable_server():
    # create the server socket
    # TCP socket
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    print(f"[*] Socket created")
    # bind the socket to our local address
    s.bind((SERVER_HOST, SERVER_PORT))
    print(f"[*] Socket binded to {SERVER_HOST}:{SERVER_PORT}")
    # receive the file infos
    # receive using client socket, not server socket
    data,addr = s.recvfrom(BUFFER_SIZE)
    received = data.decode()
    filename, filesize = received.split(SEPARATOR)
    # remove absolute path if there is
    filename = os.path.basename(filename)
    # convert to integer
    filesize = int(filesize)
    # start receiving the file from the socket
    # and writing to the file stream    
    progress = tqdm.tqdm(range(filesize), f"Receiving {filename}", unit="B", unit_scale=True, unit_divisor=1024)
    with open(filename+'-recived', "wb") as f:
        while True:
            # read 1024 bytes from the socket (receive)
            bytes_read,addr = s.recvfrom(BUFFER_SIZE)
            if not bytes_read:    
                # nothing is received
                # file transmitting is done
                print("nothing is received")
                break
            # write to the file the bytes we just received
            f.write(bytes_read)
            # update the progress bar
            progress.update(len(bytes_read))

    # close the client socket
    # client_socket.close()
    # close the server socket
    # s.close()


if __name__ == "__main__":
  enable_server()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值