实验二:传输文件

1、实验目的:

要求学生掌握Socket编程中流套接字的技术
2、实验内容:

  1. 要求学生掌握利用Socket进行编程的技术
  2. 对文件进行分割(每片256字节),分别打包传输
    1. 发送前,通过协商,发送端告诉接收端发送片数
    2. 报头为学号、姓名、本次分片在整个文件中的位置
    3. 报尾为校验和:校验和s的计算:设要发送n字节,bi为第i个字,s=(b0+b1+…+bn) mod 256
  3. 接收方进行合并
  4. 必须采用图形界面
    1. 发送端可以选择文件,本次片数
    2. 接收端显示总共的片数,目前已经接收到的文件片数,收完提示完全收到

目录

写在最前:

实验环境

软件安装教程:

软件配件工具维护:

关于我眼中的TCP和Socket

在QT中的Socket

操作方法与实验步骤

代码正文解释

实验数据记录和结果分析

附上代码:(就不教怎么配置了,根据下面文件能反推,比如类名叫啥,实在不会的就去看看qt软件,熟悉熟悉再弄)

结构如下:

TCPfile.pro

clientwidget.h

clientwidget.cpp

serverwidget.h

serverwidget.h

main.cpp

ui:

​编辑

写在最后:


写在最前:

csdn这个上传视频弄这个封面的分辨率真的是搞不来了,索性我传到b站了在主页里,自己去找吧。。

计算机-CSDN直播 不知道你们能不能看见,反正我自己可以~~

  • 实验环境

win10    +

软件安装教程:

QT从入坑到绝望_不买Huracan不改名的博客-CSDN博客

软件配件工具维护:

成功资料

库:http://mirrors.ustc.edu.cn/qtproject/online/qtsdkrepository/windows_x86/root/qt/

Qt 官网有一个专门的资源下载网站,所有的开发环境和相关工具都可以从这里下载,具体地址是:http://download.qt.io/

更新配件教程:https://blog.csdn.net/liulihuo_gyh/article/details/78583884

关于我眼中的TCP和Socket

1TCP/IP介绍

TCP/IP协议 q 传输控制/网际协议(Transfer Control Protocol/Internet Protocol) 又称作网络通讯协议

Internet国际互联网络的基础,RFC793

一组协议,通常称它为TCP/IP协议族

四个层次:网络接口层、网际层、传输层、应用层

2TCP/IP结构

3TCP传输协议

 是一种面向连接的传输层协议,它能提供高可靠性通信( 数据无误、数据无丢失、数据无失序、数据无重复到达的 通信)

 适用情况:

  1. 适合于对传输质量要求较高,以及传输大量数据的通信。
  2. 在需要可靠数据传输的场合,通常使用TCP协议
  3. MSN/QQ等即时通讯软件的用户登录账户管理相关的功能 通常采用TCP

4Socket

一个编程接口

是一种特殊的文件描述符 (everything in Unix is a file) n

并不仅限于TCP/IP协议 n

面向连接 (Transmission Control Protocol - TCP/IP) n

无连接 (User Datagram Protocol -UDP 和 Inter-network Packet Exchange - IPX)

5、在linuxC语言的使用流程

在这里我就不细讲c/c++中的使用,因为我们有QT这个框架,QT中帮助我们封装了很多socket的库,使用起来很方便。但是我还是要讲一下,在c语言中linux环境下TCP通信息的流程,因为只有知道了底层调用的一些原理,用起框架来才更加的顺手。

6、常用接口函数:

socket() 创建套接字

bind() 绑定本机地址和端口

connect() 建立连接

listen() 设置监听端口

accept() 接受TCP连接

recv(), read(), recvfrom() 数据接收

send(), write(), sendto() 数据发送

close(), shutdown() 关闭套接字

从上图可以很清楚的看到服务器和客户端的运行流程,对于客户端的bind哪一步文档上是说可以bind可以不bind,一般我们都不去将客户端bind

在这里值得注意下,对于系统编程中socket套接字都是默认阻塞的,因此accept这个函数会阻塞在哪里一直等到有客户端连接上来,还有读操作也是阻塞状态的。想要解除套接字阻塞,那就需要用到IO模型的知识了。由于没有用到,暂时就不深究了。

