मैं एक udp क्लाइंट पूल बना रहा हूं। सर्वर विभिन्न कंप्यूटरों में चलने वाले कुछ अन्य अनुप्रयोग होंगे, और उन्हें शुरू से ही जीवित रहने के लिए माना जाता है। एक विन्यास योग्य फ़ाइल का उपयोग करना (उदाहरण के लिए समस्या के लिए महत्वपूर्ण नहीं है इसलिए इसमें शामिल नहीं है) एक से कई क्लाइंट बनाए जाते हैं ताकि वे उन सर्वरों (1 से 1 संबंध) को द्विदिश तरीके से भेज और प्राप्त कर सकें।

भेजना सिंक किया जा सकता है क्योंकि यह छोटे संदेशों का उपयोग करता है और वहां कोई समस्या नहीं है, लेकिन प्राप्त करना async होना चाहिए, क्योंकि उत्तर भेजने के बाद बहुत बाद में आ सकता है।

मेरे परीक्षण में केवल एक सॉकेट के साथ, यह भेजने में सक्षम है, लेकिन यह कुछ भी प्राप्त नहीं कर रहा है।

Q1: समस्या कहां है और इसे कैसे ठीक किया जाए?

Q2: मुझे यह भी आश्चर्य होता है कि क्या async कॉल में std::vector से इटरेटर का उपयोग उस समय समस्याग्रस्त हो सकता है जब नए कनेक्शन को मेमोरी में इसके पुनर्व्यवस्था के कारण वेक्टर में धकेल दिया जाता है। यह एक समस्या हो सकती है?

Q3: मैं वास्तव में समझ नहीं पा रहा हूं कि सभी उदाहरणों में प्रेषक और रिसीवर एंडपॉइंट (एंडपॉइंट 1 और एंडपॉइंट 2 उदाहरण के लिए struct Socket) अलग-अलग हैं, क्या वे समान नहीं हो सकते?

मेरा कोड अगला है:

#include <iostream>
#include <boost/array.hpp>
#include <boost/asio.hpp>

using boost::asio::ip::udp;

class Pool
{
    struct Socket {
        std::string id;
        udp::socket socket;
        udp::endpoint endpoint1;
        udp::endpoint endpoint2;
        enum { max_length = 1024 };
        std::array<char, max_length> data;
    };

public:
    void create(const std::string& id, const std::string& host, const std::string& port)
    {
        udp::resolver resolver(io_context);
        sockets.emplace_back(Socket{ id, udp::socket{io_context, udp::v4()}, *resolver.resolve(udp::v4(), host, port).begin() });

        receive(id);
    }

    void send(const std::string& id, const std::string& msg)
    {
        auto it = std::find_if(sockets.begin(), sockets.end(), [&](auto& socket) { return id == socket.id; });
        if (it == sockets.end()) return;

        it->data = std::array<char, Socket::max_length>{ 'h', 'e', 'l', 'l', 'o' };
        auto bytes = it->socket.send_to(boost::asio::buffer(it->data, 5), it->endpoint1);
    }

    void receive(const std::string& id)
    {
        auto it = std::find_if(sockets.begin(), sockets.end(), [&](auto& socket) { return id == socket.id; });
        if (it == sockets.end()) return;

        it->socket.async_receive_from(
            boost::asio::buffer(it->data, Socket::max_length),
            it->endpoint2,
            [this, id](boost::system::error_code error, std::size_t bytes) {
                if (!error && bytes)
                    bool ok = true;//Call to whatever function
                receive(id);
            }
        );
    }

    void poll()
    {
        io_context.poll();
    }

private:
    boost::asio::io_context io_context;
    std::vector<Socket> sockets;
};

int main()
{
    Pool clients;
    clients.create("ID", "localhost", "55000");

    while (true) {
        clients.poll();
        clients.send("ID", "x");
        Sleep(5000);
    }
}
1
Pablo 28 अक्टूबर 2021, 11:56
यूडीपी और द्विदिश?
 – 
Anis Belaid
28 अक्टूबर 2021, 11:58
शायद यूडीपी नेटवर्क सामग्री के लिए सबसे अच्छा शब्द नहीं है ... मेरा मतलब है कि वे एक ही सॉकेट का उपयोग करके भेजने और प्राप्त करने जा रहे हैं।
 – 
Pablo
28 अक्टूबर 2021, 12:02
आप एक ही मशीन में कई udp क्लाइंट का उपयोग नहीं कर सकते हैं
 – 
Anis Belaid
28 अक्टूबर 2021, 12:07
वे इतने नहीं हैं, शायद हम 3 और 10 के बीच की संख्या की बात कर रहे हैं।
 – 
Pablo
28 अक्टूबर 2021, 12:10
हाँ केवल एक क्लाइंट को udp सर्वर पर सुनने की अनुमति है
 – 
Anis Belaid
28 अक्टूबर 2021, 12:14

1 उत्तर

सबसे बढ़िया उत्तर

Q1: समस्या कहां है और इसे कैसे ठीक किया जाए?

आप वास्तव में किसी भी बंदरगाह से बंधे नहीं हैं, और फिर आपके पास अनबाउंड udp पैकेट प्राप्त करने वाले एकाधिक सॉकेट हैं। शायद वे बस प्रतिस्पर्धा कर रहे हैं और भ्रम में कुछ खो जाता है।

Q2: क्या एसटीडी :: वेक्टर समस्याग्रस्त हो सकता है

हां। एक std::deque (स्थिर पुनरावर्तक/संदर्भों का उपयोग करें जब तक आप केवल किसी भी छोर पर धक्का/पॉप करते हैं)। अन्यथा, एक std::list या अन्य नोड-आधारित कंटेनर पर विचार करें।

