目录
虚拟机下载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()