在QT中的Socket

我们知道tcp通信的流程是

    1)、服务器:申请套接字 -> 绑定套接字 -> 监听套接字 -> 接收连接 -> 开始发送数据接收数据

    2)、客户端:申请套接字 -> 建立连接 -> 发送数据 接收数据

而在qt中将,这些操作都被封装成在一个模块中,所以我们就没有这么复杂的操作,大致流程如下

   1)、服务器:

          1、启动服务器,即监听

               mserver.listen(QHostAddress::Any,8080)

          2、连接newConnection这个信号判断是否有客户端连接进来      

              connect(&mserver, &QTcpServer::newConnection, this, &FileRecv::new_client);

          3、创建套接字

              QTcpSocket *msocket = mserver.nextPendingConnection();

   2)、客户端

         1、初始化一个套接字对象

         2、连接connected这个信号判断是否连接成功

         3、对套接字进行读写

1.QT下的服务端

1).socket函数变为QTcpServer

2).bind ,listen 统一为listen

同时没有accept,当有一个链接过来的时候,会产生一个信号:newconnection,可以从对应的槽函数中取出建立好的套接字(对方的)QTcpSocket 如果成功和对方建立好链接,通信套接字会自动触发connected信号

3).read :

对方发送数据过来,链接的套接字(通信套接字)就会触发(本机的)readyRead信号,需要在对应的槽函数中接收数据

4).write,

发送数据,对方的(客户端的)套接字(通信套接字)就会触发readyRead信号,需要在对应的槽函数中接收数据 如果对方主动断开连接,对方的(客户端的)套接字(通信套接字)会自动触发disconnected信号。

2.QT下的客户端:

1).socket函数变为 QTcpSocket

2).connect变为connetToHost()

如果成功和对方建立好链接,就会自动触发connected信号

3).read :

对方发送数据过来,链接的套接字(通信套接字)就会触发(本机的)readyRead信号,需要在对应的槽函数中接收数据

4).write,

发送数据,对方的(服务器的)套接字(通信套接字)就会触发readyRead信号,需要在对应的槽函数中接收数据,如果对方主动断开连接,就会自动触发disconnected信号

  • 操作方法与实验步骤

代码正文解释

文件传输的图解分析如下:

1.按照流程过一遍: (演示视频)

2.客户端点击connect

触发下面的函数:   会去连接服务器

3.服务器收到连接后,会自动触发newConnection函数进入下面操作,建议连接并且

打印相关信息。

4.选择框选择文件 :触发下面的函数,打开相应的文件,做好发送准备

5.点击发送文件按钮: 发送文件头部信息,和即将发送片数等内容,经过短暂延时后开始发送数据(tcp防止粘包问题要求的操作就是如此)

6.上面定时函数触发下面的函数,倒计时结束后调用发送函数

下面是发送函数,根据先前选的报文片数,拼接报头,正文,报尾并且发送出去

7.发送方成功以后,接收方这边检测到有数据过来会自动触发readyRead函数:

根据实际情况,拿到文件头信息,或者是拿到正文数据,然后拆分出报头报尾和正文,存到自己的数据结构,然后存入到文件中,存入的文件名默认是发送过来的名字,路径是在生成的debug文件下。

其他的都是附加的针对的ui界面的设计,可以参考文件:源码文件夹,详细代码,有注释。

  • 实验数据记录和结果分析

QT中简单的emit使用:

QT中简单的emit使用_csdn_dyq111的博客-CSDN博客_qt emit

qt字符串与字符串数组操作:qt字符串与字符串数组操作_一只藤井树的博客-CSDN博客_qt 字符串数组

QString char数组转换:

QString 和char数组转换_M_Pinery的博客-CSDN博客_qstring char数组

qstring如何初始化_QString介绍:

qstring如何初始化_QString介绍_AMD中国的博客-CSDN博客

QtQfile读取文件操作:

Qt之Qfile读取文件操作_Nina_小哥的博客-CSDN博客_qfile

QT QString字符串的操作:

QT 对QString字符串的操作_Sakuya__的博客-CSDN博客_qstring 字符串反转

