虚拟机和宿主机通过socket通信【C4】

关键词:随机森林,SDN,网络流量
环境:VMware Workstation Pro ,pycharm64,py3,mininet,ryu,ubuntu,linux,wireShark

场景一:虚拟机和宿主机通过socket通信,传送packet_in消息

指令步骤

1.运行服务端
在这里插入图片描述
2.运行客户端

ryu-manager C4client.py

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
3.启动拓扑文件
在这里插入图片描述
在这里插入图片描述
此时可以看得到客户端解读的packetin数据包信息
在这里插入图片描述

场景二:h1访问视频网站,tcpdump抓包并分析

刚刚一切设置不动

mininet-开启h1独立窗口

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
将127.0.0.53改为8.8.8.8,保存后关闭

切换用户

su  【用户名】

访问谷歌浏览器

google-chrom

打开bilibili,点开一个视频
在这里插入图片描述
在这里插入图片描述
bilibili 所用为UDP协议,验证成功
在这里插入图片描述

场景三:抓取视频流与下载流并训练机器学习模型并验证

数据集

使用wireShark抓包并选取特征值,保存为.csv文件
在这里插入图片描述
在这里插入图片描述

数据可视化

五种图预览数据分布范围和异常值
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

训练模型

模型训练后保存为.pk1文件
在这里插入图片描述

验证模型正确性

简单输出预测结果。
在这里插入图片描述

在这里插入图片描述

代码部分

虚拟机-topo-代码

位置:mininet/mininet/examples CCCTopo.py
此topo已开启交换机网桥,交换机可以直接访问互联网

#!/usr/bin/python
import re
import sys
from mininet.cli import CLI
from mininet.log import setLogLevel, info, error
from mininet.net import Mininet
from mininet.link import Intf
from mininet.topolib import TreeTopo
from mininet.util import quietRun
from mininet.node import OVSSwitch, OVSController, Controller, RemoteController
from mininet.topo import Topo
class MyTopo( Topo ):
#    "this topo is used for Scheme_1"
    
    def __init__( self ):
        "Create custom topo."
 
        # Initialize topology
        Topo.__init__( self )
 
        # Add hosts 
        h1 = self.addHost( 'h1' , ip="10.0.0.1/24", mac="00:00:00:00:00:01", defaultRoute="via 10.0.0.254")
        h2 = self.addHost( 'h2' , ip="10.0.0.2/24", mac="00:00:00:00:00:02", defaultRoute="via 10.0.0.254")
        h3 = self.addHost( 'h3' , ip="10.0.0.3/24", mac="00:00:00:00:00:03", defaultRoute="via 10.0.0.254")
        h4 = self.addHost( 'h4' , ip="10.0.0.4/24", mac="00:00:00:00:00:04", defaultRoute="via 10.0.0.254")
        
        # Add switches
        s1 = self.addSwitch( 's1' )
        s2 = self.addSwitch( 's2' )
        s3 = self.addSwitch( 's3' )
 
        # Add links
        self.addLink( s1, s2 )
        self.addLink( s1, s3 )
        self.addLink( s2, h1 )
        self.addLink( s2, h2 )
        self.addLink( s3, h3 )
        self.addLink( s3, h4 )
  # 
def checkIntf( intf ):
    "Make sure intf exists and is not configured."
    if ( ' %s:' % intf ) not in quietRun( 'ip link show' ):
        error( 'Error:', intf, 'does not exist!\n' )
        exit( 1 )
    ips = re.findall( r'\d+\.\d+\.\d+\.\d+', quietRun( 'ifconfig ' + intf ) )
    if ips:
        error( 'Error:', intf, 'has an IP address,'
               'and is probably in use!\n' )
        exit( 1 )
 
if __name__ == '__main__':
    setLogLevel( 'info' )
 
    # try to get hw intf from the command line; by default, use eth1
    intfName = sys.argv[ 1 ] if len( sys.argv ) > 1 else 'ens38'
    info( '*** Connecting to hw intf: %s' % intfName )
 
    info( '*** Checking', intfName, '\n' )
    checkIntf( intfName )
 
    info( '*** Creating network\n' )
    net = Mininet( topo=MyTopo(),controller=None) 
    #
    switch = net.switches[ 0 ] # 
    info( '*** Adding hardware interface', intfName, 'to switch', switch.name, '\n' )
    _intf = Intf( intfName, node=switch )
     # 
 
    info( '*** Note: you may need to reconfigure the interfaces for '
          'the Mininet hosts:\n', net.hosts, '\n' )
    c0 = RemoteController( 'c0', ip='127.0.0.1', port=6653 )  # 
    net.addController(c0)
    net.start()
    CLI( net )
    net.stop()
topos = {'mytopo':(lambda:MyTopo())}

虚拟机-客户端-代码

位置:ryu/ryu/app C4client.py

