在建立连接的基础上增加了发送文件的功能,在接收端和发送端定义了一个枚举类型,用于判别发送的是文件还是文本消息
enum MSG{
messAge,
fiLe
};

1.获取端口号和ip地址,进行连接,再次点击即可断开连接
void Widget::on_btn_listen_clicked()
{
QString address=ui->lineEdit_address->text();
qint16 port=ui->lineEdit_port->text().toInt();
QHostAddress ip=QHostAddress(address);
if(!conState)
{
my_client->connectToHost(ip,port);
if(!my_client->waitForConnected(5000))
{
QMessageBox::critical(this,"错误",my_client->errorString());
return ;
}
else
{
ui->btn_listen->setText("断开连接");
connect(my_client,&QTcpSocket::readyRead,this,&Widget::readyReadClientSlot);
conState=true;
}
}
else
{
conState=false;
my_client->close();
qDebug()<<"断开连接"<<endl;
ui->btn_listen->setText("开始连接");
}
}
2.点击发送消息按钮,获取文本框内容,将消息发送出去,其中type为文本消息类型
void Widget::on_btn_send_clicked()
{
QString str=ui->textEdit->toPlainText();
QString res;
res+="客户端:"+str;
QByteArray arr;
QDataStream data(&arr,QIODevice::WriteOnly);
MSG type=messAge;
data<<type<<res.toLocal8Bit();
my_client->write(arr);
ui->textBrowser->append(res);
ui->textEdit->clear();
ui->textEdit->setFocus();
}
3.接收客户端发来的文本消息
void Widget::readyReadClientSlot()
{
int len=my_client->bytesAvailable();
QByteArray arr=my_client->read(len>65536?65536:len);
QString res=QString::fromLocal8Bit(arr);
ui->textBrowser->append(res);
}
4.浏览文件
void Widget::on_btn_openfile_clicked()
{
QString path=QFileDialog::getOpenFileName(this,"选择文件","E:/");
ui->lineEdit_path->setText(path);
}
5.点击发送文件按钮,首先会将文件名和文件大小传输过去,以作判断传输是否完成依据
void Widget::on_btn_sendfile_clicked()
{
if(!conState)//如果没有连接客户端弹出警告
{
QMessageBox::warning(this,"错误","没有连接服务端");
return;
}
QString path=ui->lineEdit_path->text();//得到文件路径
QFileInfo info(path);
//获取文件信息
filename=info.fileName();
filesize=info.size();
sendsize=0;//初始化发送的文件大小为0
QByteArray arr;
MSG type=fiLe;//发送的内容为文件类型
QDataStream stream(&arr,QIODevice::WriteOnly);
stream<<type<<filename<<filesize;//写入文件名和文件大小
qDebug()<<filename<<" "<<filesize<<endl;
//打开文件
file.setFileName(path);
file.open(QIODevice::ReadOnly);
ui->progressBar->setMaximum(filesize);
my_client->write(arr);//发送内容到服务端
connect(my_client, &QTcpSocket::bytesWritten, this, &Widget::sendtxtSLot);
//resarr=arr;
//emit this->sendFileToYes();//发送完后 发送已经发完文件信息的信号
}
6.当文件信息传输完成后,会发送bytesWritten信号,后继每次传输完成也会发送这个信号,接着传输文件内容,当内容传输完成后,关闭文件,将filesize(发送的文件大小)和sendsize(已发送的文件大小)初始化为0,断开信号与槽,免得与文本消息冲突
void Widget::sendtxtSLot()
{
//timer->start(5000);
qDebug()<<"准备开始发送文件"<<endl;
qDebug()<<"文件信息:"<<filename<<filesize<<endl<<"已经发送的大小:"<<sendsize<<endl;
if(sendsize<filesize)//当发送大小小于文件大小执行 文件比较小就换成了if 一次能读完 换成while现在还有bug
{
//connect(timer,&QTimer::timeout,this,&Widget::sendfiletxt);
qDebug()<<"开始发送文件"<<endl;
QByteArray arr=file.read(1024*10);//一次读取的内容
QByteArray arrsend;
QDataStream data(&arrsend,QIODevice::WriteOnly);
MSG type=fiLe;//发送的内容为文件类型
data<<type<<arr;//读入文件类型和文件内容
my_client->write(arrsend);//发送数据内容
sendsize+=arr.size();
QString strfile=QString::fromUtf8(arr);
ui->textBrowser->append(strfile);
qDebug()<<"更新发送的大小"<<sendsize<<endl;
ui->progressBar->setValue(sendsize);
}
if(filesize==sendsize)
{
qDebug()<<"文件发送完成"<<endl;
file.close();
filesize=0;
sendsize=0;
//timer->stop();
// disconnect(timer,&QTimer::timeout,this,&Widget::sendfiletxt);
disconnect(my_client, &QTcpSocket::bytesWritten, this, &Widget::sendtxtSLot);
}
}
头文件:
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include<QTcpSocket>
#include<QDebug>
#include<QMessageBox>
#include<QFile>
#include<QTimer>
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
enum MSG{
messAge,
fiLe
};
public:
explicit Widget(QWidget *parent = 0);
~Widget();
private:
signals:
void sendFileToYes();//测试bug用的信号,已经废弃
private slots:
void on_btn_listen_clicked();//开始/断开连接
void on_btn_send_clicked();//发送文本消息
void readyReadClientSlot();//接收服务端文本消息
void on_btn_openfile_clicked();//浏览文件
void on_btn_sendfile_clicked();//发送文件,首先发送文件信息过去
void sendtxtSLot();//发送文件内容
private:
Ui::Widget *ui;
QTcpSocket *my_client;
bool conState;
//文件
QString filename;
int filesize;
int sendsize;
QFile file;
QByteArray resarr;
QTimer *timer;//测试bug用,已舍弃
};
#endif // WIDGET_H
cpp:
#include "widget.h"
#include "ui_widget.h"
#include<QHostAddress>
#include<QFileDialog>
#include<QFileInfo>
#include<QDataStream>
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
this->setWindowTitle("客户端");
timer =new QTimer(this);
ui->progressBar->setValue(0);
my_client=new QTcpSocket();
conState=false;
connect(this,&Widget::sendFileToYes,this,&Widget::sendtxtSLot);
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_btn_listen_clicked()
{
QString address=ui->lineEdit_address->text();
qint16 port=ui->lineEdit_port->text().toInt();
QHostAddress ip=QHostAddress(address);
if(!conState)
{
my_client->connectToHost(ip,port);
if(!my_client->waitForConnected(5000))
{
QMessageBox::critical(this,"错误",my_client->errorString());
return ;
}
else
{
ui->btn_listen->setText("断开连接");
connect(my_client,&QTcpSocket::readyRead,this,&Widget::readyReadClientSlot);
conState=true;
}
}
else
{
conState=false;
my_client->close();
qDebug()<<"断开连接"<<endl;
ui->btn_listen->setText("开始连接");
}
}
void Widget::on_btn_send_clicked()
{
QString str=ui->textEdit->toPlainText();
QString res;
res+="客户端:"+str;
QByteArray arr;
QDataStream data(&arr,QIODevice::WriteOnly);
MSG type=messAge;
data<<type<<res.toLocal8Bit();
my_client->write(arr);
ui->textBrowser->append(res);
ui->textEdit->clear();
ui->textEdit->setFocus();
}
void Widget::readyReadClientSlot()
{
int len=my_client->bytesAvailable();
QByteArray arr=my_client->read(len>65536?65536:len);
QString res=QString::fromLocal8Bit(arr);
ui->textBrowser->append(res);
}
void Widget::on_btn_openfile_clicked()
{
QString path=QFileDialog::getOpenFileName(this,"选择文件","E:/");
ui->lineEdit_path->setText(path);
}
void Widget::on_btn_sendfile_clicked()
{
if(!conState)//如果没有连接客户端弹出警告
{
QMessageBox::warning(this,"错误","没有连接服务端");
return;
}
QString path=ui->lineEdit_path->text();//得到文件路径
QFileInfo info(path);
//获取文件信息
filename=info.fileName();
filesize=info.size();
sendsize=0;//初始化发送的文件大小为0
QByteArray arr;
MSG type=fiLe;//发送的内容为文件类型
QDataStream stream(&arr,QIODevice::WriteOnly);
stream<<type<<filename<<filesize;//写入文件名和文件大小
qDebug()<<filename<<" "<<filesize<<endl;
//打开文件
file.setFileName(path);
file.open(QIODevice::ReadOnly);
ui->progressBar->setMaximum(filesize);
my_client->write(arr);//发送内容到服务端
connect(my_client, &QTcpSocket::bytesWritten, this, &Widget::sendtxtSLot);
//resarr=arr;
//emit this->sendFileToYes();//发送完后 发送已经发完文件信息的信号
}
void Widget::sendtxtSLot()
{
//timer->start(5000);
qDebug()<<"准备开始发送文件"<<endl;
qDebug()<<"文件信息:"<<filename<<filesize<<endl<<"已经发送的大小:"<<sendsize<<endl;
if(sendsize<filesize)//当发送大小小于文件大小执行 文件比较小就换成了if 一次能读完 换成while现在还有bug
{
//connect(timer,&QTimer::timeout,this,&Widget::sendfiletxt);
qDebug()<<"开始发送文件"<<endl;
QByteArray arr=file.read(1024*10);//一次读取的内容
QByteArray arrsend;
QDataStream data(&arrsend,QIODevice::WriteOnly);
MSG type=fiLe;//发送的内容为文件类型
data<<type<<arr;//读入文件类型和文件内容
my_client->write(arrsend);//发送数据内容
sendsize+=arr.size();
QString strfile=QString::fromUtf8(arr);
ui->textBrowser->append(strfile);
qDebug()<<"更新发送的大小"<<sendsize<<endl;
ui->progressBar->setValue(sendsize);
}
if(filesize==sendsize)
{
qDebug()<<"文件发送完成"<<endl;
file.close();
filesize=0;
sendsize=0;
//timer->stop();
// disconnect(timer,&QTimer::timeout,this,&Widget::sendfiletxt);
disconnect(my_client, &QTcpSocket::bytesWritten, this, &Widget::sendtxtSLot);
}
}

