Форум программистов, компьютерный форум, киберфорум
Наши страницы
Boost C++
Войти
Регистрация
Восстановить пароль
 
 
Рейтинг 4.62/13: Рейтинг темы: голосов - 13, средняя оценка - 4.62
lawliet93
17 / 5 / 3
Регистрация: 22.03.2011
Сообщений: 329
1

Ip::udp::socket.async_receive_from. Как передать дополнительные аргументы в callback

14.10.2014, 00:19. Просмотров 2563. Ответов 32
Метки нет (Все метки)

Прив. Есть такой код

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <cstdlib>
#include <iostream>
#include <boost\asio.hpp>
 
using namespace boost::asio;
 
io_service service;
ip::udp::socket sock(service);
char buff[1024];
 
 
void receive_callback(const boost::system::error_code& ec, std::size_t bytes_transferred)
{
    std::cout << "Got " << bytes_transferred<< " bytes" <<std::endl;
    sock.async_receive(buffer(buff), receive_callback);
}
 
int main()
{
    try{
        ip::udp::endpoint endPoint(ip::udp::v4(), 9050);
        sock.open(ip::udp::v4());
        sock.bind(endPoint);
        ip::udp::endpoint senderEP;
        sock.async_receive_from(buffer(buff), senderEP, 0, receive_callback);
 
        service.run();
    }
    catch (std::exception ex)
    {
        std::cout <<"Error: " << ex.what() << std::endl; 
    }
 
    system("pause>>void");
    return 0;
}
Как видите, здесь выполняется прослушивание порта 9050 на наличие приходящих данных, или как-то так.
В общем, суть в том, что мне очень нужно передать в метод receive_callback свои данные.
В C#, с его асинхронными методами BeginИмяМетода это все можно было легко сделать, передав нужный параметр, и получив его в методе callback'e.
Но как это сделать в C++?
0
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
14.10.2014, 00:19
Ответы с готовыми решениями:

Как передать аргументы в консольное приложение в одну строку?
Не могу понять, как в windows можно передать аргументы cin'у с помощью командной строки в одну...

При boost::scoped_ptr<udp::socket> reset вылетает 0xC0000005
В конструктор класса подаются io_service и int port. На строчке в конструкторе ...

Boost::asio::ip::udp::socket bind а мне нужен не локальный хост
Здравствуйте. Пытаюсь наладить для своих нужд пример #include &lt;iostream&gt; #include &lt;string&gt;...

For_each и аргументы callback-функции; Как передать callback'у больше одного аргумента
Изучаю контейнеры и алгоритмы stl по Майерсу . С непривычки слегка охренел и запутался в них . В...

Как передать callback функцию?
Добрый вечер. Как в классе передать callback функцию? Хочу ее использовать в array_filter....

32
ForEveR
В астрале
Эксперт С++
8003 / 4761 / 653
Регистрация: 24.06.2010
Сообщений: 10,547
Завершенные тесты: 3
15.10.2014, 17:27 21
lawliet93, А это уже вам решать каким он должен быть. Но то, что он должен быть это факт. Порты можно выбирать рандомно, явно указывать при запуске программы / в конфиге или как-то еще, это уже не суть важно.
0
lawliet93
17 / 5 / 3
Регистрация: 22.03.2011
Сообщений: 329
15.10.2014, 17:29  [ТС] 22
ForEveR, да все важно.
Если я буду заранее определять порт, то не смогу запустить два клиента на одном компе.
А если рандомно, то как сервер должен узнать - на какой порт отправлять? эт разве что только клиент должен отправлять данные о своем порте серверу.
0
ForEveR
В астрале
Эксперт С++
8003 / 4761 / 653
Регистрация: 24.06.2010
Сообщений: 10,547
Завершенные тесты: 3
15.10.2014, 17:40 23
lawliet93, Эм. Вы не заметили, что async_receive_from принимает endpoint по ссылке? Он сохраняет в переданной ссылке endpoint с которого пришел клиент.
Можно так же работать без bind - приложение будет открыто на рандомном порте.
Примеры
Сервер

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#include <cstdlib>
#include <iostream>
#include <list>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/array.hpp>
 
using namespace boost::asio;
 
class UdpSimpleServer{
private:
    ip::udp::socket socket1;
    std::array<char, 1024> buff;
    int port;
 