QByteArrayQStringString-Base64):QByteArray转QString(String-Base64)_于大博的博客-CSDN博客_qbytearray转qstring

QStringQbytearraystring的相互转换及相关问题:

QString、Qbytearray、string的相互转换及相关问题_HelloEarth_的博客-CSDN博客_string 转q'b'y't

Qt 字符串的比较和遍历:

Qt中 字符串的比较和遍历_后起乱秀的博客-CSDN博客_qt遍历字符串

QMap中的key进行自定义排序:

对QMap中的key进行自定义排序_hp_cpp的博客-CSDN博客_qmap排序

Qt 使用QInputDialog弹出输入框获取用户输入数据:

Qt 使用QInputDialog弹出输入框获取用户输入数据_Cqy_Chaos的博客-CSDN博客_qt弹窗输入

C++intstring的相互转换:

C++中int与string的相互转换_HarryLi的博客-CSDN博客_int转string c++语言

std:;remove_if用法讲解:

std:;remove_if用法讲解_KFLING的博客-CSDN博客_remove_if

Qt 整型与字符串 intQString互转:

Qt 整型与字符串 int与QString互转_秃顶吧!程序猿的博客-CSDN博客_qt 整形转qstring

Qt TCP网络编程:

Qt TCP网络编程——传输图片(附TCP连接逻辑以及完整代码)_繁星蓝雨的博客-CSDN博客_qt发送图片

附上代码:

(就不教怎么配置了,根据下面文件能反推,比如类名叫啥,实在不会的就去看看qt软件,熟悉熟悉再弄)

(好像没什么用 因为ui 的部分是没办法给的?)

结构如下:

TCPfile.pro

QT       += core gui networkgreaterThan(QT_MAJOR_VERSION, 4): QT += widgetsCONFIG += c++11# The following define makes your compiler emit warnings if you use
# any Qt feature that has been marked deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS# You can also make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0SOURCES += \clientwidget.cpp \main.cpp \serverwidget.cppHEADERS += \clientwidget.h \serverwidget.hFORMS += \clientwidget.ui \serverwidget.ui
CONFIG += C++11
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

clientwidget.h

#ifndef CLIENTWIDGET_H
#define CLIENTWIDGET_H
#include"newwindow.h"
#include <QWidget>
#include <QMap>
#include<QTcpSocket>
#include<QFile>
namespace Ui {
class clientwidget;
}class clientwidget : public QWidget
{Q_OBJECTpublic:explicit clientwidget(QWidget *parent = nullptr);~clientwidget();QString prefix="txt";QByteArray RecString;//收到的字节数int rcve;//即将收到的个数QMap<int,QString>Accept_Data;//存放所有分片的数据结构
private slots:void on_pushButton_clicked();
private:Ui::clientwidget *ui;QTcpSocket *tcpSocket;QString fileName;qint64 fileSize;qint64 receiveSize;bool isStart;QFile file;
};#endif // CLIENTWIDGET_H

clientwidget.cpp