主要函数
1.获得端口号和ip地址进行监听,再次点击即可断开监听
void Widget::on_btn_listen_clicked()
{
QString ip=ui->lineEdit_address->text();
qint16 port=ui->lineEdit_port->text().toInt();
QHostAddress address=QHostAddress(ip);
if(!my_sever->isListening())
{
if(!my_sever->listen(address,port))
{
QMessageBox::critical(this,"错误",my_sever->errorString());
return ;
}
else
{
ui->btn_listen->setText("停止监听");
connect(my_sever,&QTcpServer::newConnection,this,&Widget::newConnectionSlot);
}
}
else
{
ui->btn_listen->setText("开始监听");
my_sever->close();
}
}
2.将文本消息发送到每个客户端
void Widget::on_btn_send_clicked()
{
QString str=ui->textEdit->toPlainText();
ui->textEdit->clear();
ui->textEdit->setFocus();
QString res;
res+="服务端: "+str;
QByteArray arr=res.toLocal8Bit();
ui->textBrowser->append(res);
for(int i=0;i<my_client.size();i++)
{
my_client[i]->write(arr);
}
}
3.当服务端发出newConnection信号时,将客户端加入到my_client的一员中,初始化接收到的文件大小和已接收的文件大小
void Widget::newConnectionSlot()
{
qDebug()<<"新用户来了"<<endl;
QTcpSocket* sock=my_sever->nextPendingConnection();
my_client.append(sock);
connect(sock,&QTcpSocket::readyRead,this,&Widget::readyReadSlot);
filesize=0;
recvsize=0;
}
4.接收来自客户端发送的文件或文本消息,首先获得是哪个客户端发送来的消息,然后判断是文本消息类型还是文件类型
注意:if(recvsize<filesize)和if(filesize==0)顺序不能颠倒,否则就会多执行一次if(recvsize<filesize)分支,在此卡了很久的bug!!!
void Widget::readyReadSlot()
{
QTcpSocket *sock=qobject_cast<QTcpSocket*>(sender());
sendnum++;//触发一次槽函数,客户端发来消息的次数加一
ui->lcdNumber->display(sendnum);
int type;//判断客户端发送的消息类型 {messAge:普通消息,fiLe:文件}
int len=sock->bytesAvailable();
QByteArray arr=sock->read(len>65536?65536:len);
QByteArray arrtxt;//普通消息内容
QByteArray arrfile;//文件内容
QDataStream data(&arr,QIODevice::ReadOnly);
QString str;
data>>type;//读入类型
switch (type) {
case messAge://普通消息分支
data>>arrtxt;
str=QString::fromLocal8Bit(arrtxt);
ui->textBrowser->append(str);
break;
case fiLe://文件分支
qDebug()<<"准备接收文件"<<endl;
if(recvsize<filesize)//当接收到的内容不完整时继续读取
{
qDebug()<<"开始接收文件内容"<<endl;
data>>arrfile;//读入文件内容
file.write(arrfile);
recvsize+=arrfile.size();
qDebug()<<"接受的大小:"<<recvsize<<endl;
ui->progressBar->setValue(recvsize);
}
if(filesize==0)//如果文件大小为0,说明才开始传输,首先客户端要传输文件名字,和文件大小
{
qDebug()<<"接收文件信息"<<endl;
data>>filename>>filesize;//读入文件名和文件大小
qDebug()<<"文件信息:"<<recvsize<<" "<<filesize<<endl;
ui->progressBar->setMaximum(filesize);//将进度条的最大值设置为客户端传入文件大小
//打开文件
file.setFileName(filename);
file.open(QIODevice::WriteOnly);
}
if(recvsize==filesize)
{
qDebug()<<"关闭接收文件内容"<<endl;
file.close();
filesize=0;
recvsize=0;
}
break;
default:
break;
}
}
头文件:
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include<QTcpServer>
#include<QTcpSocket>
#include<QDebug>
#include<QMessageBox>
#include<QFile>
#include<QFileInfo>
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
enum MSG{
messAge,
fiLe
};
public:
explicit Widget(QWidget *parent = 0);
~Widget();
private slots:
void on_btn_listen_clicked();//开启、关闭监听
void on_btn_send_clicked();//发送文本消息到客户端
void readyReadSlot();//接收客户端文本消息
void newConnectionSlot();
private:
Ui::Widget *ui;
QTcpServer *my_sever;
QList<QTcpSocket*> my_client;
QString filename;
int filesize;
int recvsize;
QFile file;
int sendnum;//测试用,获得客户端发来了几次消息
};
#endif // WIDGET_H
cpp:
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
my_sever=new QTcpServer();
this->setWindowTitle("服务端");
ui->progressBar->setValue(0);
sendnum=0;
ui->lcdNumber->display(sendnum);
//connect(my_sever,&QTcpServer::newConnection,this,&Widget::readyReadSlot);
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_btn_listen_clicked()
{
QString ip=ui->lineEdit_address->text();
qint16 port=ui->lineEdit_port->text().toInt();
QHostAddress address=QHostAddress(ip);
if(!my_sever->isListening())
{
if(!my_sever->listen(address,port))
{
QMessageBox::critical(this,"错误",my_sever->errorString());
return ;
}
else
{
ui->btn_listen->setText("停止监听");
connect(my_sever,&QTcpServer::newConnection,this,&Widget::newConnectionSlot);
}
}
else
{
ui->btn_listen->setText("开始监听");
my_sever->close();
}
}
void Widget::on_btn_send_clicked()
{
QString str=ui->textEdit->toPlainText();
ui->textEdit->clear();
ui->textEdit->setFocus();
QString res;
res+="服务端: "+str;
QByteArray arr=res.toLocal8Bit();
ui->textBrowser->append(res);
for(int i=0;i<my_client.size();i++)
{
my_client[i]->write(arr);
}
}
void Widget::readyReadSlot()
{
QTcpSocket *sock=qobject_cast<QTcpSocket*>(sender());
sendnum++;//触发一次槽函数,客户端发来消息的次数加一
ui->lcdNumber->display(sendnum);
int type;//判断客户端发送的消息类型 {messAge:普通消息,fiLe:文件}
int len=sock->bytesAvailable();
QByteArray arr=sock->read(len>65536?65536:len);
QByteArray arrtxt;//普通消息内容
QByteArray arrfile;//文件内容
QDataStream data(&arr,QIODevice::ReadOnly);
QString str;
data>>type;//读入类型
switch (type) {
case messAge://普通消息分支
data>>arrtxt;
str=QString::fromLocal8Bit(arrtxt);
ui->textBrowser->append(str);
break;
case fiLe://文件分支
qDebug()<<"准备接收文件"<<endl;
if(recvsize<filesize)//当接收到的内容不完整时继续读取
{
qDebug()<<"开始接收文件内容"<<endl;
data>>arrfile;//读入文件内容
file.write(arrfile);
recvsize+=arrfile.size();
qDebug()<<"接受的大小:"<<recvsize<<endl;
ui->progressBar->setValue(recvsize);
}
if(filesize==0)//如果文件大小为0,说明才开始传输,首先客户端要传输文件名字,和文件大小
{
qDebug()<<"接收文件信息"<<endl;
data>>filename>>filesize;//读入文件名和文件大小
qDebug()<<"文件信息:"<<recvsize<<" "<<filesize<<endl;
ui->progressBar->setMaximum(filesize);//将进度条的最大值设置为客户端传入文件大小
//打开文件
file.setFileName(filename);
file.open(QIODevice::WriteOnly);
}
if(recvsize==filesize)
{
qDebug()<<"关闭接收文件内容"<<endl;
file.close();
filesize=0;
recvsize=0;
}
break;
default:
break;
}
}
void Widget::newConnectionSlot()
{
qDebug()<<"新用户来了"<<endl;
QTcpSocket* sock=my_sever->nextPendingConnection();
my_client.append(sock);
connect(sock,&QTcpSocket::readyRead,this,&Widget::readyReadSlot);
filesize=0;
recvsize=0;
}
我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看rubyzip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d
我试图在一个项目中使用rake,如果我把所有东西都放到Rakefile中,它会很大并且很难读取/找到东西,所以我试着将每个命名空间放在lib/rake中它自己的文件中,我添加了这个到我的rake文件的顶部:Dir['#{File.dirname(__FILE__)}/lib/rake/*.rake'].map{|f|requiref}它加载文件没问题,但没有任务。我现在只有一个.rake文件作为测试,名为“servers.rake”,它看起来像这样:namespace:serverdotask:testdoputs"test"endend所以当我运行rakeserver:testid时
我的目标是转换表单输入,例如“100兆字节”或“1GB”,并将其转换为我可以存储在数据库中的文件大小(以千字节为单位)。目前,我有这个:defquota_convert@regex=/([0-9]+)(.*)s/@sizes=%w{kilobytemegabytegigabyte}m=self.quota.match(@regex)if@sizes.include?m[2]eval("self.quota=#{m[1]}.#{m[2]}")endend这有效,但前提是输入是倍数(“gigabytes”,而不是“gigabyte”)并且由于使用了eval看起来疯狂不安全。所以,功能正常,
Rails2.3可以选择随时使用RouteSet#add_configuration_file添加更多路由。是否可以在Rails3项目中做同样的事情? 最佳答案 在config/application.rb中:config.paths.config.routes在Rails3.2(也可能是Rails3.1)中,使用:config.paths["config/routes"] 关于ruby-on-rails-Rails3中的多个路由文件,我们在StackOverflow上找到一个类似的问题
对于具有离线功能的智能手机应用程序,我正在为Xml文件创建单向文本同步。我希望我的服务器将增量/差异(例如GNU差异补丁)发送到目标设备。这是计划:Time=0Server:hasversion_1ofXmlfile(~800kiB)Client:hasversion_1ofXmlfile(~800kiB)Time=1Server:hasversion_1andversion_2ofXmlfile(each~800kiB)computesdeltaoftheseversions(=patch)(~10kiB)sendspatchtoClient(~10kiBtransferred)Cl
我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚
尝试通过RVM将RubyGems升级到版本1.8.10并出现此错误:$rvmrubygemslatestRemovingoldRubygemsfiles...Installingrubygems-1.8.10forruby-1.9.2-p180...ERROR:Errorrunning'GEM_PATH="/Users/foo/.rvm/gems/ruby-1.9.2-p180:/Users/foo/.rvm/gems/ruby-1.9.2-p180@global:/Users/foo/.rvm/gems/ruby-1.9.2-p180:/Users/foo/.rvm/gems/rub
使用带有Rails插件的vim,您可以创建一个迁移文件,然后一次性打开该文件吗?textmate也可以这样吗? 最佳答案 你可以使用rails.vim然后做类似的事情::Rgeneratemigratonadd_foo_to_bar插件将打开迁移生成的文件,这正是您想要的。我不能代表textmate。 关于ruby-使用VimRails,您可以创建一个新的迁移文件并一次性打开它吗?,我们在StackOverflow上找到一个类似的问题: https://sta
我正在使用puppet为ruby程序提供一组常量。我需要提供一组主机名,我的程序将对其进行迭代。在我之前使用的bash脚本中,我只是将它作为一个puppet变量hosts=>"host1,host2"我将其提供给bash脚本作为HOSTS=显然这对ruby不太适用——我需要它的格式hosts=["host1","host2"]自从phosts和putsmy_array.inspect提供输出["host1","host2"]我希望使用其中之一。不幸的是,我终其一生都无法弄清楚如何让它发挥作用。我尝试了以下各项:我发现某处他们指出我需要在函数调用前放置“function_”……这
好的,所以我的目标是轻松地将一些数据保存到磁盘以备后用。您如何简单地写入然后读取一个对象?所以如果我有一个简单的类classCattr_accessor:a,:bdefinitialize(a,b)@a,@b=a,bendend所以如果我从中非常快地制作一个objobj=C.new("foo","bar")#justgaveitsomerandomvalues然后我可以把它变成一个kindaidstring=obj.to_s#whichreturns""我终于可以将此字符串打印到文件或其他内容中。我的问题是,我该如何再次将这个id变回一个对象?我知道我可以自己挑选信息并制作一个接受该信