ورود

View Full Version : سوال: ارسال Structure با استفاده از Qtcpsocket



returnx
شنبه 18 آذر 1391, 21:36 عصر
من در برنامم می خوام یک Structure رو از Clinet ارسال کنم به سرور وبا کد زیر اینکارو انجام میدم:
packeti_packet;
i_packet.packet_type=hello_packet;
i_packet.reciver="[server]";
i_packet.sender=ui->txt_username->text();
i_packet.message="hello!!";
socket->write(packet_to_bytes(i_packet));و در سمت سرور با این کد می خوانم:packeti_packet=byte_array_to_packet(i_c lient->readAll());qDebug()<<i_packet.message;اما سمت سرور چیزی دریافت نمیشه!!مشکل کدم کجاست!؟

returnx
دوشنبه 20 آذر 1391, 10:19 صبح
کسی کمک خاصی به ذهنش نمیرسه!؟

alamate_aoal
سه شنبه 21 آذر 1391, 15:51 عصر
از QDataStream برای انتقال استفاده کن

QByteArray block;
QDataStream out(&block, QIODevice::WriteOnly);
out.setVersion(QDataStream::Qt_4_0);
out << (quint16)0;
out << s;
out.device()->seek(0);
out << (quint16)(block.size() - sizeof(quint16));
clientConnection->write(block);

مثال fortune client و fortune server رو نگاه کن , کدهاش داکیومنت هم شدن.

returnx
سه شنبه 21 آذر 1391, 19:47 عصر
از QDataStream برای انتقال استفاده کن

QByteArray block;
QDataStream out(&block, QIODevice::WriteOnly);
out.setVersion(QDataStream::Qt_4_0);
out << (quint16)0;
out << s;
out.device()->seek(0);
out << (quint16)(block.size() - sizeof(quint16));
clientConnection->write(block);

مثال fortune client و fortune server رو نگاه کن , کدهاش داکیومنت هم شدن.
من برای تبدیل struct به QbyteArray مشکلی ندارم و دقیقا هم از همین روش استفاده میکنم!! اما وقتی با سوکت Write می کنم در اون سمت چیزی دریافت نمی کنم!!! در حالی که وقتی رشته میفرستم بدون مشکل اون سمت دریافت میشه!!!
اینم متد های من برای تبدیل Struct:

QByteArray packet_to_bytes(packet i_packet)
{
QByteArray i_byte_array;
QDataStream i_datastream(&i_byte_array,QIODevice::WriteOnly);
i_datastream<<i_packet.packet_type<<i_packet.sender<<i_packet.reciver<<i_packet.message;
return i_byte_array;

}//End function

packet byte_array_to_packet(QByteArray buffer)
{
packet i_packet;
QDataStream i_datastream(buffer);
i_datastream>>i_packet.packet_type>>i_packet.sender>>i_packet.reciver>>i_packet.message;
return i_packet;
}//End function تست هم کردم کاملا درست جواب میده ، اما ظاهرا تو Send اشکالی دارم...

alamate_aoal
پنج شنبه 23 آذر 1391, 01:54 صبح
این کدی که شما گذاشتید برای جواب دادن ناکافیه.
مراحل انجام اینکار رو بصورت کلی و به ترتیب می نویسم گرچه احتمالا بیشتر این مراحل رو انجام دادید :

سمت کلاینت:
یک آبجکت از نوع QTcpSocket بساز
با متد connectToHost از کلاس QTcpSocket به هاست مورد نظر کانکت شو
یک بافر از نوع QByteArray ایجاد و با استفاده از QDataStream مقادیر Structure رو در بافر سریالیزه کن(اینکار باعث استقلال کد از نوع سیستم عامل , معماری CPU و یا Endianness میشه - توجه به این موارد در برنامه نویسی شبکه مهمه)
حتما اندازه بافر ارسالی رو در ابتدای بافر درج کن. این قضیه برای ارسال داده حجیم که غالبا در چندین مرحله ارسال میشن حیاتیه(توی این کدی که گذاشتی اینکار رو نکردی)
در آخر با متد write بنویسش(برای حصول اطمینان از صحت عملکرد, خروجی متد write رو با اندازه بافر مقایسه کن-باید برابر باشن)

سمت سرور:
یک آبجکت از نوع QTcpServer بساز
سیگنال newConnection از آبجکت بالا رو به یه اسلات وصل کن( مثلا onNewConnection)
listen کن
در اسلات onNewConnection توسط متد nextPendingConnection از QTcpServer یک آبجکت از نوع QTcpSocket دریافت کن
سیگنالهای readyRead و disconnected از آبجکت بالا رو به اسلات های دلخواه , مثلا onReadyRead و onDisconnected وصل کن
در onDisconnected سوکت رو delete کن
در onReadyRead اطلاعات رو بخون

من با طی همین مراحل اون چیزی که مد نظر شما بود رو نوشتم.

returnx
پنج شنبه 23 آذر 1391, 08:57 صبح
همه اینکارایی که میگید رو انجام دادم برای همینه که متوجه نمیشم مشکل از کجاست!!! البته با این تفاوت ، که می خوام Chat Multi Clinet باشه برای همین هر Socket ای که Accept میشه رو در یک Qset نگه می دارم و در در Signal Ready Read با این کد :

QTcpSocket*i_client=(QTcpSocket*)sender();
Sender رو میگیرم و با این کد یک packet جدید رو می خوام برای همه کلاینت ها دوباره بفرستم:

