Поиск:

Ответ в темуСоздание новой темы Создание опроса
> [Qt] Подскажите простой пример клиент-сервера 
V
    Опции темы
shutffl
Дата 26.11.2008, 07:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 171
Регистрация: 18.8.2008

Репутация: нет
Всего: 3



Добрый!

Пишу проект, в котором надо организовать работу с сетью по принципу чата. Сетевые приложения писал, но на оригинальном C. Пробовал писать, используя QTcpServer и QTcpSocket.
Задача не совсем тривиальна - в хелпе похожего не нашел, а догадки переделки Fortune клиента и сервера плодов не дали.

Цель.
На машине запускается сервер(адрес и порт известны). Сервер должен слушать порт и получать сообщения от клиентов.

Возможная реализация.
Клиент стучится на порт сервера, посылает ему строку(это на самом деле сетевой логгер). Сервер ее получает, клиент отсоединяется. Сервер обрабатывает полученные данные и пишет в лог.

Проблемы.
Не понимаю как это чудо реализовать. Пробую уже почти с неделю.  Код приводить не имеет смысла ибо бред, если честно. Google ничего путного не сказал акромя Simple Network Chat. При беглом анализе кода посчитал, что пример не подходит, перегружен.
Возможно (даже желательно), клиент должен висеть на порту постоянно, пока работает. Как делать - тоже загадка. Думаю, кусок клиента и сервера должен быть при такой реализации достаточно простым.

Заранее спасибо. Все вопросы или необходимые уточнения приветствуются. Как и критика.
--------------------
shadowmoon
PM MAIL   Вверх
Ches
Дата 26.11.2008, 08:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 84
Регистрация: 19.8.2008

Репутация: нет
Всего: 3



в qtdemo есть пример UDP сервера/клиента. Называются "Broadcast sender/reciever"
Цитата(shutffl @  26.11.2008,  07:23 Найти цитируемый пост)
адача не совсем тривиальна

Тривиальна до невозможности smile 

PM MAIL ICQ   Вверх
shutffl
Дата 26.11.2008, 09:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 171
Регистрация: 18.8.2008

Репутация: нет
Всего: 3



Хм... А мона UDP на TCP изменить? В проге важно, чтобы пакеты точно дошли до пункта назначения.
--------------------
shadowmoon
PM MAIL   Вверх
Ches
Дата 26.11.2008, 09:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 84
Регистрация: 19.8.2008

Репутация: нет
Всего: 3



Можно, но просто заменить в тексте "Udp" на "Tcp" не получится.

з.ы. у меня в локалке юдп пакеты не теряются. Если юдп не с гарантированной доставкой, это не значит, что он не работает. Не стоит использовать TCP не обоснованно
PM MAIL ICQ   Вверх
SABROG
Дата 26.11.2008, 09:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Hacker
****


Профиль
Группа: Завсегдатай
Сообщений: 2481
Регистрация: 18.9.2006

Репутация: 81
Всего: 91



Посмотри Loopback Example, думаю его можно чуток доработать, чтобы не только с локалхостом работал.


--------------------
Национальная группа Russian Federation на QtCentre.
PM MAIL   Вверх
shutffl
Дата 26.11.2008, 09:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 171
Регистрация: 18.8.2008

Репутация: нет
Всего: 3



Спасибо за ответы. Буду разбираться. По результатам отпишусь.
--------------------
shadowmoon
PM MAIL   Вверх
shutffl
Дата 26.11.2008, 10:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 171
Регистрация: 18.8.2008

Репутация: нет
Всего: 3



Взял за основу Loopback.

test_net_serv.h:
Код

#ifndef TEST_NET_SERV_H
#define TEST_NET_SERV_H

#include <QtGui/QWidget>
#include <QTcpServer>
#include <QTcpSocket>
#include <QHostAddress>
#include <QMessageBox>
#include "ui_test_net_serv.h"

class test_net_serv : public QWidget
{
    Q_OBJECT

public:
    test_net_serv(QWidget *parent = 0);
    ~test_net_serv();

public slots:
    void
    NewClient();
    void
    GetMessage();

private:
    Ui::test_net_servClass ui;

    QTcpServer *server;
    QTcpSocket *client;
    QHostAddress s_address;
    quint16 s_port;
    quint32 bytes;
};

#endif // TEST_NET_SERV_H


test_net_serv.cpp:
Код

#include "test_net_serv.h"

