كيفية الحصول على عنوان IP (المحلي) الخاص بك من مقبس UDP (C/C++)

StackOverflow https://stackoverflow.com/questions/29890

  •  09-06-2019
  •  | 
  •  

سؤال

  1. لديك محولات شبكة متعددة.
  2. ربط مقبس UDP بمنفذ محلي، دون تحديد عنوان.
  3. تلقي الحزم على أحد المحولات.

كيف يمكنك الحصول على عنوان IP المحلي للمحول الذي استقبل الحزمة؟

والسؤال هو ، "ما هو عنوان IP من محول المتلقي؟" ليس العنوان من المرسل الذي نحصل عليه في

receive_from( ..., &senderAddr, ... );

يتصل.

هل كانت مفيدة؟

المحلول

يمكنك تعداد جميع محولات الشبكة والحصول على عناوين IP الخاصة بها ومقارنة الجزء الذي يغطيه قناع الشبكة الفرعية بعنوان المرسل.

يحب:

IPAddress FindLocalIPAddressOfIncomingPacket( senderAddr )
{
    foreach( adapter in EnumAllNetworkAdapters() )
    {
        adapterSubnet = adapter.subnetmask & adapter.ipaddress;
        senderSubnet = adapter.subnetmask & senderAddr;
        if( adapterSubnet == senderSubnet )
        {
            return adapter.ipaddress;
        }
    }
}

نصائح أخرى

يوم سعيد،

أفترض أنك قمت بالربط باستخدام INADDR_ANY لتحديد العنوان.

إذا كانت هذه هي الحالة، فإن دلالات INADDR_ANY هي أنه يتم إنشاء مقبس UDP على المنفذ المحدد على كافة الواجهات الخاصة بك.سيقوم المقبس بإرسال كافة الحزم إلى جميع الواجهات الموجودة على المنفذ المحدد.

عند الإرسال باستخدام هذا المقبس، يتم استخدام أقل واجهة مرقمة.يتم تعيين حقل عنوان المرسل الصادر على عنوان IP الخاص بالواجهة الصادرة الأولى المستخدمة.

يتم تعريف الواجهة الصادرة الأولى على أنها التسلسل عند إجراء ifconfig -a.من المحتمل أن يكون eth0.

هث.

هتافات ، روب

الحل المقدم من تيمبو يفترض أن نطاقات العناوين فريدة وغير متداخلة.على الرغم من أن هذا هو الحال عادةً، إلا أنه ليس حلاً عامًا.

هناك تنفيذ ممتاز لوظيفة تقوم بالضبط بما تنص عليه في كتاب ستيفن "برمجة شبكة يونكس" (القسم 20.2) هذه وظيفة تعتمد على RECVMSG () ، بدلاً من RECVFROM ().إذا كان الخيار IP_RECVIF ممكّنًا في مأخذ التوصيل الخاص بك، فسيقوم التابع recvmsg() بإرجاع فهرس الواجهة التي تم استلام الحزمة عليها.ويمكن بعد ذلك استخدام هذا للبحث عن عنوان الوجهة.

يتوفر شفرة المصدر هنا.الوظيفة المعنية هي "recvfrom_flags ()"

لسوء الحظ، يتم قطع استدعاءات sendto وrecvfrom API بشكل أساسي عند استخدامها مع مآخذ توصيل مرتبطة بـ "Any IP" لأنها لا تحتوي على حقل لمعلومات IP المحلية.

اذا ماذا تستطيع ان تفعل حيال ذلك؟

  1. يمكنك التخمين (على سبيل المثال بناءً على جدول التوجيه).
  2. يمكنك الحصول على قائمة بالعناوين المحلية وربط مأخذ توصيل منفصل لكل عنوان محلي.
  3. يمكنك استخدام واجهات برمجة التطبيقات الأحدث التي تدعم هذه المعلومات.هناك جزأين لهذا، أولاً عليك استخدام خيار مأخذ التوصيل relavent (ip_recvif لـ IPv4، ipv6_recvif لـ IPv6) لإخبار المكدس أنك تريد هذه المعلومات.ثم يتعين عليك استخدام وظيفة مختلفة (recvmsg على Linux والعديد من الأنظمة الأخرى المشابهة لنظام التشغيل Unix، WSArecvmsg على windows) لتلقي الحزمة.

لا شيء من هذه الخيارات رائع.من الواضح أن التخمين سيؤدي إلى إجابات خاطئة في بعض الأحيان.يؤدي ربط المقابس المنفصلة إلى زيادة تعقيد برنامجك ويسبب مشاكل إذا تغيرت قائمة العناوين المحلية أثناء تشغيل البرنامج.تعد واجهات برمجة التطبيقات الأحدث هي الحل الفني الصحيح ولكنها قد تقلل من إمكانية النقل (يبدو على وجه الخصوص أن WSArecvmsg غير متوفر على نظام التشغيل Windows XP) وقد يتطلب الأمر إجراء تعديلات على مكتبة مجمّع المقبس التي تستخدمها.

يبدو أن التعديل كنت مخطئًا، ويبدو أن وثائق MS مضللة وأن WSArecvmsg متاح على نظام التشغيل Windows XP.يرى https://stackoverflow.com/a/37334943/5083516

ssize_t
     recvfrom(int socket, void *restrict buffer, size_t length, int flags,
         struct sockaddr *restrict address, socklen_t *restrict address_len);

     ssize_t
     recvmsg(int socket, struct msghdr *message, int flags);

[..]
     If address is not a null pointer and the socket is not connection-oriented, the
     source address of the message is filled in.

الكود الفعلي:

int nbytes = recvfrom(sock, buf, MAXBUFSIZE, MSG_WAITALL, (struct sockaddr *)&bindaddr, &addrlen);

fprintf(stdout, "Read %d bytes on local address %s\n", nbytes, inet_ntoa(bindaddr.sin_addr.s_addr));

أتمنى أن يساعدك هذا.

جرب هذا:

gethostbyname("localhost");
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top