packeti_packet=byte_array_to_packet(i_client->read(1024));
//QStringline=QString::fromUtf8(i_client->readLine(1024));
//qDebug()<<"Readline:"<<line;
if(i_packet.packet_type==hello_packet)
{

qDebug()<<i_packet.sender+"hasjoined\n";
users[i_client]=i_packet.sender;
packettemp_packet;
temp_packet.packet_type=command_message;
temp_packet.sender="[server]";
temp_packet.reciver="[All]";
temp_packet.message=i_packet.sender+"hasjoined\n";
foreach(QTcpSocket*i_client,clint_accept)
{
i_client->write(packet_to_bytes(temp_packet));
}
send_user_list();



}//Endifولی مشکل اینجاست که اصلا در این سمت (سرور) packet ای دریافت نمیشه!!البته من در زمان Send فقط سایز رو مشخص نمیکنم...

returnx
پنج شنبه 23 آذر 1391, 09:01 صبح
الان درست شد!!! یعنی مشکل از ارسال نکردن size بود!!!:متعجب:

returnx
پنج شنبه 23 آذر 1391, 20:20 عصر
نمیدونم چرا بعضی موقع ها hello Packet به سرور میرسه ولی بعضی موقع ها نمیرسه!!
و یک سوال دیگه،
می خوام کاربر از لیست کاربری که می خواد باهاش چت کنه رو انتخاب کنه و پنجره جدیدی مثل یاهو باز شه و در اون با هم چت کنند!! ولی دقیقا نمیدونم چطور از همون Socket که در پنجره قبلی ارتباط برقرار کرده استفاده کنم!؟
البته تا یک جاهایی رفتم ولی بعید میدونم نهایتا جواب بده ، فکر کنم این راهی که دارم میرم به نا کجا آباد ختم میشه...:لبخند:
اگر کسی راه حل خاصی به ذهنش میرسه ممنون میشه اگه کمک کنه...:لبخندساده:

returnx
جمعه 24 آذر 1391, 12:35 عصر
همچنان در خواندن مشکل دارم!!
زمانی که داده ای فرستاده میشه در این سمت Signal Ready Read به درستی صدا زده میشه و برنامه وارد SLOT مورد نظر میشه اما مقادیر درست خوانده نمیشه!!
اینم کد:

void server::readyRead()
{

QTcpSocket *i_client=(QTcpSocket*) sender();
qDebug()<<"ReadyRead...\n";
while (i_client->canReadLine())
{


QByteArray i_arr=i_client->readAll();
qDebug()<<"Packet len: "<<i_arr.length()<<"\n";
packet i_packet=byte_array_to_packet(i_arr);
if (i_packet.packet_type==hello_packet)
{
qDebug()<<"\n" + i_packet.sender +" has joined";
users[i_client]=i_packet.sender;
send_user_list();
}//End if
else if (i_packet.packet_type==general_message)
{
qDebug()<<i_packet.message;
}
}//End while
}//End function

alamate_aoal
جمعه 24 آذر 1391, 13:56 عصر
کلاینت


#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent) :
QWidget(parent, Qt::WindowStaysOnTopHint), ui(new Ui::Widget)
{
ui->setupUi(this);

if (!setupSocket())
QMessageBox::warning(this, "Err", m_socket->errorString());
}

Widget::~Widget()
{
delete ui;
}

bool Widget::setupSocket()
{
m_socket = new QTcpSocket(this);
connect(m_socket, SIGNAL(error(QAbstractSocket::SocketError)),
SLOT(onError(QAbstractSocket::SocketError)));
m_socket->connectToHost(QHostAddress::LocalHost, 4030);

return m_socket->isValid();
}

void Widget::onError(QAbstractSocket::SocketError err)
{
qDebug() << err << " --- " << m_socket->errorString();
}

void Widget::on_pushButton_clicked()
{
QByteArray block;
QDataStream out(&block, QIODevice::WriteOnly);
out.setVersion(QDataStream::Qt_4_8);

out << (quint16)0;
out << ui->ledFname->text();
out << ui->ledLname->text();
out << (qint8)ui->spbAge->value();

out.device()->seek(0);
out << (quint16)(block.size() - sizeof(quint16));

m_socket->write(block);
}

alamate_aoal
جمعه 24 آذر 1391, 13:57 عصر
سرور


#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent) :
QWidget(parent, Qt::WindowStaysOnTopHint), ui(new Ui::Widget)
{
ui->setupUi(this);

blockSize = 0;

if (!setupServer())
QMessageBox::critical(this, "Err", m_server->errorString());

}

Widget::~Widget()
{
delete ui;
}

bool Widget::setupServer()
{
m_server = new QTcpServer(this);
connect(m_server, SIGNAL(newConnection()), SLOT(onNewConnection()));

return m_server->listen(QHostAddress::Any, 4030);
}

void Widget::onNewConnection()
{
QTcpSocket *connection = m_server->nextPendingConnection();
connect(connection, SIGNAL(readyRead()), SLOT(onReadyRead()) );
connect(connection, SIGNAL(disconnected()), SLOT(onDisconnected()));
}

void Widget::onReadyRead()
{
QTcpSocket *socket = (QTcpSocket *)sender();

QDataStream in(socket);
in.setVersion(QDataStream::Qt_4_8);

if (blockSize == 0)
{
if (socket->bytesAvailable() < (int)sizeof(quint16))
return;
in >> blockSize;
}

if (socket->bytesAvailable() < blockSize)
return;

qint8 age;
QString fName, lName;
in >> fName >> lName >> age;

ui->ledFname->setText(fName);
ui->ledLname->setText(lName);
ui->ledAge->setText(QString::number(age));

blockSize = 0;
}

void Widget::onDisconnected()
{
QTcpSocket *socket = (QTcpSocket *)sender();
socket->deleteLater();
}