test_net_serv::test_net_serv(QWidget *parent)
    : QWidget(parent)
{
    ui.setupUi(this);

    server = new QTcpServer(this);
    s_address.setAddress("127.0.0.1");
    s_port = 30010;
    server->listen(s_address, s_port);
    connect(server, SIGNAL(newConnection()), this, SLOT(NewClient()));
    bytes = 0;
}

test_net_serv::~test_net_serv()
{

}

void
test_net_serv::NewClient() {
  client = server->nextPendingConnection();
  QMessageBox::information(this, "info","new cl",QMessageBox::Ok);
  connect(client, SIGNAL(readReady()),this,SLOT(GetMessage()));
  server->close();
}

void
test_net_serv::GetMessage() {
  bytes += (quint32)client->bytesAvailable();
  QByteArray data = client->readAll();
  ui.textEdit->append(data);
}


test_net_cli.h:
Код

#ifndef TEST_NET_CLI_H
#define TEST_NET_CLI_H

#include <QtGui/QWidget>
#include <QTcpSocket>
#include <QHostAddress>
#include <QByteArray>
#include <QMessageBox>
#include "ui_test_net_cli.h"

class test_net_cli : public QWidget
{
    Q_OBJECT

public:
    test_net_cli(QWidget *parent = 0);
    ~test_net_cli();

public slots:
    void
    SendMessage();
    void
    displayError(QAbstractSocket::SocketError socketError);

private:
    Ui::test_net_cliClass ui;

    QTcpSocket *client;
    QHostAddress s_address;
    quint16 s_port;
    QByteArray data;
};

#endif // TEST_NET_CLI_H


test_net_cli.cpp:
Код

#include "test_net_cli.h"

test_net_cli::test_net_cli(QWidget *parent)
    : QWidget(parent)
{
    ui.setupUi(this);

    s_port = 30010;
    s_address.setAddress("127.0.0.1");
    client = new QTcpSocket;
    client->connectToHost(s_address, s_port);
    if (client->isValid())
      QMessageBox::information(this, "info", "cl start", QMessageBox::Ok);
    connect(client, SIGNAL(connected()),this,SLOT(SendMessage()));
    connect(client, SIGNAL(error(QAbstractSocket::SocketError)),this, SLOT(displayError(QAbstractSocket::SocketError)));
    data.append("Client started!");
}

test_net_cli::~test_net_cli()
{

}

void
test_net_cli::SendMessage() {
  client->write(data);
}

void test_net_cli::displayError(QAbstractSocket::SocketError socketError)
 {
     if (socketError == QTcpSocket::RemoteHostClosedError)
         return;

     QMessageBox::information(this, tr("Network error"),
                              tr("The following error occurred: %1.")
                              .arg(client->errorString()));

     client->close();
 }


И сервер, и клиент выводят сообщения (один, что подключился; другой, что есть клиент).
Данных нет.
--------------------
shadowmoon
PM MAIL   Вверх
SABROG
Дата 26.11.2008, 12:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Hacker
****


Профиль
Группа: Завсегдатай
Сообщений: 2481
Регистрация: 18.9.2006

Репутация: 81
Всего: 91



А оригинальный example работает ? Посмотри в консоли, может ругается где-нибудь на коннекты.


--------------------
Национальная группа Russian Federation на QtCentre.
PM MAIL   Вверх
shutffl
Дата 26.11.2008, 13:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 171
Регистрация: 18.8.2008

Репутация: нет
Всего: 3



Оригинал работает. Какая-то ошибка у меня.
--------------------
shadowmoon
PM MAIL   Вверх
shutffl
Дата 27.11.2008, 11:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 171
Регистрация: 18.8.2008

Репутация: нет
Всего: 3



Коль никто и ничего путного не добавил, добавлю я.

Пример клиент-сервера на основе Loopback. Протокор TCP.

test_net_serv.h
Код

#ifndef TEST_NET_SERV_H
#define TEST_NET_SERV_H

#include <QtGui/QWidget>
#include <QTcpServer>
#include <QTcpSocket>
#include <QHostAddress>
#include <QMessageBox>
#include "ui_test_net_serv.h"

class test_net_serv : public QWidget
{
    Q_OBJECT

public:
    test_net_serv(QWidget *parent = 0);
    ~test_net_serv();

public slots:
    void
    NewClient();
    void
    GetMessage();

private:
    Ui::test_net_servClass ui;

    QTcpServer *server;
    QTcpSocket *client;
    QHostAddress s_address;
    quint16 s_port;
    qint64 bytes;
};

#endif // TEST_NET_SERV_H