    void receive_callback(const boost::system::error_code &err, std::size_t bytes_transfered)
    {
        buff[bytes_transfered] = '\0';
        std::cout<< "got: " << buff.data() << std::endl;
        socket1.send_to(buffer(buff, bytes_transfered), client_endpoint_);
        socket1.async_receive_from(buffer(buff), client_endpoint_, boost::bind(&UdpSimpleServer::receive_callback, this,
            boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
    }
 
public:
    UdpSimpleServer(io_service &service,int port) :socket1(service){
        UdpSimpleServer::port = port;
    }
    void Start()
    {
        try{
            socket1.open(ip::udp::v4());
            socket1.bind(ip::udp::endpoint(ip::address_v4::from_string("0.0.0.0"), port));
            
            socket1.async_receive_from(buffer(buff), client_endpoint_, boost::bind(&UdpSimpleServer::receive_callback, this,
                boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
        }
        catch (std::exception ex)
        {
            std::cout << "Error: " << ex.what() << std::endl;
        }
    }
 
    ip::udp::endpoint client_endpoint_;
};
 
int main()
{
    io_service service;
    UdpSimpleServer server(service, 9050);
    server.Start();
    service.run();
 
    std::cin.get();
    return 0;
}
Клиент:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#include <cstdlib>
#include <iostream>
#include <list>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/array.hpp>
#include <boost/thread.hpp>
 
using namespace boost::asio;
 
io_service ios;
 
class Client
{
public:
   Client(int port) : socket_(ios)
   {
      receiver_ = ip::udp::endpoint(ip::address_v4::from_string("127.0.0.1"), port);
 
      socket_.open(ip::udp::v4());
      socket_.async_receive_from(buffer(buffer_), receiver_, boost::bind(&Client::on_receive, this, placeholders::error, placeholders::bytes_transferred));
   }
   void send(const std::string& msg)
   {
      std::copy(msg.begin(), msg.end(), buffer_.begin());
      socket_.async_send_to(buffer(buffer_, msg.size()), receiver_, boost::bind(&Client::on_send, this, placeholders::error, placeholders::bytes_transferred));
   }
private:
 
   void on_send(const boost::system::error_code& ec, const size_t bytes)
   {
      std::cout << "sended " << bytes << " bytes with " << ec.message() << std::endl;
   }
 
   void on_receive(const boost::system::error_code& ec, const size_t bytes)
   {
      std::cout << "received " << bytes << " bytes with " << ec.message() << std::endl;
      buffer_[bytes] = '\0';
      std::cout << buffer_.data() << std::endl;
   }
 
   ip::udp::socket socket_;
   std::array<char, 1024> buffer_;
   ip::udp::endpoint receiver_;
};
 
int main()
{
   Client client(9050);
   client.send("hello");
   ios.run();
}


Добавлено через 2 минуты
При запуске сервера, затем клиента.
Со стороны сервера:
got: hello
Со стороны клиента:
sended 5 bytes with Success
received 5 bytes with Success
hello

Добавлено через 1 минуту
Я вас наверное запутал сначала, когда начал отвечать. Давно не связывался с boost::asio::udp. Освежил память - теперь говорю как есть.
1
lawliet93
17 / 5 / 3
Регистрация: 22.03.2011
Сообщений: 329
15.10.2014, 21:07  [ТС] 24
ForEveR, вот добавил я строку
C++
1
socket_.async_receive_from(buffer(buffer_), receiver_, boost::bind(&Client::on_receive, this, placeholders::error, placeholders::bytes_transferred));
в конец метода on_receive, и когда запускаю клиент, то идет принятие 0 байтов, а еще текст ошибок нормально не отображается, почему-то :c
0
Миниатюры
Ip::udp::socket.async_receive_from. Как передать дополнительные аргументы в callback  
ForEveR
В астрале
Эксперт С++
8003 / 4761 / 653
Регистрация: 24.06.2010
Сообщений: 10,547
Завершенные тесты: 3
16.10.2014, 08:46 25
lawliet93, Весь код в студию.
0
lawliet93
17 / 5 / 3
Регистрация: 22.03.2011
Сообщений: 329
16.10.2014, 09:29  [ТС] 26
ForEveR, не верете мне?? не верете??????
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#include <cstdlib>
#include <iostream>
#include <list>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/array.hpp>
#include <boost/thread.hpp>
 
using namespace boost::asio;
 
io_service ios;
 
class Client
{
public:
    Client(int port) : socket_(ios)
    {
        receiver_ = ip::udp::endpoint(ip::address_v4::from_string("127.0.0.1"), port);
 
        socket_.open(ip::udp::v4());
        socket_.async_receive_from(buffer(buffer_), receiver_, boost::bind(&Client::on_receive, this, placeholders::error, placeholders::bytes_transferred));
    }
    void send(const std::string& msg)
    {
        std::copy(msg.begin(), msg.end(), buffer_.begin());
        socket_.async_send_to(buffer(buffer_, msg.size()), receiver_, boost::bind(&Client::on_send, this, placeholders::error, placeholders::bytes_transferred));
    }
private:
 
    void on_send(const boost::system::error_code& ec, const size_t bytes)
    {
        std::cout << "sended " << bytes << " bytes with " << ec.message() << std::endl;
    }
 
    void on_receive(const boost::system::error_code& ec, const size_t bytes)
    {
        std::cout << "received " << bytes << " bytes with " << ec.message() << std::endl;
        buffer_[bytes] = '\0';
        std::cout << buffer_.data() << std::endl;
        socket_.async_receive_from(buffer(buffer_), receiver_, boost::bind(&Client::on_receive, this, placeholders::error, placeholders::bytes_transferred));
    }
 
    ip::udp::socket socket_;
    std::array<char, 1024> buffer_;
    ip::udp::endpoint receiver_;
};
 
int main()
{
    Client client(9050);
    client.send("hello");
    ios.run();
}
0
ForEveR
В астрале
Эксперт С++
8003 / 4761 / 653
Регистрация: 24.06.2010
Сообщений: 10,547
Завершенные тесты: 3
16.10.2014, 10:29 27
lawliet93, receive handler не должен вызываться просто так. Значит откуда-то прилетает запрос на клиент.
0
lawliet93
17 / 5 / 3
Регистрация: 22.03.2011
Сообщений: 329
16.10.2014, 11:59  [ТС] 28
ForEveR, очень странно, первые 0 байт приходят от порта 9050, хотя сервер не работает. А второе от порта 0. Первое сообщение приходит с кодом ошибки 10022, а второе с 10054.
Порт менял пару раз, каждый раз эта же проблема.
0
ForEveR
В астрале
Эксперт С++
8003 / 4761 / 653
Регистрация: 24.06.2010
Сообщений: 10,547
Завершенные тесты: 3
16.10.2014, 12:05 29
lawliet93, У меня не удается это воспроизвести. Скиньте так же код сервера. Включите сервер, включите клиент. Попосылайте запросы с клиента на сервер. Скиньте вывод клиента/сервера. Так же выводите ошибки через e.message() и никак иначе.
П.С. проверьте какая установлена кодировка, очень странно, что ошибки выводятся неверно.
0
lawliet93
17 / 5 / 3
Регистрация: 22.03.2011
Сообщений: 329
16.10.2014, 12:53  [ТС] 30
ForEveR, код сервера (вообще я его не переделывал почти, вроде)
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
    #include <cstdlib>
    #include <iostream>
    #include <boost\asio.hpp>
    #include <boost\bind.hpp>
    #include <boost\array.hpp>
 
    using namespace boost::asio;
 
    class Client{
 
    public:
        Client(ip::udp::endpoint endP) :endPoint(endP.address(), endP.port()){}
        ip::udp::endpoint endPoint;
        bool Compare(Client &other)
        {
            if (other.endPoint.address() == endPoint.address() && other.endPoint.port() == endPoint.port())
            {
                return true;
            }
            else
            {
                return false;
            }
        }
 
    };
 
    class UdpSimpleServer{
    private:
        ip::udp::socket socket1;
        std::array<char, 1024> buff;
        std::list<Client> clients;
        ip::udp::endpoint endpoint;
        int port;
 
        void receive_callback(const boost::system::error_code &err, std::size_t bytes_transfered)
        {
            std::cout << "We got " << bytes_transfered << " bytes from port: " << endpoint.port() << std::endl;
            if (bytes_transfered > 0){
                buff[bytes_transfered] = '\0';
                std::cout << buff.data() << std::endl;
 
                Client client(endpoint);
 
                bool add = false;
 
                if (clients.size() > 0)
                {
                    for each (Client cl in clients)
                    {
                        if (client.Compare(cl))
                        {
                            add = true;
                            break;
                        }
                    }
                }
 
                if (!add)
                {
                    std::cout << "Add new client" << std::endl;
                    clients.push_back(client);
                    std::cout << "We have " << clients.size() << " clients now" << std::endl;
                }
                if (clients.size() > 1)
                {
                    for each (Client cl in clients)
                    {
                        if (!client.Compare(cl))
                        {
                            socket1.send_to(buffer(buff), cl.endPoint);
                            std::cout << "Sent data to: " << cl.endPoint.port() << std::endl;
                        }
                    }
                }
            }
 
            std::cout << std::endl;
 
            socket1.async_receive_from(buffer(buff), endpoint, boost::bind(&UdpSimpleServer::receive_callback, this,
                boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
        }
 
    public:
        UdpSimpleServer(io_service &service, int port) :socket1(service){
            UdpSimpleServer::port = port;
        }
 
        void Start()
        {
            try{
                socket1.open(ip::udp::v4());
                socket1.bind(ip::udp::endpoint(ip::address_v4::from_string("0.0.0.0"), port));
 
                socket1.async_receive_from(buffer(buff), endpoint, boost::bind(&UdpSimpleServer::receive_callback, this,
                    boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
            }
            catch (std::exception ex)
            {
                std::cout << "Error: " << ex.what() << std::endl;
            }
        }
    };
 
    int main()
    {
        io_service service;
        UdpSimpleServer server(service, 9050);
        server.Start();
        service.run();
 
        std::cin.get();
        return 0;
    }
Значит, запускаю сначала сервер, потом клиент, в клиенте отправляю 3 сообщение подряд, вот так
C++
1
2
3
4
5
6
7
8
9
int main()
{
    setlocale(LC_ALL, "");
    Client client(9050);
    client.send("hello1");
    client.send("hello2");
    client.send("hello3");
    ios.run();
}
0
Миниатюры
Ip::udp::socket.async_receive_from. Как передать дополнительные аргументы в callback  
ForEveR
В астрале
Эксперт С++
8003 / 4761 / 653
Регистрация: 24.06.2010
Сообщений: 10,547
Завершенные тесты: 3
16.10.2014, 14:42 31
lawliet93, Не знаю в чем проблема. У меня не удается это воспроизвести. Можете проверять ec на то, что он успешен и только тогда обрабатывать запрос.

Мой вывод с вашим кодом.
Клиент:
sended 6 bytes with Success
sended 6 bytes with Success
sended 6 bytes with Success
Сервер:
We got 6 bytes from port: 44549
hello1
Add new client
We have 1 clients now

We got 6 bytes from port: 44549
hello2

We got 6 bytes from port: 44549
hello3
0
lawliet93
17 / 5 / 3
Регистрация: 22.03.2011
Сообщений: 329
16.10.2014, 15:23  [ТС] 32
ForEveR, у меня есть один просьба к вам. Запустите сервак, потом клиент. Потом закройте клиент и запустите еще раз.
У меня при этом на сервере творится какая-то белеберда.
И еще, какая у вас ОС?
0
ForEveR
В астрале
Эксперт С++
8003 / 4761 / 653
Регистрация: 24.06.2010
Сообщений: 10,547
Завершенные тесты: 3
17.10.2014, 13:50 33
lawliet93, Ubuntu 14.04.
После исправления на клиенте
C++
1
if (client.Compare(cl))
в вашем коде здесь было !client.Compare что не особо логично для теста, вывод такой:
Клиент:
Bash
1
2
3
4
5
6
7
8
9
10
11
12
13
14
./client 
sended 6 bytes with Success
sended 6 bytes with Success
sended 6 bytes with Success
./client 
sended 6 bytes with Success
sended 6 bytes with Success
sended 6 bytes with Success
received 1024 bytes with Success
hello1
received 1024 bytes with Success
hello2
received 1024 bytes with Success
hello3
Сервер:
Bash
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
./new
We got 6 bytes from port: 38489
hello1
Add new client
We have 1 clients now
 
We got 6 bytes from port: 38489
hello2
 
We got 6 bytes from port: 38489
hello3
 
We got 6 bytes from port: 37434
hello1
Add new client
We have 2 clients now
Sent data to: 37434
 
We got 6 bytes from port: 37434
hello2
Sent data to: 37434
 
We got 6 bytes from port: 37434
hello3
Sent data to: 37434
Добавлено через 20 часов 30 минут
lawliet93, Кстати, с моей точки зрения, намного веселее использовать сопрограммы. Вот как выглядят простые сервер/клиент на сопрограммах. Все выполняется асинхронно.
Примеры
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
#include <cstdlib>
#include <iostream>
#include <list>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/array.hpp>
#include <boost/asio/spawn.hpp>
 
using namespace boost::asio;
 
class UdpSimpleServer{
private:
  ip::udp::socket socket1;
  int port;
 
  void receiver(boost::asio::yield_context yield)
  {
     for (;;)
     {
        std::array<char, 1024> buff;
        ip::udp::endpoint endpoint;
        boost::system::error_code ec;
        std::size_t bytes_transfered = socket1.async_receive_from(buffer(buff), endpoint, yield[ec]);
        std::cout << "We got " << bytes_transfered << " bytes " << ec.message() << " from port: " << endpoint.port() << std::endl;
        const std::string received(buff.begin(), buff.begin() + bytes_transfered);
        if (bytes_transfered > 0)
        {
           std::cout << "received: " << received << " send it to client" << std::endl;
           bytes_transfered = socket1.async_send_to(buffer(received), endpoint, yield[ec]);
           std::cout << "Sended " << bytes_transfered << " bytes " << ec.message() << std::endl;
        }
     }
  }
 
public:
  UdpSimpleServer(io_service &service, int port) :socket1(service){
      UdpSimpleServer::port = port;
  }
 
  void Start()
  {
      try{
          socket1.open(ip::udp::v4());
          socket1.bind(ip::udp::endpoint(ip::address_v4::from_string("0.0.0.0"), port));
          boost::asio::spawn(socket1.get_io_service(), boost::bind(&UdpSimpleServer::receiver, this, _1));
      }
      catch (std::exception ex)
      {
          std::cout << "Error: " << ex.what() << std::endl;
      }
  }
};
 
int main()
{
  io_service service;
  UdpSimpleServer server(service, 9050);
  server.Start();
  service.run();
 
  std::cin.get();
  return 0;
}
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#include <cstdlib>
#include <iostream>
#include <queue>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/array.hpp>
#include <boost/asio/spawn.hpp>
 
using namespace boost::asio;
 
io_service ios;
 
class Client
{
public:
    Client(int port) : socket_(ios)
    {
        receiver_ = ip::udp::endpoint(ip::address_v4::from_string("127.0.0.1"), port);
        socket_.open(ip::udp::v4());
    }
 
    void spawn_task()
    {
       spawn(ios, boost::bind(&Client::sender, this, _1));
    }
 
    void send(const std::string& message)
    {
       queue.push(message);
    }
 
private:
    void sender(boost::asio::yield_context yield)
    {
       for (;;)
       {
         while (!queue.empty())
         {
            const std::string message = queue.front();
            queue.pop();
            boost::system::error_code ec;
            size_t bytes = socket_.async_send_to(buffer(message), receiver_, yield[ec]);
            std::cout << "sended " << bytes << " " << ec.message() << std::endl;
            std::array<char, 1024> buff;
            bytes = socket_.async_receive_from(buffer(buff), receiver_, yield);
            std::cout << "received " << bytes << " " << ec.message() << " " << std::string(buff.begin(), buff.begin() + bytes) << std::endl;
         }
       }
    }
    ip::udp::socket socket_;
    ip::udp::endpoint receiver_;
    std::queue<std::string> queue;
};
 
int main()
{
    Client client(9050);
    client.spawn_task();
    client.send("message");
    client.send("message2");
    ios.run();
}
1
17.10.2014, 13:50
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
17.10.2014, 13:50

Как в Qt передать указатель на CallBack функцию WinAPI ? :-)
Есть ли в Qt такое понятие как CallBack или нет? Конечно же тут проскакивает аналогия со слотом,...

WCF Callback for UDP
Как в WCF, получая и отправляя данные по UDP использовать Callback? IScreenCallback callback =...

addEventListener - дополнительные аргументы
Здравствуйте. ActionScript знаю довольно плохо, поэтому требуется помощь) Конечно, мог бы...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
33
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2019, vBulletin Solutions, Inc.
Рейтинг@Mail.ru