आपके मामले में map<id, socket> अधिक सहज लगता है।

वास्तव में, map<endpoint, peer> बहुत अधिक सहज ज्ञान युक्त होगा। या... आप साथियों के बिना पूरी तरह से कर सकते हैं।

Q3: मैं वास्तव में समझ नहीं पा रहा हूं कि सभी उदाहरणों में प्रेषक और रिसीवर एंडपॉइंट (उदाहरण के लिए एंडपॉइंट 1 और एंडपॉइंट 2) अलग-अलग क्यों हैं, क्या वे समान नहीं हो सकते?

हाँ, वे "समान" हो सकते हैं यदि आप अपने द्वारा भेजे गए मूल समापन बिंदु को अधिलेखित करने की परवाह नहीं करते हैं।


यहाँ मेरा सरलीकृत लेना है। जैसा कि अन्य ने कहा है, एक ही एंडपॉइंट पर कई यूडीपी सॉकेट "सुनने" के लिए संभव/उपयोगी नहीं है। यही है, बशर्ते कि आप एक समापन बिंदु तक भी सीमित हों।

तो मेरा नमूना स्थानीय समापन बिंदु के साथ एक एकल _socket का उपयोग करता है: 8765।

यह कई क्लाइंट एंडपॉइंट से कनेक्ट हो सकता है - मैंने आईडी स्ट्रिंग को एंडपॉइंट के साथ सरलता के लिए बदलना चुना है। कुछ अनुवाद के लिए बेझिझक map<string, endpoint> जोड़ें।

इसे देखें कोलिरू पर लाइव

#include <boost/asio.hpp>
#include <iomanip>
#include <iostream>
#include <set>

using boost::asio::ip::udp;
using namespace std::chrono_literals;

class Pool {
  public:
    using Message = std::array<char, 1024>;
    using Peers   = std::set<udp::endpoint>;
    using Id      = udp::endpoint;

    Pool() { receive_loop(); }

    Id create(const std::string& host, const std::string& port)
    {
        auto ep = *udp::resolver(_io).resolve(udp::v4(), host, port).begin();
        /*auto [it,ok] =*/_peers.emplace(ep);
        return ep;
    }

    void send(Id id, const std::string& msg)
    {
        /*auto bytes =*/
        _socket.send_to(boost::asio::buffer(msg), id);
    }

    void receive_loop()
    {
        _socket.async_receive_from(
            boost::asio::buffer(_incoming), _incoming_ep,
            [this](boost::system::error_code error, std::size_t bytes) {
                if (!error && bytes)
                {
                    if (_peers.contains(_incoming_ep)) {
                        std::cout << "Received: "
                                  << std::quoted(std::string_view(
                                         _incoming.data(), bytes))
                                  << " from " << _incoming_ep << "\n";
                    } else {
                        std::cout << "Ignoring message from  unknown peer "
                                  << _incoming_ep << "\n";
                    }
                }
                receive_loop();
            });
    }

    void poll() { _io.poll(); }

  private:
    boost::asio::io_context _io;
    udp::socket             _socket{_io, udp::endpoint{udp::v4(), 8765}};
    Message                 _incoming;
    udp::endpoint           _incoming_ep;
    Peers                   _peers;
};

int main(int argc, char** argv) {
    Pool pool;

    std::vector<Pool::Id> peers;

    for (auto port : std::vector(argv + 1, argv + argc)) {
        peers.push_back(pool.create("localhost", port));
    }

    int message_number = 0;
    while (peers.size()) {
        pool.poll();

        auto id = peers.at(rand() % peers.size());
        pool.send(id, "Message #" + std::to_string(++message_number) + "\n");

        std::this_thread::sleep_for(1s);
    }
}

मेरी मशीन पर लाइव कुछ सिम्युलेटेड रिमोट के साथ जैसे

sort -R /etc/dictionaries-common/words | while read word; do sleep 5; echo "$word"; done | netcat -u -l -p 8787 -w 1000

आवारा/अज्ञात संदेशों का अनुकरण करने के लिए "अन्य" समापन बिंदु से फर्जी संदेश भेजना।

enter image description here

1
sehe 28 अक्टूबर 2021, 16:53
ठंडा! मुझे उन सभी udp अवधारणाओं को स्पष्ट करने के लिए धन्यवाद। यदि आप बुरा न मानें तो मैं आपकी पावती का दुरुपयोग करने जा रहा हूं: मेरा पोर्ट नंबर (8765) सेट करना आवश्यक है या यह मान्य होगा यदि मैं ओएस को स्वचालित रूप से इसे एक मुफ्त असाइन करने देता हूं? मुझे लगता है कि यह निजी चर में udp::socket _socket{io_context, udp::v4()}; का उपयोग करके किया जा सकता है।
 – 
Pablo
28 अक्टूबर 2021, 17:20
1
अल्पकालिक बंदरगाह भी ठीक हैं। समापन बिंदु को संप्रेषित करना थोड़ा कम स्वाभाविक है।
 – 
sehe
28 अक्टूबर 2021, 17:51
मुझे फिर से सिखाने के लिए बहुत-बहुत धन्यवाद। आप किसी प्रकार की परामर्श फर्म या इसी तरह की शुरुआत कर सकते हैं, आप इसे "बेटर कॉल सेहे" नाम दे सकते हैं ;-) (यह एक ब्रेकिंग बैड शो मजाक है, अगर आपने इसे नहीं देखा है)
 – 
Pablo
28 अक्टूबर 2021, 18:02
हाहा। चीयर्स। मुझे लगता है कि मेम बीबी से पहले का है? en.wikipedia.org/wiki/Better_Call_Saul मुझे लगता है कि यह पल्प फिक्शन में भी है?
 – 
sehe
28 अक्टूबर 2021, 18:18