Есть сервер и клиент (отсылает данные, например файл):
Клиент:
void FileSender::sendFile()
{
QFile file(filePath);
if (file.open(QIODevice::ReadOnly)) {//если файл открылся
QByteArray dataForPeer;//массив для данных
QDataStream out(&dataForPeer, QIODevice::WriteOnly);//выходной поток
QByteArray byteArray;//поток байтов из файла
while(!file.atEnd()) {//пока не конец файла
byteArray=file.read(1024);//читаем по килобайту
out << quint16(0) << FILEBYTES << byteArray;
out.device()->seek(0);
out << quint16(dataForPeer.size() - sizeof(quint16));
tcpSocket->write(dataForPeer);
dataForPeer.clear();//очищаем массив для отправки серверу
}
//отправка уведомления об окончании передачи файла
out << quint16(0) << SENDING_FINISHED;
out.device()->seek(0);
out << quint16(dataForPeer.size() - sizeof(quint16));
tcpSocket->write(dataForPeer);
file.close();//закрываем файл
}
}
Покажи как читаются данные на другой стороне.
/*
Слот для обработки принятых из сокета данных.
*/
void FileWriter::readBytes()
{
QTcpSocket *tcpSocket=(QTcpSocket*)sender();//получаем сокет
QDataStream in(tcpSocket);
quint16 nextBlockSize=0;//размер принятого блока
for(;;) {
if(!nextBlockSize) {
if(tcpSocket->bytesAvailable()<sizeof(quint16)) break;//если данных принято меньше 2 байт, то выходим
in>>nextBlockSize;//получаем размер блока
}
if(tcpSocket->bytesAvailable()<nextBlockSize) break;//если все данные получены, то продолжаем работать
quint8 request;//получаем запрос
in>>request;
TypeOfRequest type=(TypeOfRequest)request;
if (type==FILEBYTES) {//если данные - файл, то записываем их на жесткий диск
writeBytes(in);
}
else if (type==SENDING_FINISHED) {//если пир окончил отправку файла, то отправляем ему
sendFinishMessage(tcpSocket);//уведомление об окончании его принятия
}
nextBlockSize=0;
}
}
/*
Функция записи принятых данных в файл. Параметры: поток данных из сокета(reference).
*/
void FileWriter::writeBytes(QDataStream &in)
{
QByteArray bytes;
in>>bytes;//получаем нужные байты
QFile file("D:/ref.dat");
if (file.open(QIODevice::Append)) {
file.write(bytes);//записываем байты
file.close();
}
}
/*
Функция отправки сообщения об окончании принятия файла. Параметры: принимающий сокет.
*/
void FileWriter::sendFinishMessage(QTcpSocket *tcpSocket)
{
QByteArray dataForPeer;//массив для данных
QDataStream out(&dataForPeer, QIODevice::WriteOnly);//выходной поток
out << quint16(0) << quint8(RECEIVING_FINISHED);//соообщение об окончании
out.device()->seek(0);
out << quint16(dataForPeer.size() - sizeof(quint16));
tcpSocket->write(dataForPeer);
}
Посмотри примеры еще раз и обрати внимание на то, как определена эта переменная:
void FileWriter::readBytes()
{
....
quint16 nextBlockSize=0;//размер принятого блока
....
void FileWriter::readBytes()
{
....
quint16 nextBlockSize=0;//размер принятого блока
....
Может быть не так, алгоритм Нагла думаю включен, поэтому TCP-стек скорее всего пакеты объединяет.
А не нужно отключать алгоритм Нагла, нужно придерживаться при чтении своего же протокола.
Ты пишешь по 1K, а при чтении читаешь все, со всеми управляющими командами. А нужно читать так же как пишешь по 1K.
Проверь несколько раз, сколько байт (какими порциями) реально читает эта функция из сокета:
void FileWriter::writeBytes(QDataStream &in)
{
QByteArray bytes;
in>>bytes;
qDebug() << "Read data size from socket:" << bytes.size();
QFile file("D:/ref.dat");
if (file.open(QIODevice::Append)) {
file.write(bytes);//записываем байты
file.close();
}
}
void FileWriter::writeBytes(QDataStream &in)
{
QByteArray bytes;
in>>bytes;
qDebug() << "Read data size from socket:" << bytes.size();
QFile file("D:/ref.dat");
if (file.open(QIODevice::Append)) {
file.write(bytes);//записываем байты
file.close();
}
}
quint8 request;//получаем запрос
in>>request;
TypeOfRequest type=(TypeOfRequest)request;
if (type==FILEBYTES) {//если данные - файл, то записываем их на жесткий диск
writeBytes(in);
}
в reguest вместо 0 или 1 попадает 97 вроде.
А покажи как определены: FILEBYTES, SENDING_FINISHED
class FileWriter : public QObject
{
Q_OBJECT
public:
FileWriter(QObject *parent=0):QObject(parent),nextBlockSize(0) {};
public slots:
void readBytes();//слот для чтения принятых данных
private:
quint16 nextBlockSize;
//тип запроса от клиента
enum TypeOfRequest {FILEBYTES/*отправка частей файла*/,SENDING_FINISHED/*отправка файла завершена*/};
//тип ответа от сервера
enum TypeOfReply {RECEIVING_FINISHED/*окончание принятия файла*/};
void writeBytes(QDataStream &in);//запись принятых байтов в файл
void sendFinishMessage(QTcpSocket *tcpSocket);//отправка уведомления об окончании принятия файла
};
Попробуй сиправить отсылку:
void FileSender::sendFile()
{
QFile file(filePath);
if (file.open(QIODevice::ReadOnly)) {//если файл открылся
QByteArray dataForPeer;//массив для данных
QDataStream out(&dataForPeer, QIODevice::WriteOnly);//выходной поток
QByteArray byteArray;//поток байтов из файла
while(!file.atEnd()) {//пока не конец файла
byteArray=file.read(1024);//читаем по килобайту
out << quint16(0) << quint8( FILEBYTES ) << byteArray; // <<<
out.device()->seek(0);
out << quint16(dataForPeer.size() - sizeof(quint16));
tcpSocket->write(dataForPeer);
dataForPeer.clear();//очищаем массив для отправки серверу
}
//отправка уведомления об окончании передачи файла
out << quint16(0) << quint8( SENDING_FINISHED ); // <<<
out.device()->seek(0);
out << quint16(dataForPeer.size() - sizeof(quint16));
tcpSocket->write(dataForPeer);
file.close();//закрываем файл
}
}
Да я вечером уже этот глюк нашел и исправил, но все равно неправильно работает
Вот исходники 3 классов: сервер, поток-приемщик и отправитель. Может поможет Вам разобраться точней..
Попробуй изменить так:
void FileSender::sendFile()
{
QFile file(filePath);
if (file.open(QIODevice::ReadOnly)) {//если файл открылся
while(!file.atEnd()) {//пока не конец файла
QByteArray byteArray=file.read(1024);//читаем по килобайту
QByteArray dataForPeer;//массив для данных
QDataStream out(&dataForPeer, QIODevice::WriteOnly);//выходной поток
out << quint16(0) << FILEBYTES << byteArray;
out.device()->seek(0);
out << quint16(dataForPeer.size() - sizeof(quint16));
tcpSocket->write(dataForPeer);
}
//отправка уведомления об окончании передачи файла
QByteArray dataForPeer;//массив для данных
QDataStream out(&dataForPeer, QIODevice::WriteOnly);//выходной поток
out << quint16(0) << SENDING_FINISHED;
out.device()->seek(0);
out << quint16(dataForPeer.size() - sizeof(quint16));
tcpSocket->write(dataForPeer);
file.close();//закрываем файл
}
}
Блин, quint8 забыл добавить:
void FileSender::sendFile()
{
QFile file(filePath);
if (file.open(QIODevice::ReadOnly)) {//если файл открылся
while(!file.atEnd()) {//пока не конец файла
QByteArray byteArray=file.read(1024);//читаем по килобайту
QByteArray dataForPeer;//массив для данных
QDataStream out(&dataForPeer, QIODevice::WriteOnly);//выходной поток
out << quint16(0) << quint8( FILEBYTES ) << byteArray;
out.device()->seek(0);
out << quint16(dataForPeer.size() - sizeof(quint16));
tcpSocket->write(dataForPeer);
}
//отправка уведомления об окончании передачи файла
QByteArray dataForPeer;//массив для данных
QDataStream out(&dataForPeer, QIODevice::WriteOnly);//выходной поток
out << quint16(0) << quint8( SENDING_FINISHED );
out.device()->seek(0);
out << quint16(dataForPeer.size() - sizeof(quint16));
tcpSocket->write(dataForPeer);
file.close();//закрываем файл
}
}
Вы уже это писали Я же сказал, что еще вчера это исправил, но все равно не работает. У меня с quint8 сейчас.
BRE, спасибо за разные подсказки! Сейчас посидел, подумал - неправильно вообще я алгоритм организовал, понял в чем дело, буду перерабатывать. Загвоздка как раз в типе запроса(request).
QFile file(filePath);
if (file.open(QIODevice::ReadOnly)) {//если файл открылся
char b[1025];
char *bytes=b;
while(!file.atEnd()) {//пока не конец файла
file.read(bytes,1024);//читаем по килобайту
tcpSocket->write(bytes);
}
file.close();//закрываем файл
}
Посмотри эту тему, там я выкладывал архивы с тестовым проектом, передающим файл:
http://www.forum.crossplatform.ru/index.php?showtopic=4296&st=0
connect(fileSender,SIGNAL(finished()),fileSender,SLOT(deleteLater())); //fileSender это поток
Без кода я затрудняюсь ответить.
Форум Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)