#include "clientwidget.h"
#include "ui_clientwidget.h"
#include <QMessageBox>
#include <QHostAddress>clientwidget::clientwidget(QWidget *parent) :QWidget(parent),ui(new Ui::clientwidget)
{ui->setupUi(this);isStart = true;//代表传输的文件头tcpSocket = new QTcpSocket(this);connect(tcpSocket,&QTcpSocket::readyRead,[=]{QByteArray buf = tcpSocket->readAll();//是拿到的文件头部信息的话if(true == isStart){isStart = false;fileName = QString(buf).section("##",0,0);fileSize = QString(buf).section("##",1,1).toInt();rcve= QString(buf).section("##",2,2).toInt();receiveSize = 0;// qDebug()<<"clent接受到的文件名:"<<fileName<<fileSize<<rcve;file.setFileName(fileName);bool isOk = file.open(QIODevice::WriteOnly);if(isOk == false){qDebug()<<"只写方式打开出错";}}//如果是txt文件的话else if(fileName.contains(prefix,Qt::CaseSensitive)){QString temp=QString(buf);QStringList list = temp.split("|||", QString::SkipEmptyParts);//QString字符串分割函数int recc=0;//用来显示进度for (QList<QString>::Iterator it =  list.begin();it!=list.end(); it++){// qDebug()<<(*it);QString tt= QString(*it).section("##",2,2);//拿到中间正文数据int  pianyiliang = QString(*it).section("##",0,0).toInt();//显示进度条recc++;float f = 100.0*recc/fileSize;ui->progressBar->setValue(f);//放入自己的数据结构Accept_Data.insert(pianyiliang,tt);}// 把手里拿到的报文拼接回去QString tt="";QMapIterator<int, QString> i(Accept_Data);while(i.hasNext()) {i.next();tt+=i.value();}qDebug()<<tt;//写入文件qint64 len = file.write(tt.toUtf8());if(Accept_Data.size()==rcve) {file.close();QMessageBox::information(this,"完成","文件接收完成");qDebug()<<"收到得全部内容"<<RecString;ui->progressBar->setValue(0);tcpSocket->disconnectFromHost();tcpSocket->close();}}//其他文件else{qint64 len = file.write(buf);qDebug()<<"收到de内容"<<buf;RecString+=buf;receiveSize +=len;_sleep(5000);float f = 100.0*receiveSize/fileSize;ui->progressBar->setValue(f);if(receiveSize==fileSize) {file.close();QMessageBox::information(this,"完成","文件接收完成");qDebug()<<"收到得全部内容"<<RecString;ui->progressBar->setValue(0);tcpSocket->disconnectFromHost();tcpSocket->close();}}});
}clientwidget::~clientwidget()
{delete ui;
}/*** @brief 连接函数点击动作*/
void clientwidget::on_pushButton_clicked()
{QString ip = ui->lineEditIP->text();quint16 port = ui->lineEditPort->text().toInt();tcpSocket->connectToHost(QHostAddress(ip),port);
}

serverwidget.h

#ifndef SERVERWIDGET_H
#define SERVERWIDGET_H
#include"newwindow.h"
#include <QWidget>
#include<QTcpServer>
#include<QTcpSocket>
#include<QFile>
#include<QVector>
#include<QTimer>
#include<QDebug>
#include<string.h>
#include<string>
#include<QInputDialog>
#include <QPushButton> //Push按钮类
#include <QList> //列表类QT_BEGIN_NAMESPACE
namespace Ui { class serverWidget; }
QT_END_NAMESPACEclass serverWidget : public QWidget
{Q_OBJECTpublic:serverWidget(QWidget *parent = nullptr);int LoadFile();~serverWidget();void sendData();QString STR_Not_Cut;QVector<int>  Checksum;QVector<int>  data;QString prefix="txt";int size=100;int file_to_chose=0;QVector<QString> DATA;private slots:void on_buttonFile_clicked();void on_buttonSend_clicked();void on_pushButton_clicked();void on_pushButton_2_clicked();private:Ui::serverWidget *ui;QTcpServer *tcpServer;QTcpSocket *tcpSocket;QFile file;QString fileName;qint64 fileSize;qint64 sendSize;QTimer timer;QList<QPushButton*> btnPushlist;//动态创建按钮的列表QPushButton *btnPush;//动态创建按钮指针
public:void PRINT(){qDebug() << "拿到的所有存放在DATA:"<< "\0";for ( auto iter:DATA)qDebug()<<iter;qDebug() << DATA.size() << "\0";}};
#endif // SERVERWIDGET_H

serverwidget.h

