1 概述
Kermit文件运输协议提供了一条从大型计算机下载文件到微机的途径。它已被用于进行公用数据传输。
 其特性如下:
- Kermit文件运输协议是一个半双工的通信协议。
- 它支持7位ASCII字符。
- 数据以可多达96字节长度的可变长度的分组形式传输。
- 对每个被传送分组需要一个确认。
- Kermit文件运输协议在每次会话中可以传送多个文件。
本文利用C++实现Kermit协议,并利用Qt串口类QSerialPort实现数据读写。
2 概要设计
2.1 类图

类型说明:
- Kermit 实现了Kermit协议。
- KermitSendFile 实现Kermit协议发送文件。
- KermitRecvFile 实现Kermit协议接收文件。
- KermitFileSender 实现在线程中异步发送文件。
- KermitFileRecver 实现在线程中异步接收文件。
2.3 模块
整个代码分为5个模块.
2.3.1 Kermit
该模块定义和实现了Kermit类型。
 Kermit类型是纯虚类型,其派生类需要实现下面三个虚函数:
- write 向串口写数据
- read 从串口读数据
- getc 从串口读取一个字符
文件列表:
- kermit.h
- kermit.cpp
2.3.2 KermitSendFile
该模块定义和实现了KermitSendFile类型。
 KermitSendFile从Kermit派生,实现类三个读写接口:
- write
- read
- getc
重新实现如下接口:
- on_ack
- on_nack
- on_error
文件列表:
- kermitsendfile.h
- kermitsendfile.cpp
2.3.3 KermitRecvFile
该模块定义和实现了KermitRecvFile类型。
 KermitRecvFile从Kermit派生,实现类三个读写接口:
- write
- read
- getc
重新实现如下接口:
- on_init
- on_data
- on_break
文件列表:
- kermitrecvfile.h
- kermitrecvfile.cpp
2.3.4 KermitFileSender
该模块定义和实现了KermitFileSender类型。
 KermitSendFile发送文件是同步操作,KermitFileSender将发送文件操作放入线程中实现异步调用。
文件列表:
- kermitfilesender.h
- kermitfilesender.cpp
2.3.5 KermitFileRecver
该模块定义和实现了KermitFileRecver类型。
 KermitRecvFile接收文件是同步操作,KermitFileRecver将接收文件操作放入线程中实现异步调用。
文件列表:
- kermitfilerecver.h
- kermitfilerecver.cpp
使用
发送文件
void SerialPortWidget::sendFileByKermit(QString const& fileName)
{
    QObject::disconnect(serial, SIGNAL(readyRead()), this, SLOT(onData()));
    FileProgressDialog dialog(this);
    KermitFileSender sender(serial);
    connect(&sender, &KermitFileSender::gotFileSize, &dialog, &FileProgressDialog::setFileSize);
    connect(&sender, &KermitFileSender::progressInfo, &dialog, &FileProgressDialog::setProgressInfo);
    connect(&sender, &KermitFileSender::finished, &dialog, &FileProgressDialog::finished);
    connect(&sender, &KermitFileSender::error, &dialog, &FileProgressDialog::error);
    dialog.setTitle(tr("Kermit Send"));
    dialog.setProtocol("Kermit");
    dialog.setFilename(QFileInfo(fileName).fileName());
    dialog.setModal(true);
    dialog.setVisible(true);
    sender.start(fileName);
    while(!dialog.isFinished())
    {
        if(dialog.isCancel())
        {
            sender.stop();
            while(!dialog.isFinished())
                QApplication::processEvents();
            sender.cancel();
        }
        QApplication::processEvents();
    }
    connect(serial, SIGNAL(readyRead()), this, SLOT(onData()));
}
接收文件
void SerialPortWidget::recvFileByKermit(QString const& fileName)
{
    QObject::disconnect(serial, SIGNAL(readyRead()), this, SLOT(onData()));
    FileProgressDialog dialog(this);
    KermitFileRecver recver(serial);
    connect(&recver, &KermitFileRecver::gotFileSize, &dialog, &FileProgressDialog::setFileSize);
    connect(&recver, &KermitFileRecver::progressInfo, &dialog, &FileProgressDialog::setProgressInfo);
    connect(&recver, &KermitFileRecver::finished, &dialog, &FileProgressDialog::finished);
    connect(&recver, &KermitFileRecver::error, &dialog, &FileProgressDialog::error);
    dialog.setTitle(tr("Kermit Recv"));
    dialog.setProtocol("Kermit");
    dialog.setFilename(QFileInfo(fileName).fileName());
    dialog.setModal(true);
    dialog.setVisible(true);
    recver.start(fileName);
    while(!dialog.isFinished())
    {
        if(dialog.isCancel())
        {
            recver.stop();
            while(!dialog.isFinished())
                QApplication::processEvents();
            recver.cancel();
        }
        QApplication::processEvents();
    }
    connect(serial, SIGNAL(readyRead()), this, SLOT(onData()));
}
未完待续…



