test_net_serv.cpp
Код

#include "test_net_serv.h"

test_net_serv::test_net_serv(QWidget *parent)
    : QWidget(parent)
{
    ui.setupUi(this);

    server = new QTcpServer(this);
    s_address.setAddress("127.0.0.1");
    s_port = 30010;
    server->listen(s_address, s_port);
    connect(server, SIGNAL(newConnection()), this, SLOT(NewClient()));
    connect(server, SIGNAL(readReady()),this,SLOT(GetMessage()));
    bytes = 0;
}

test_net_serv::~test_net_serv()
{

}

void
test_net_serv::NewClient() {
  client = server->nextPendingConnection();
  ui.textEdit->append(tr("New client from ") + client->peerAddress().toString());
  client->write("hey");
  connect(client, SIGNAL(readyRead()),this,SLOT(GetMessage()));
  //server->close();
}

void
test_net_serv::GetMessage() {
  if(0 < client->bytesAvailable()) {
    bytes += client->bytesAvailable();
    ui.textEdit->append("bytes: "+QString::number(bytes));
    QByteArray data = client->readAll();
    ui.textEdit->append(data);
  }
}



test_net_cli.h
Код

#ifndef TEST_NET_CLI_H
#define TEST_NET_CLI_H

#include <QtGui/QWidget>
#include <QTcpSocket>
#include <QHostAddress>
#include <QByteArray>
#include <QMessageBox>
#include "ui_test_net_cli.h"

class test_net_cli : public QWidget
{
    Q_OBJECT

public:
    test_net_cli(QWidget *parent = 0);
    ~test_net_cli();

public slots:
    void
    SendMessage();
    void
    GetMessage();
    void
    LogMessage(qint64 bytes);
    void
    displayError(QAbstractSocket::SocketError socketError);

private:
    Ui::test_net_cliClass ui;

    QTcpSocket *client;
    QHostAddress s_address;
    quint16 s_port;
    QByteArray data;
};

#endif // TEST_NET_CLI_H



test_net_cli.cpp
Код

#include "test_net_cli.h"

test_net_cli::test_net_cli(QWidget *parent)
    : QWidget(parent)
{
    ui.setupUi(this);

    s_port = 30010;
    s_address.setAddress("127.0.0.1");
    client = new QTcpSocket;
    client->connectToHost(s_address, s_port);
    //if (client->isValid())
      //QMessageBox::information(this, "info", "cl start", QMessageBox::Ok);
    connect(client, SIGNAL(connected()),this,SLOT(SendMessage()));
    connect(client, SIGNAL(readyRead()),this,SLOT(GetMessage()));
    //connect(client,SIGNAL(bytesWritten(qint64)),this,SLOT(LogMessage(qint64)));
    connect(client, SIGNAL(error(QAbstractSocket::SocketError)),this, SLOT(displayError(QAbstractSocket::SocketError)));
    data.append("Client started!");
}

test_net_cli::~test_net_cli()
{

}

void
test_net_cli::SendMessage() {
  client->write(data);
}

void
test_net_cli::LogMessage(qint64 bytes) {
  ui.textEdit->append(QString::number(bytes));
}

void
test_net_cli::GetMessage() {
  ui.textEdit->setText(client->readAll());
}

void test_net_cli::displayError(QAbstractSocket::SocketError socketError)
 {
     if (socketError == QTcpSocket::RemoteHostClosedError)
         return;

     QMessageBox::critical(this, tr("Network error"),
                              tr("The following error occurred: %1.")
                              .arg(client->errorString()));

     client->close();
 }



Вот так оно выглядит после старта:
user posted image
--------------------
shadowmoon
PM MAIL   Вверх
SABROG
Дата 27.11.2008, 11:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Hacker
****


Профиль
Группа: Завсегдатай
Сообщений: 2481
Регистрация: 18.9.2006

Репутация: 81
Всего: 91



Я бы вчера позаморачивался, но уж больно лень было копировать исходники из форума, создавать файлы, .pro файл. Если бы выложил аттачем, то другое дело.

В чем ошибка в итоге была у тебя ? Что-то мне не верится что дело в server->close(). Как ни старался не нашел я в этом методе закрытия сокетов клиентов, только работа со списком очередей.

Вообще написано, что сокет должен сразу отправлять данные при возвращении в QEventLoop. Но кто знает, может быть слово типа "hey" слишком короткое и сокет ждет, когда буфер данных наполнится.

Это сообщение отредактировал(а) SABROG - 27.11.2008, 12:01