#include "serverwidget.h"
#include "ui_serverwidget.h"
#include<QFileDialog>
#include<QDebug>
#include <string>
#include<QFileInfo>
#define flag fileName.contains(prefix,Qt::CaseInsensitive)
serverWidget::serverWidget(QWidget *parent): QWidget(parent), ui(new Ui::serverWidget)
{ui->setupUi(this);tcpServer = new QTcpServer(this);tcpServer->listen(QHostAddress::Any,8000);ui->buttonFile->setEnabled(false);ui->buttonSend  ->setEnabled(false);setWindowTitle("客户端口为:8000");connect(tcpServer,&QTcpServer::newConnection,[=]{tcpSocket = tcpServer->nextPendingConnection();QString ip = tcpSocket->peerAddress().toString();quint16 port = tcpSocket->peerPort();QString str = QString("[%1:%2]成功连接").arg(ip).arg(port);ui->textEdit->setText(str);ui->buttonFile->setEnabled(true);ui->buttonSend->setEnabled(true);});connect(&timer,&QTimer::timeout,[=]{timer.stop();sendData();});
}serverWidget::~serverWidget()
{delete ui;}/*** @brief 装载数据 同时拿到校验和*/
int serverWidget::LoadFile()
{qint64 len = 0;QByteArray buf;do{len = 0;buf=file.read(256);if(buf.size()!=0)DATA.push_back(buf);}while(buf.size()>0);int sum=0;for(int i=0;i<DATA.size();i++){for (QChar *it=DATA[i].begin(); it!=DATA[i].end(); ++it) {sum+=(int)(*it).toLatin1();}Checksum.push_back(sum%256);}return 0;
}/*** @brief 当选择文件按钮被点击以后的动作
*/
void serverWidget::on_buttonFile_clicked()
{QString filePath = QFileDialog::getOpenFileName(this,"open","../");if(!filePath.isEmpty()){fileName.clear();fileSize = 0;QFileInfo info(filePath);fileName = info.fileName();fileSize = info.size();qDebug()<<"从 文件筐拿到的文件信息<"<<fileName<<fileSize;sendSize = 0;file.setFileName(filePath);bool isOk = file.open(QIODevice::ReadOnly);if(isOk == false){qDebug()<<"只读方式打开文件失败了";}ui->textEdit->setText(filePath);ui->buttonFile->setEnabled(false);ui->buttonSend->setEnabled(true);}else{qDebug() << "选择文件出错 62";}//加载数据if(fileName.contains(prefix,Qt::CaseInsensitive)){LoadFile();}//creat();}/*** @brief 发送按钮被点击以后的动作*/
void serverWidget::on_buttonSend_clicked()
{//告诉他要发送的片数QString head = QString("%1##%2##%3").arg(fileName).arg(fileSize).arg(data.size());qint64 len = tcpSocket->write(head.toUtf8());if(len>0){timer.start(30);}else{qDebug()<<"头部信息发送失败";file.close();ui->buttonFile->setEnabled(true);ui->buttonSend->setEnabled(false);}
}void serverWidget::sendData()
{//确实到了发送的时机if(flag){//std::string stm;QString stm;//QByteArray stm;for(int i=0;i<data.size();i++){_sleep(500);QString head = QString("%1##%2##%3##%4").arg(QString::number(data[i])).arg(QString("162040210-zhangtutu")).arg(DATA[i]).arg(QString::number(Checksum[i]));head+="|||";QByteArray sendMessage = head.toUtf8();tcpSocket->write(sendMessage);// tcpSocket->waitForBytesWritten();}}//其他命令状态操作else{qint64 len = 0;do{char buf[1024] = {0};len = 0;len = file.read(buf,sizeof(buf));len = tcpSocket->write(buf,len);sendSize += len;}while(len>0);if(sendSize == fileSize){ui->textEdit->append("文件发送完毕");file.close();tcpSocket->disconnectFromHost();tcpSocket->close();}}
}
//全选
void serverWidget::on_pushButton_clicked()
{for(int i=0;i<DATA.size();i++){data.push_back(i);}ui->textEdit->setText("选中全部的报文成功!\n");
}//选择一次片数
void serverWidget::on_pushButton_2_clicked()
{bool bOk = false;int dbWeight = QInputDialog::getInt(this,"QInputDialog_Weight","最大值"+QString::number(DATA.size()),1,       //默认值-1,            //最小值DATA.size(),       //最大值2,         //步长&bOk);if (bOk && dbWeight > -1) {data.push_back(dbWeight);}}

main.cpp

#include "serverwidget.h"
#include "clientwidget.h"
#include <QApplication>int main(int argc, char *argv[])
{QApplication a(argc, argv);serverWidget w;w.show();clientwidget w1;w1.show();return a.exec();
}

ui:

写在最后:

写这个题目真的是百感交集,也可谓是一波三折。

我原来的思路是: @1 写好文件传输的终端下的demo(也就是上文提到的linux中的通信模式一样)@2 尝试内嵌一点图形化界面或者交互已完成题目要求。

结果做到后面发现,想要做一个图形化的交互界面可以用:qt c# 或者是py

但是无论是上面那一种他们都有自己的socket套接字通讯函数(或者准确的来说,烦着呢个qt是肯定有自己的封装的函数,具体参见上文提到的“qttocket”),qt是基于c++的,不是说自己原来写的函数不行。 但就是违背了qt本身自带Socket函数这一方便性。所以尝试把原来的代码嵌入到qt中。从c转变成c++。图方便就全部public了。于是就这样跑去验收,然后被痛批,发现只能传txtdocxpng。反正不行。

跑回来慢慢改,直接全部推倒重来,全部基于qt实现,采用qt下的Socket通讯函数,Qt与原来通讯函数的区别:见上文。采用Qt下的QStringQByteArray存放信息,渐渐也知道了原来失败的原因,由于Qt编译器和本身自带的环境的编码格式可能存在差异,就会导致非acill码的部分出现解析失败,自然传过去的信息就是错误的。

到目前我写下这篇文章开始,我已经全部实现了要求的全部功能,并且可以正确的传输,不经感叹,计算机的神奇,qt的图形强大,未统一编码格式的痛苦。

在这里真的要首先感谢xxx老师对于知识的传授,为我成功实现实验6打下了坚定的基础;其次是负责验收的不知道姓名的助教学长,(其实对于本身强迫症的我来说,一开始验收的版本本就是qtc的杂糅版本,不太符合我自己的预期,恰好验收未通过),给予我推到重来的动力,完成了目前让我满意的版本;最终也要感谢所有在这次实验中帮助过我了学长学姐和同学以及从未放弃的自己!最后以一句诗结尾吧:千磨万击还坚劲,任尔东西南北风!

官方话术结束:开始真正的心里话: (服务端称之为s端,客户端成为c端)

被这个实验差点搞破防,直接说结论吧,少废话,这个代码的s端和c端是反过来的,有没有发现,直接也就是说:c端找s端建立连接后,s端发送文件给c端.......

另外:针对txt和非txt我做的特殊的处理

txt部分:是可以 片头 报头 正文 报尾 拆分的 然后对应的接受度端(在我代码里是c端)是可以去掉 片头 报头 报尾的,拿到的正文放到了map中(第一个元素是 本次的片数,第二个元素是正文)

非txt部分:读一个 字符就写一个字符,不存在分片处理。(真写不出来了,那个编码问题搞得我直接破防了。)

作为个define处理以防止被看出来。。。。。。。。。。。。。

想要源码或者需要讲解的话:就先找我私聊吧,其实按照文件内容能推算出应该进行的设置。

只求问的时候客气点、礼貌点就行。最后祝学妹学弟们愉快度过这个难题!!!

NUAA-泛在网实验-实验六相关推荐

  1. 域名解析和内网穿透实验

    MQTT相关实验 第一节:Mosquitto 相关实验 第二节:域名解析和内网穿透实验 第三节:OneNET 相关实验 Gitee仓库地址: https://gitee.com/zhj0125/MQT ...

  2. 虚拟实验工场大学计算机实验报告答案,虚拟实验实验报告 - 实验报告 - 书业网.doc...

    虚拟实验实验报告 - 实验报告 - 书业网 虚拟实验实验报告 - 实验报告 - 书业网 篇一:虚拟实验报告 第一章 文献综述 1.1 丙酮酸脱氢酶概述 丙酮酸脱氢酶复合体(Pyruvate Dehyd ...

  3. Secret-Key Encryption Lab网安实验

    Secret-Key Encryption Lab网安实验 实验站点 文章目录 Secret-Key Encryption Lab网安实验 Task 1: Frequency Analysis Aga ...

  4. Mininet系列实验(六):Mininet动态改变转发规则实验

    Mininet系列实验(六):Mininet动态改变转发规则实验 一. 实验目的 熟悉Mininet自定义拓扑脚本的编写: 熟悉编写POX脚本动态改变转发规则 二.实验原理 在SDN环境中,控制器可以 ...

  5. SDN实验(六)——SDN流量监控

    SDN实验(六)--SDN流量监控 一.流量监控原理 二.代码实现 (一)代码 (二)讲解 三.实验演示 (一)开启Ryu (二)开启Mininet (三)Ryu显示结果 四.扩展 一.流量监控原理 ...

  6. oracle空间数据库实验报告,Oracle数据库实验报告六 PL/SQL基础

    Oracle数据库实验报告六 PL/SQL基础 -by QQC from BTBU [实验目的] PL/SQL的安装网上有很多教程这里就不做赘述了,如果后序需求大的话我再考虑做一期PL/SQL安装使用 ...

  7. 计算机科学导论实验(六)

    计算机科学导论实验 --实验六 简单的卡通与游戏实验 文章目录 计算机科学导论实验 --实验六 简单的卡通与游戏实验 前言 一.实验目的 二.实验内容 1.引入库 三.实验总结 前言 终于到最后的实验 ...

  8. 计算机组成原理实验 第六章,计算机组成原理实验

    第一部分 数字电路基础 第一章 基本逻辑关系和基本逻辑门电路 第一节 基本逻辑关系和基本逻辑门电路概述 第二节 复合逻辑门 第三节 OC门和三态输出门 第二章 逻辑代数基础 第一节 逻辑代数的基本关系 ...

  9. 北邮计算机网络dns实验报告,北邮计网实践实验报告范文

    计算机网络技术是一门需要动手实践才能真正掌握知识的学科,多参加实践,多动手,可以学到更多知识.下面是爱汇网小编为大家整理的北邮计网实践实验报告范文,供大家阅读! 北邮计网实践实验报告范文篇1 开学第一 ...

  10. 南京邮电大学C语言实验报告六

    实验六:结构体与文件实验 实验题目(1)[见实验教材实验八的题目3]:编写程序exp8_3.c,验证用户输入的日期格式是否正确,如果不正确,则提示重新输入,直到重新输入正确为止.(提示:需要定义一个表 ...

最新文章

  1. mysql 安装dso命令_LAMP环境搭建
  2. 三基站定位几何精度因子的简便运算
  3. 拦截器读post参数导致接口post请求报错_vue中Axios的封装和API接口的管理
  4. mysql 报错解决思考Expression #5 of SELECT list is not in GROUP BY clause and contains nonaggregated column
  5. 4.1 Spark SQL概述
  6. sklearn中的naive bayes算法
  7. 抓包工具charles青花瓷的基本使用(android)
  8. JS判断数组是否相同
  9. 2021年与 Linux 有关的几件大事
  10. 分析QQ和QQ游戏的价值特性极其快速发展的原因,并对其盈利模式进行探讨
  11. 避坑指南:Kafka集群快速扩容的方案总结
  12. 手写基于redis实现分布式限流器-pdlr
  13. BUUCTF-Misc-No.4
  14. Linux下的常用的打包和解压缩命令
  15. python实现api接口
  16. 用计算机弹我的一个道故朋友,我的一个道姑朋友
  17. 日期控件My97的时间限制
  18. 新书出版发布会发言稿_我从发布会议发言人调查中学到的东西
  19. 邮件接收中Postfix、Dovecot、Squirrelmail、MySQL、AMaVis、Clam AntiVirus和SpamAssasin的功能解析
  20. Java通过selenium+ashot对网页进行长截屏

热门文章

  1. 微信小程序 音乐播放代码(播放方式,歌词滚动) (更新优化版:添加文字颜色过渡)
  2. 计算机系统遗传学,中国象棋计算机博弈系统评估函数自适应遗传算法[转]
  3. ThinkPad开启、禁用触摸板
  4. First Order Methods in Optimization Ch5. Smoothness and Strong Convexity
  5. 半岛电视台网络遭多次网络攻击
  6. new date的含义
  7. IDEA 中如何完成 Git 版本回退?
  8. 炫龙银魂t1配置_高配好用不贵炫龙银魂T1让你体验到真正性价比
  9. django -- url映射
  10. linux定时情况root mail,Linux_Linux系统下mail命令使用,我经常用root帐号登录RHEL5,在 - phpStudy...