from operator import attrgetter
from ryu.app import simple_switch_13
from ryu.controller import ofp_event
from ryu.controller.handler import MAIN_DISPATCHER, DEAD_DISPATCHER, CONFIG_DISPATCHER
from ryu.controller.handler import set_ev_cls
import array
from ryu.lib import hub
from ryu.lib.packet import packet
from ryu.base import app_manager
from ryu.ofproto import ofproto_v1_3
from ryu.controller.handler import MAIN_DISPATCHER
from ctypes.wintypes import BYTE
import socket


class MyMonitor13(simple_switch_13.SimpleSwitch13, app_manager.RyuApp):
    OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION]

    def __init__(self, *args, **kwargs):  # 初始化函数
        super(MyMonitor13, self).__init__(*args, **kwargs)
        self.dp_id = '0'
        self.in_port = '0'

        # 开启client,并连接server
        self.client1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        dst_host = '192.168.203.1'
        dst_port = 12306

        # 防止server端连接不上影响hub的使用
        try:
            self.client1.connect((dst_host, dst_port))
        except Exception as error:
            print('Connect error:', error)

    def doflow(self, datapath, command, priority, match, actions):
        ofp = datapath.ofproto
        ofp_parser = datapath.ofproto_parser
        inst = [ofp_parser.OFPInstructionActions(ofp.OFPIT_APPLY_ACTIONS, actions)]
        req = ofp_parser.OFPFlowMod(datapath=datapath, command=command,
                                    priority=priority, match=match, instructions=inst)
        datapath.send_msg(req)

    # 控制器和交换机握手时,向交换机下发默认流表项
    @set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER)
    def switch_features_handler(self, ev):
        msg = ev.msg
        datapath = msg.datapath
        ofp = datapath.ofproto
        ofp_parser = datapath.ofproto_parser

        # add table-miss
        command = ofp.OFPFC_ADD
        match = ofp_parser.OFPMatch()
        actions = [ofp_parser.OFPActionOutput(ofp.OFPP_CONTROLLER, ofp.OFPCML_NO_BUFFER)]
        self.doflow(datapath, command, 0, match, actions)

    @set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER)
    def packet_in_handler(self, ev):
        msg = ev.msg
        dp = msg.datapath
        ofp = dp.ofproto
        ofp_parser = dp.ofproto_parser
        self.dp_id = dp.id

        # 计算出in_port
        start = str(msg).index('oxm_fields') + 11
        end = str(msg).index('),reason')
        inport_str = str(msg)[start:end]
        instr = eval(inport_str)
        self.in_port = instr['in_port']

        actions = [ofp_parser.OFPActionOutput(ofp.OFPP_FLOOD)]

        data = None
        if msg.buffer_id == ofp.OFP_NO_BUFFER:
            data = msg.data
        print('id:{0}     in_port:{1}'.format(self.dp_id, self.in_port))
        # 每次有信息经过交换机时,控制器就将获取的dpid和port发送给server
        # info = str(self.dp_id) + ',' + str(self.in_port)

        pkt = packet.Packet(array.array('B', msg.data))
        # 几种协议
        plist = []
        for p in pkt.protocols:
            print('received protocol data:', p)
            plist.append(p)

        info = str(len(data)) + ',' + str(self.in_port) 
        self.client1.send(info.encode())

        out = ofp_parser.OFPPacketOut(
            datapath=dp, buffer_id=msg.buffer_id, in_port=self.in_port,
            actions=actions, data=data)
        dp.send_msg(out)

宿主机-服务端-代码

server.py
host为宿主机IP地址
可通过cmd指令ipconfig查询,本机为192.168.203.1

import socket
import re


def main():
    server1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  # TCP

    host = '192.168.203.1'
    port = 12306
    server1.bind((host, port))
    print('server  lunching  .  .  .  ')
    server1.listen(5)
    while True:
        conn, addr = server1.accept()
        print("----------------------------")
        print("Success connect from ", addr)
        try:
            count = 0
            while True:
                data = conn.recv(1024)
                data = re.split(r'[, :]', data.decode('utf-8'))  # 对收到的信息进行解析,包括dpid和port
                count += 1
                print("from {0}:length={1}, in_port={2}".format(addr, data[0], data[1]))
            conn.close()
        except Exception as error:  # 当控制器和应用层断开连接后,输出统计信息
            print('共接收{}条信息。'.format(count - 1))
            print(error)
            exit()


if __name__ == '__main__':
    main()

随机森林-训练-代码

import joblib
import pandas as pd
from sklearn.metrics import accuracy_score, classification_report
from sklearn.preprocessing import StandardScaler
import matplotlib as mpl
import warnings
import numpy as np
from sklearn.model_selection import cross_val_score
from sklearn.datasets import make_blobs
from sklearn.ensemble import ExtraTreesClassifier, RandomForestClassifier
from sklearn.tree import DecisionTreeClassifier, export_graphviz
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split

