@1405010304geshuaishuai
2016-10-18T03:45:40.000000Z
字数 4440
阅读 999
网络通信
文件传输
服务器端和客户端各传递1次字符串。考虑到使用TCP协议,所以传递字符串前先以4字节整数型方式传递字符串长度。连接时服务器端和客户端数据传输格式如下:
图1-1 传输数据格式
从题目中可以看出首先将用户输入到文本框中的数据进行解析,看看到底有多少个字符,然后在将字符数据和后面的信息一起发过去,在题目中,我们很容易看到一共是四个字节来记录文本的数据,所以我们默认将这四个数据全都设为0,然后经过对用户输入的信息分析之后在修改相应的位数。
界面设计如下:
图1-2 客户端界面
图1-3 服务器端界面
当用户在信息输入框中输入字符,点击发送,服务器端就会返还回字符的个数加数据。
客户端核心代码如下:
void tcp_client1::datatranslate()
{
QTextCodec *code=QTextCodec::codecForName("GBK");
QString message=ui->lineEdit_meseg->text();
int a=0, b=0, c=0, d=0;
if(message.length()<10)
{
d=message.length();
}
else if(message.length()<100)
{
d=message.length()%10;
c=message.length()/10;
}
else if(message.length()<1000)
{
d=message.length()%10;
c=message.length()%100/10;
b=message.length()/100;
}
else if(message.length()<10000)
{
d=message.length()%10;
c=message.length()%100/10;
b=message.length()%1000/100;
a=message.length()/1000;
}
QString qa= QString::number(a);
QString qb= QString::number(b);
QString qc= QString::number(c);
QString qd= QString::number(d);
QByteArray sa=code->fromUnicode(qa);
QByteArray sb=code->fromUnicode(qb);
QByteArray sc=code->fromUnicode(qc);
QByteArray sd=code->fromUnicode(qd);
QByteArray mes1=code->fromUnicode(message);
this->tcpSocket->write(sa+sb+sc+sd+mes1);
ui->lineEdit_meseg->clear();
}
服务器端核心代码如下:
void tcp_server1::readdata()
{
QString fromClient = tcpSocket->readAll();
QTextCodec *code=QTextCodec::codecForName("GBK");
QByteArray mes=code->fromUnicode(fromClient);
ui->char_num->setText(mes);
tcpSocket->write(mes);
}
图1-4 运行效果图
1-4 实验总结
通过本次实验,对TCP通信有了进一步的认识,将字符的个数发送到服务器这里首先在客户端进行数据的解析,通过计算算出一共有多少字符,然后一起和数据进行发送,当服务器接收到数据时,原封不动的将数据返回给客户端,就像前面做过的迭代服务器一样。
创建收发文件的服务器端/客户端,实现顺序如下。
客户端接收用户输入的传输文件名。
客户端请求服务器端传输该文件名所指文件。
如果指定文件存在,服务器端就将其发送给客户端;反之,则断开连接。
考虑到本题目涉及到文件的传输,所以只实现了其中由客户端选择文件上传到服务端,由于水平有限,所以只能是先到这一步。首先客户端的界面如下:
图2-1 客户端运行界面
服务端的界面如下:
图2-2 服务器端运行界面
首先客户端打开文件,服务端选择监听,然后哭护短选择上传文件,服务端开始接收文件,知道完成传输。
实现文件的传输,在实际的文件传输以前,需要将整个传输数据的大小、文件名的大小还有文件名等信息放在数据的开头进行传输,这里可以把他们统称为文件头结构。数据是分为数据块进行发送的,每次发送的数据块的大小为指定大小,每当有数据发送时就更新进度条,如果数据发送完毕,便关闭本地文件和客户端套接字。服务器端先分别接收了数据总大小、文件名大小及文件名等文件头结构的信息,然后才接受实际的文件。一旦建立连接,客户端套接字便发射connected()信号,从而调用startTransfer()来发送头文件结构。这时服务器端发现有数据到来便更新进度条,在其中获取发送过来的数据。而在客户端,当有数据发送时,也会更新进度条,在其中将后面的数据库发送出去。
客户端核心代码:
void Client::startTransfer()
{
localFile=new QFile(fileName);
if(!localFile->open(QFile::ReadOnly)){
qDebug()<<"client: open file error!";
return;
}
totalBytes=localFile->size();
QDataStream sendOut(&outBlock, QIODevice::WriteOnly);
sendOut.setVersion(QDataStream::Qt_4_0);
QString currentFileName=fileName.right(fileName.size()-fileName.lastIndexOf('/')-1);
sendOut<<qint64(0)<<qint64(0)<<currentFileName;
totalBytes+=outBlock.size();
sendOut.device()->seek(0);
sendOut<<totalBytes<<qint64((outBlock.size()-sizeof(qint64)*2));
bytesToWrite=totalBytes-tcpClient->write(outBlock);
ui->clientStatusLabel->setText(tr("已连接"));
outBlock.resize(0);
}
void Client::updateClientProcess(qint64 numBytes)
{
bytesWritten+=(int)numBytes;
if(bytesToWrite>0){
outBlock=localFile->read(qMin(bytesToWrite, payloadSize));
bytesToWrite-=(int)tcpClient->write(outBlock);
outBlock.resize(0);
}else{
localFile->close();
}
ui->clientProgressBar->setMaximum(totalBytes);
ui->clientProgressBar->setValue(bytesWritten);
if(bytesWritten==totalBytes){
ui->clientStatusLabel->setText(tr("传送文件 %1 成功").arg(fileName));
localFile->close();
tcpClient->close();
}
}
服务器端代码:
void Server::updateServerProgress()
{
QDataStream in(tcpServerConnection);
in.setVersion(QDataStream::Qt_4_0);
if(bytesReceived<=sizeof(qint64)*2){
if((tcpServerConnection->bytesAvailable()>=sizeof(qint64)*2)&&(fileNameSize==0)){
in>>totalBytes>>fileNameSize;
bytesReceived+=sizeof(qint64)*2;
}
if((tcpServerConnection->bytesAvailable()>=fileNameSize)&&(fileNameSize!=0)){
in>>fileName;
ui->serverStatusLabel->setText(tr("接收文件 %1 ...").arg(fileName));
bytesReceived+=fileNameSize;
//QString dir="D:\\server\\";
/*QDir d;
d.mkpath(dir);*/
localFile=new QFile(dir+"\\"+fileName);
if(! localFile->open(QFile::WriteOnly)){
qDebug()<<"server: open file error!";
return;
}
}else{
return;
}
}
if(bytesReceived<totalBytes){
bytesReceived+=tcpServerConnection->bytesAvailable();
inBlock=tcpServerConnection->readAll();
localFile->write(inBlock);
inBlock.resize(0);
}
ui->serverProgressBar->setMaximum(totalBytes);
ui->serverProgressBar->setValue(bytesReceived);
if(bytesReceived==totalBytes){
tcpServerConnection->close();
ui->startButton->setEnabled(true);
ui->serverStatusLabel->setText(tr("接收文件 %1 成功!").arg(fileName));
}
}
通过本次实验,了解到文件在客户端与服务器端的传输,相信文件能从客户端上传到服务端,当然也能从服务端下载到客户端,方法是一样的,首先在客户端输入要在服务器端下载的文件名称,发送到服务器,服务器接收到名称然后去指定的文件夹下去查找,如果有则将这个文件传送到客户端,如果没有则断开连接。