// Chat and file Transceiver
// Author : Zouxy
// Date : 2013-6-20
// HomePage : http://blog.csdn.net/zouxy09
// Email : zouxy09@qq.com
#include "MainWindow.h"
#include "ui_MainWindow.h"
#include <QFileDialog>
#include <QObject>
#include <QMessageBox>
#include <QTextCodec>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
/********** Send and receive message though UCP protocol **************/
UdpSender = new QUdpSocket(this);
UdpReader = new QUdpSocket(this);
// 将UdpReader绑定到广播地址的6666端口,接收发到这个端口的信息
UdpReader->bind(6666, QUdpSocket::ShareAddress);
connect(UdpReader, SIGNAL(readyRead()), this, SLOT(readMessage()));
/********** Send and receive files though TCP protocol **************/
loadSize = 4*1024; //将整个大的文件分成很多小的部分进行发送,每部分为4字节
totalBytes = 0;
bytesWritten = 0;
bytesToWrite = 0;
bytesReceived = 0;
fileNameSize = 0;
tcpServer = new QTcpServer(this);
tcpSocket = new QTcpSocket(this);
//当发现新连接时发出newConnection()信号
connect(tcpServer, SIGNAL(newConnection()), this, SLOT(acceptConnection()));
ui->sendFileButton->setEnabled(false); //开始使”发送文件“按钮不可用
ui->sendMesButton->setEnabled(true); //开始使”发送信息“按钮可用
// 服务器的缺省值
hostIP = getHostIP();
if (hostIP == 0)
ui->hostLineEdit->setText("127.0.0.1");
else
ui->hostLineEdit->setText(hostIP);
ui->portLineEdit->setText("5555");
helpDialog = new Dialog;
helpDialog->hide();
histroyMessageDialog = new hisMesDialog;
histroyMessageDialog->hide();
historyMessage = new QFile("historyMessage.txt");
if(!historyMessage->open(QFile::Append))
{
qDebug() << "writing history Message file error!";
return;
}
}
MainWindow::~MainWindow()
{
delete ui;
}
// 监听
void MainWindow::listening()
{
//初始化已发送字节为0
bytesWritten = 0;
bytesReceived = 0;
blockSize = 0; //初始化其为0
ui->listenButton->setEnabled(false);
if(!tcpServer->listen(QHostAddress::LocalHost, ui->portLineEdit->text().toInt()))
{
qDebug() << tcpServer->errorString();
close();
return;
}
ui->currentStatusLabel->setText("Status: listening...");
}
// 连接后的对话框提示
void MainWindow::acceptConnection()
{
//QMessageBox box_success;
//box_success.information(NULL, "提示", "会话建立成功", QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
tcpSocket = tcpServer->nextPendingConnection();
// 当有数据发送成功时,我们更新进度条
connect(tcpSocket, SIGNAL(bytesWritten(qint64)), this, SLOT(updateClientProgress(qint64)));
// 当有数据接收成功时,我们更新进度条
connect(tcpSocket, SIGNAL(readyRead()), this, SLOT(updateServerProgress()));
// 绑定错误处理
connect(tcpSocket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(displayError(QAbstractSocket::SocketError)));
tcpServer->close();
ui->currentStatusLabel->setText("Status: Waiting for file transfer...");
}
// 发送信息
void MainWindow::sendMessage()
{
localMessage = ui->inputTextEdit->toPlainText();
QByteArray datagram = localMessage.toUtf8();
//进行UDP数据报(datagrams)的发送
UdpSender->writeDatagram(datagram.data(), datagram.size(), QHostAddress::Broadcast, 5566);
// 显示消息
showMessage(true);
}
// 接收信息
void MainWindow::readMessage()
{
//拥有等待的数据报
while(UdpReader->hasPendingDatagrams())
{
QByteArray datagram; //拥于存放接收的数据报
//让datagram的大小为等待处理的数据报的大小,这样才能接收到完整的数据
datagram.resize(UdpReader->pendingDatagramSize());
//接收数据报,将其存放到datagram中
UdpReader->readDatagram(datagram.data(), datagram.size());
//将数据报内容显示出来
serverMessage = datagram;
}
// 显示消息
showMessage(false);
}
// 显示消息
void MainWindow::showMessage(bool isSend)
{
QDateTime time = QDateTime::currentDateTime(); //获取系统现在的时间
QString str = time.toString("hh:mm:ss ddd"); //设置显示格式
QString str4file = time.toString("yyyy-MM-dd hh:mm:ss"); //设置显示格式
blockSize = 0;
QFont font;
font.setPixelSize(18);
ui->textBrowser->setFont(font);
QTextStream stream(historyMessage);
if (isSend)
{
// 用不同的颜色显示信息所属和当前时间
ui->textBrowser->setTextColor(QColor(0, 0, 0));
QString entraMess = "I say: " + str;
ui->textBrowser->append(entraMess);
stream<<"I say: "<<str4file<<"\n"; // 写入 历史信息 文件时需要保存日期
ui->textBrowser->setTextColor(QColor(0, 0, 255));
ui->textBrowser->append(localMessage);
ui->inputTextEdit->clear();
ui->currentStatusLabel->setText("Status: send message successfully...");
stream<<localMessage<<"\n";
}
else
{
// 用不同的颜色显示信息所属和当前时间
ui->textBrowser->setTextColor(QColor(0, 0, 0));
QString entraMess = "He/she: " + str;
ui->textBrowser->append(entraMess);
stream<<"He/she: "<<str4file<<"\n";
ui->textBrowser->setTextColor(QColor(255, 0, 0));
ui->textBrowser->append(serverMessage);
ui->currentStatusLabel->setText("Status: new message coming...");
stream<<localMessage<<"\n";
}
}
// 打开文件
void MainWindow::openFile()
{
fileName = QFileDialog::getOpenFileName(this);
if(!fileName.isEmpty())
{
ui->sendFileButton->setEnabled(true);
QString currentFileName = fileName.right(fileName.size() - fileName.lastIndexOf('/')-1);
ui->currentStatusLabel->setText(tr("Status: open file %1 successfully!").arg(currentFileName));
}
}
// 实现文件大小等信息的发送
void MainWindow::startTransferFile()
{
localFile = new QFile(fileName);
if(!localFile->open(QFile::ReadOnly))
{
qDebug() << "open file error!";
return;
}
totalBytes = localFile->size(); //文件总大小
QDataStream sendOut(&outBlock, QIODevice::WriteOnly);
sendOut.setVersion(QDataStream::Qt_5_0);
QString currentFileName = fileName.right(fileName.size() - fileName.lastIndexOf('/')-1);
//依次写入总大小信息空间,文件名大小信息空间,文件名
sendOut << qint64(0) << qint64(0) << currentFileName;
//这里的总大小是文件名大小等信息和实际文件大小的总和
totalBytes += outBlock.size();
//返回outBolock的开始,用实际的大小信息代替两个qint64(0)空间
sendOut.device()->seek(0);
sendOut<<totalBytes<<qint64((outBlock.size() - sizeof(qint64)*2));
//发送完头数据后剩余数据的大小
bytesToWrite = totalBytes - tcpSocket->write(outBlock);
ui->currentStatusLabel->setText("Status: start transfering...");
outBlock.resize(0);
}
// 更新进度条,实现文件的传送
void MainWindow::updateClientProgress(qint64 numBytes)
{
//已经发送数据的大小
bytesWritten += (int)numBytes;
if(bytesToWrite > 0) //如果已经发送了数据
{
//每次发送loadSize大小的数据,这里设置为4KB,如果剩余的数据不足4KB,就发送剩余数据的大小
outBlock = localFile->read(qMin(bytesToWrite, loadSize));
//发