# 读取数据
data = pd.read_csv('D:/data.csv')
print(data.head())
# 数据可视化
# 直方图
data.hist()
plt.show()
# 密度图
data.plot(kind='density', subplots=True, layout=(3, 3), sharex=False)
plt.show()
# 箱线图
data.plot(kind='box', subplots=True, layout=(3, 3), sharex=False)
plt.show()
# 相关矩阵图
correlations = data.corr()
fig = plt.figure()
ax = fig.add_subplot(111)
cax = ax.matshow(correlations, vmin=-1, vmax=1)
fig.colorbar(cax)  # 颜色柱
ticks = np.arange(0, 9, 1)
plt.show()
# 散点矩阵图
pd.plotting.scatter_matrix(data)
plt.show()

# 提取自变量和因变量
X = data.iloc[:, :-1].values
y = data.iloc[:, -1].values
# 实现标准化
scaler = StandardScaler()  # 实例化
scaler.fit(X)
print('查看每列均值的属性mean_:', scaler.mean_)  # 查看每列均值的属性mean_
print('查看每列方差属性var_:', scaler.var_)  # 查看每列方差属性var_
x = scaler.transform(X)
# train_test_split方法:将样本集合划分为训练集和测试集
random_state = 1  # 随机数种子
test_size = 0.2  # 若在0~1之间,为测试集样本数目与原始样本数目之比;若为整数,则是测试集样本的数目
x_train, x_test, y_train, y_test = train_test_split(x, y, random_state=random_state, test_size=test_size)
# print('x_train:', x_train)
print('x_test:', x_test)
# print('y_train:', y_train)
# print('y_test:', y_test)
# 随机森林分类类RandomForestClassifier
n_estimators = 100  # 森林中决策树的数目
max_features = 0.4  # 寻找最佳分割时需要考虑的特征数目(百分比)
max_dep = 10  # 决策树的最大深度
min_samples_split = 2  # 分割内部节点所需要的最小样本数量
bootstrap = True  # 建立决策树时,是否使用有放回抽样
clf = RandomForestClassifier(n_estimators=n_estimators, max_features=max_features, max_depth=max_dep,
                             min_samples_split=min_samples_split, bootstrap=bootstrap)
# 交叉检验
estimator = clf  # 估计器,也就是模型
verbose = 2  # 日志冗长度:int:冗长度,0:不输出训练过程,1:偶尔输出,>1:对每个子模型都输出
scores2 = cross_val_score(estimator, x_train, y_train, cv=10, verbose=verbose)
print('交叉检验得分:', scores2)
print('RandomForestClassifier交叉验证准确率为:%.4f' % scores2.mean())

# 预测数据集
clf.fit(x_train, y_train)
y_p = clf.predict(x_test)
print('预测值:', y_p)
print('准确率:', accuracy_score(y_test, y_p))
print("其他指标:\n", classification_report(y_test, y_p, target_names=['0', '1']))

joblib.dump(clf, 'D:/C4_RF.pk1')

随机森林-验证-代码

# 提取自变量和因变量
import joblib
from sklearn.preprocessing import StandardScaler

# X = [1099.78, 679, 699.7, 54, ]
X = [[948.69, 106, 112.7, 54, 1466, 647.711, 3.149191, 4.21835],
     [960.16, 255, 266.4, 54, 1466, 670.822, 0.03011, 0.003753],
     [1038.46, 3238, 3118.2, 54, 1506, 678.776, 0.000721, 0.00032],
     [995.66, 2202, 2212, 54, 1506, 692.776, 0.000993, 0.000452]]
# 实现标准化
scaler = StandardScaler()  # 实例化
scaler.fit(X)
x = scaler.transform(X)
estimator = joblib.load("D:/C4_RF.pk1")
y_predict = estimator.predict(x)
print('检测结果为:', y_predict)

总结

原计划:
1.离线状态下训练随机森林算法,生成分类识别模型
2.利用ryu控制器自定义客户端文件获取h1上网时流量的各项特征值
3.传送到服务端,显示分类结果
遇到的问题与反思:
1.原计划中随机森林训练已完成,socket通信已完成
2.h1上网已实现
3.h1上网时能成功采集packetin消息并解析
4.解析packetin数据包后发现并不是我们想要的h1浏览视频得到的下载数据包!!!
5.摆烂
6.发现利用tcpdump可以抓取数据包,也是我们想要的
7.统计特征值后发现mininet自动将分割开的数据包合成一个,与我们wireshark抓取的形态不一样!!!
8.摆烂
9.直接在外部宿主机抓包并统计,验证结果良好符合预期
10.赶紧结束,提交作品
11.以上遇到的问题留到以后再解决吧~~

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

HAL9000pp

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值