--------------------
Национальная группа Russian Federation на QtCentre.
PM MAIL   Вверх
shutffl
Дата 28.11.2008, 13:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 171
Регистрация: 18.8.2008

Репутация: нет
Всего: 3



Вот так вот, из-за лени, люди не могут узнать или понять что-то новое))))

По теме.

Если честно, точно сказать не могу, что я сделал, чтобы оно заработало.
Конкретно было сделано:
1. Исправил readReady() на readyRead(). Зверский косяк.
2. Добавил в клиент connect(client, SIGNAL(readyRead()),this,SLOT(GetMessage()));
3. Добавил в сервер client->write("hey");
4. Добавил в сервер connect(server, SIGNAL(readReady()),this,SLOT(GetMessage()));

Вроде, все.

Вообще, изначально планировалось, что клиент просто подключается и отсылает сообщение, без протокольного взаимодействия с сервером (т.е. сервер ничего явно посылать не должен). Поэтому появилась идея сделать заглушку на обмене (пункт 2). А вывод сообщения сделан только для тестирования. Сами понимаете, мона было и не писать в TextEdit ничего. На самом деле, в клиенте его даже не было изначально. Тупо форма была.

Проекты добавил.

PS.
Я понимаю, что я на этом форуме как крестьянин до отмены крепостного права. Но не кажется ли публике, что форум создан для получения информации?
Если есть еще какие-то замечания по коду - буду рад услышать.

Это сообщение отредактировал(а) shutffl - 28.11.2008, 13:29

Присоединённый файл ( Кол-во скачиваний: 150 )
Присоединённый файл  qt.7z 591,09 Kb
--------------------
shadowmoon
PM MAIL   Вверх
SABROG
Дата 28.11.2008, 16:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Hacker
****


Профиль
Группа: Завсегдатай
Сообщений: 2481
Регистрация: 18.9.2006

Репутация: 81
Всего: 91



Цитата(shutffl @  28.11.2008,  13:27 Найти цитируемый пост)
Вот так вот, из-за лени, люди не могут узнать или понять что-то новое))))

Скорее не из-за лени, а из-за того, что искать косяк не так интересно, как придумывать велосипед.

Цитата(shutffl @  28.11.2008,  13:27 Найти цитируемый пост)
Если есть еще какие-то замечания по коду - буду рад услышать.

Если все работает и ты получил ответ, то какие могут быть замечания по коду ? Или ты хочешь направить свой код в качестве example'a в Нокию, чтобы они его включили в дистрибутив ? Пометь тему решеной, если вопросов больше нет.


--------------------
Национальная группа Russian Federation на QtCentre.
PM MAIL   Вверх
timofius111
  Дата 20.6.2011, 01:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 2
Регистрация: 20.6.2011

Репутация: нет
Всего: нет



Добрый вечер!
Сразу скажу, что во всём, что связано с сетью, я дичайше нуб(
В общем нужно сделать на qt самый простой сетевой чат.
Если я всё правильно понял, вышеприведённый чат мне вполне подходит. Он скомпилился (сначала сервер, потом клиент), вроде они законнектились (сервер написал, что всё ок, есть новый клиент). Одного не пойму, как отправлять сообщения? 
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С/С++: Кроссплатформенное программирование, QT/Gtk+/wxWidgets"
JackYF
Любитель
  • В заголовке темы в квадратных скобках обозначьте используемую вами библиотеку, например: [QT],[GTK],[wx].
  • Если вопрос актуален только для некоторой версии библиотеки, либо, если вы пользуетесь не самой последней версией, укажите это. Например: [QT4], [GTK2].
  • Все начинающие изучать Qt - не забудьте зайти сюда.
  • Проставьте несколько ключевых слов темы, чтобы её можно было легче найти.
  • В вопросе укажите полную версию версию библиотеки, а также все дополнительные используемые программные пакеты.
  • Не забывайте пользоваться кнопкой "Код".
  • Телепатов на форуме нет! Задавайте чёткий, конкретный и полный вопрос. Указывайте полностью ошибки компилятора и компоновщика.
  • Новое сообщение должно иметь прямое отношение к тематике этого раздела. Флуд, флейм, оффтопик запрещены.
  • Категорически запрещается обсуждение вареза, "кряков", взлома программ и т.д.

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, JackYF, Любитель.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | С/С++: Кроссплатформенное программирование, Qt/Gtk+/wxWidgets | Следующая тема »


 




[ Время генерации скрипта: 0.0882 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.