سؤال

لنفترض أن لديك برنامجًا يقرأ من مأخذ توصيل.كيف يمكنك الحفاظ على معدل التنزيل أقل من حد معين؟

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

المحلول

في طبقة التطبيق (باستخدام واجهة برمجة تطبيقات نمط مقبس بيركلي)، ما عليك سوى مشاهدة الساعة وقراءة البيانات أو كتابتها بالمعدل الذي تريد تحديده.

إذا كنت تقرأ فقط 10 كيلوبت في الثانية في المتوسط، ولكن المصدر يرسل أكثر من ذلك، ففي النهاية سوف تمتلئ جميع المخازن المؤقتة بينهما.يسمح TCP/IP بذلك، وسيعمل البروتوكول على إبطاء المرسل (في طبقة التطبيق، ربما كل ما تحتاج إلى معرفته هو أنه في الطرف الآخر، سيتم حظر مكالمات الكتابة المحظورة، وستفشل عمليات الكتابة غير المحظورة، وستفشل عمليات الكتابة غير المتزامنة لن تكتمل عمليات الكتابة حتى تقرأ ما يكفي من البيانات للسماح بذلك).

في طبقة التطبيق، يمكنك أن تكون تقريبيًا فقط - ولا يمكنك ضمان الحدود الصارمة مثل "لن يمر أكثر من 10 كيلو بايت من نقطة معينة في الشبكة في أي ثانية واحدة".ولكن إذا قمت بتتبع ما تلقيته، فيمكنك الحصول على المتوسط ​​الصحيح على المدى الطويل.

نصائح أخرى

بافتراض أن النقل عبر الشبكة يعتمد على TCP/IP، يتم إرسال الحزم استجابةً لحزم ACK/NACK التي تسير في الاتجاه الآخر.

ومن خلال الحد من معدل الحزم التي تقر باستلام الحزم الواردة، فإنك ستقوم بدورها بتقليل معدل إرسال الحزم الجديدة.

يمكن أن يكون غير دقيق بعض الشيء، لذلك ربما يكون من الأمثل مراقبة معدل المصب وضبط معدل الاستجابة بشكل تكيفي حتى يقع داخل عتبة مريحة.(سيحدث هذا بسرعة كبيرة، ولكنك ترسل عشرات الردود في الثانية)

يشبه الأمر عند قصر اللعبة على عدد معين من الإطارات في الثانية.

extern int FPS;
....    
timePerFrameinMS = 1000/FPS;

while(1) {
time = getMilliseconds();
DrawScene();
time = getMilliseconds()-time;
if (time < timePerFrameinMS) {
   sleep(timePerFrameinMS - time);
}
}

بهذه الطريقة تتأكد من أن معدل تحديث اللعبة سيكون بحد أقصى FPS.بنفس الطريقة، يمكن أن تكون DrawScene هي الوظيفة المستخدمة لضخ البايتات في دفق المقبس.

إذا كنت تقرأ من مأخذ توصيل، فليس لديك أي سيطرة على النطاق الترددي المستخدم - فأنت تقرأ المخزن المؤقت لنظام التشغيل لهذا المقبس، ولا شيء تقوله سيجعل الشخص الذي يكتب إلى المقبس يكتب بيانات أقل (ما لم يكن ذلك بالطبع ، لقد قمت بوضع بروتوكول لذلك).

كل ما ستفعله القراءة ببطء هو ملء المخزن المؤقت، والتسبب في توقف نهائي في نهاية الشبكة - ولكن لا يمكنك التحكم في كيفية أو وقت حدوث ذلك.

إذا كنت تريد حقًا قراءة قدر كبير من البيانات في المرة الواحدة، فيمكنك القيام بشيء مثل هذا:

ReadFixedRate() {
  while(Data_Exists()) {
    t = GetTime();
    ReadBlock();
    while(t + delay > GetTime()) {
      Delay()'
    }
  }
}

يبدو أن wget يديرها باستخدام خيار --limit-rate.وهنا من صفحة الرجل:

لاحظ أن WGT تنفذ الحد من خلال النوم على مقدار الوقت المناسب بعد قراءة الشبكة التي استغرقت وقتًا أقل من المحدد حسب المعدل.في النهاية ، تتسبب هذه الاستراتيجية في نقل TCP إلى التباطؤ إلى المعدل المحدد تقريبًا.ومع ذلك ، قد يستغرق الأمر بعض الوقت لتحقيق هذا التوازن ، لذلك لا تفاجأ إذا كان الحد من المعدل لا يعمل بشكل جيد مع ملفات صغيرة جدًا.

كما قال الآخرون، فإن نواة نظام التشغيل تدير حركة المرور وأنت ببساطة تقرأ نسخة من البيانات من ذاكرة النواة.للحد تقريبًا من معدل تطبيق واحد فقط، تحتاج إلى تأخير قراءاتك للبيانات والسماح للحزم الواردة بالتخزين المؤقت في النواة، الأمر الذي سيؤدي في النهاية إلى إبطاء الإقرار بالحزم الواردة وتقليل المعدل على ذلك المقبس الواحد.

إذا كنت تريد إبطاء كل حركة المرور إلى الجهاز، فستحتاج إلى الذهاب وضبط أحجام مخازن TCP المؤقتة الواردة.في Linux، يمكنك التأثير على هذا التغيير عن طريق تغيير القيم في /proc/sys/net/ipv4/tcp_rmem (قراءة أحجام المخزن المؤقت للذاكرة) وملفات tcp_* الأخرى.

للإضافة إلى إجابة برانان:

إذا قمت بتحديد سرعة القراءة طوعًا عند طرف جهاز الاستقبال، فسوف تمتلئ قوائم الانتظار في النهاية عند كلا الطرفين.بعد ذلك، سيقوم المرسل إما بحظر استدعاء الإرسال () أو العودة من استدعاء الإرسال () بطول مرسل أقل من الطول المتوقع الذي تم تمريره إلى استدعاء الإرسال ().

إذا لم يكن المرسل مستعدًا للتعامل مع هذه الحالة عن طريق النوم ومحاولة إعادة إرسال ما لا يتناسب مع المخازن المؤقتة لنظام التشغيل، فسوف ينتهي بك الأمر إلى مواجهة مشكلات في الاتصال (قد يكتشف المرسل ذلك كخطأ) أو فقدان البيانات (قد يكون المرسل دون علم تجاهل البيانات التي لم تتناسب مع المخازن المؤقتة لنظام التشغيل).

قم بتعيين مخازن مؤقتة صغيرة للإرسال والاستقبال، على سبيل المثال 1 كيلو أو 2 كيلو، بحيث يكون عرض النطاق الترددي * منتج التأخير = حجم المخزن المؤقت.قد لا تتمكن من جعله صغيرًا بدرجة كافية عبر الروابط السريعة.

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