سؤال

لدي تسلسل هرمي صغير للكائنات التي أحتاج إلى إجراء تسلسل لها ونقلها عبر اتصال مأخذ توصيل.أحتاج إلى إجراء تسلسل للكائن، ثم إلغاء تسلسله بناءً على نوعه.هل هناك طريقة سهلة للقيام بذلك في C++ (كما هو الحال في Java)؟

هل هناك أي نماذج أو برامج تعليمية عبر الإنترنت لتسلسل C++؟

يحرر: فقط للتوضيح، أنا أبحث عن طرق لتحويل كائن إلى مصفوفة من البايتات، ثم العودة إلى كائن.يمكنني التعامل مع انتقال المقبس.

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

المحلول

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

يحرر:
إذا كنت تريد إجراء تسلسل للكائنات الخاصة بك إلى مصفوفة بايت، فيمكنك استخدام مُسلسل التعزيز بالطريقة التالية (مأخوذة من موقع البرنامج التعليمي):

#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/binary_iarchive.hpp>
class gps_position
{
private:
    friend class boost::serialization::access;
    template<class Archive>
    void serialize(Archive & ar, const unsigned int version)
    {
        ar & degrees;
        ar & minutes;
        ar & seconds;
    }
    int degrees;
    int minutes;
    float seconds;

public:
    gps_position(){};
    gps_position(int d, int m, float s) :
    degrees(d), minutes(m), seconds(s)
    {}
};

يصبح التسلسل الفعلي سهلاً جدًا:

#include <fstream>
std::ofstream ofs("filename.dat", std::ios::binary);

    // create class instance
    const gps_position g(35, 59, 24.567f);

    // save data to archive
    {
        boost::archive::binary_oarchive oa(ofs);
        // write class instance to archive
        oa << g;
        // archive and stream closed when destructors are called
    }

تعمل عملية إلغاء التسلسل بطريقة مماثلة.

هناك أيضًا آليات تتيح لك التعامل مع تسلسل المؤشرات (هياكل البيانات المعقدة مثل الخصلة وما إلى ذلك لا تمثل مشكلة)، والفئات المشتقة ويمكنك الاختيار بين التسلسل الثنائي والتسلسل النصي.إلى جانب ذلك، يتم دعم جميع حاويات STL خارج الصندوق.

نصائح أخرى

في بعض الحالات، عند التعامل مع الأنواع البسيطة، يمكنك القيام بما يلي:

object o;
socket.write(&o, sizeof(o));

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

ولكن عاجلاً أم آجلاً، عادة عاجلا, ، هذا سوف يؤذيك!

تواجه مشكلات مع:

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

(بالإضافة إلى أنك تحتاج إلى معرفة ما تقوم بتفريغه على الجانب المتلقي.)

يمكنك تحسين ذلك من خلال تطوير أساليب التنظيم/إلغاء التنظيم الخاصة بك لكل فئة.(من الناحية المثالية، تكون افتراضية، بحيث يمكن توسيعها في فئات فرعية.) ستتيح لك بعض وحدات الماكرو البسيطة كتابة أنواع أساسية مختلفة بسرعة كبيرة بترتيب كبير/صغير محايد.

لكن هذا النوع من العمل الشاق أفضل بكثير، ويمكن التعامل معه بسهولة أكبر مكتبة التسلسل Boost.

التسلسل يعني تحويل الكائن الخاص بك إلى بيانات ثنائية.بينما يعني إلغاء التسلسل إعادة إنشاء كائن من البيانات.

عند إجراء التسلسل، فإنك تقوم بدفع البايتات إلى ملف uint8_t المتجه.عند إلغاء التسلسل، فإنك تقرأ وحدات البايت من ملف uint8_t المتجه.

هناك بالتأكيد أنماط يمكنك استخدامها عند إجراء تسلسل للأشياء.

يجب أن يكون لكل فئة قابلة للتسلسل ملف serialize(std::vector<uint8_t> &binaryData) أو دالة موقعة مماثلة ستكتب تمثيلها الثنائي في المتجه المقدم.ثم قد تقوم هذه الوظيفة بتمرير هذا المتجه إلى وظائف التسلسل الخاصة بالأعضاء حتى يتمكنوا من كتابة أشياءهم فيه أيضًا.

نظرًا لأن تمثيل البيانات يمكن أن يكون مختلفًا باختلاف البنيات.تحتاج إلى معرفة مخطط كيفية تمثيل البيانات.

لنبدأ من الأساسيات:

تسلسل البيانات الصحيحة

فقط اكتب البايتات بترتيب نهائي صغير.أو استخدم التمثيل المتغير إذا كان الحجم مهمًا.

التسلسل بترتيب endian الصغير:

data.push_back(integer32 & 0xFF);
data.push_back((integer32 >> 8) & 0xFF);
data.push_back((integer32 >> 16) & 0xFF);
data.push_back((integer32 >> 24) & 0xFF);

إلغاء التسلسل من ترتيب endian الصغير:

integer32 = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);

تسلسل بيانات النقطة العائمة

بقدر ما أعرف فإن IEEE 754 يحتكر هنا.لا أعرف أي بنية سائدة قد تستخدم شيئًا آخر للعوامات.الشيء الوحيد الذي يمكن أن يكون مختلفًا هو ترتيب البايت.تستخدم بعض البنيات عددًا صغيرًا من وحدات endian، بينما يستخدم البعض الآخر ترتيب بايت endian كبير.هذا يعني أنك بحاجة إلى توخي الحذر بشأن الترتيب الذي سترفع به وحدات البايت على الطرف المتلقي.يمكن أن يكون الاختلاف الآخر هو التعامل مع القيم غير الطبيعية واللانهاية وقيم NAN.ولكن طالما أنك تتجنب هذه القيم، فيجب أن تكون على ما يرام.

التسلسل:

uint8_t mem[8];
memcpy(mem, doubleValue, 8);
data.push_back(mem[0]);
data.push_back(mem[1]);
...

إلغاء التسلسل يفعل ذلك إلى الوراء.اهتم بترتيب البايت للهندسة المعمارية الخاصة بك!

تسلسل السلاسل

تحتاج أولاً إلى الاتفاق على الترميز.UTF-8 شائع.ثم قم بتخزينه بطريقة مسبوقة بالطول:أولاً، تقوم بتخزين طول السلسلة باستخدام الطريقة التي ذكرتها أعلاه، ثم تكتب السلسلة بايتة بايت.

تسلسل المصفوفات.

هم نفس السلاسل.عليك أولاً إجراء تسلسل لعدد صحيح يمثل حجم المصفوفة ثم إجراء تسلسل لكل كائن فيه.

تسلسل الكائنات بأكملها

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

تسلسل الرسوم البيانية الكائن

تحتاج أولاً إلى التأكد مما إذا كانت هذه الكائنات هي بالفعل شيء تريد إجراء تسلسل له.لا تحتاج إلى إجراء تسلسل لها في حالة وجود مثيلات لهذه الكائنات على الوجهة.

لقد اكتشفت الآن أنك بحاجة إلى إجراء تسلسل لهذا الكائن المشار إليه بمؤشر.مشكلة المؤشرات أنها صالحة فقط في البرنامج الذي يستخدمها.لا يمكنك إجراء تسلسل للمؤشر، ويجب عليك التوقف عن استخدامه في الكائنات.بدلاً من ذلك، قم بإنشاء تجمعات كائنات.تجمع الكائنات هذا هو في الأساس مصفوفة ديناميكية تحتوي على "مربعات".تحتوي هذه المربعات على عدد مرجعي.يشير العدد المرجعي غير الصفري إلى كائن حي، ويشير الصفر إلى فتحة فارغة.ثم تقوم بإنشاء مؤشر ذكي مشابه لـ Shared_ptr الذي لا يخزن المؤشر على الكائن، بل الفهرس الموجود في المصفوفة.تحتاج أيضًا إلى الاتفاق على فهرس يشير إلى المؤشر الفارغ، على سبيل المثال.-1.

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

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

على الطرف المتلقي، يتم إلغاء تسلسل جميع المصفوفات والكائنات الموجودة بداخلها، مما يؤدي إلى إعادة إنشاء الرسم البياني للكائن المطلوب.

تسلسل مؤشرات الوظيفة

لا تقم بتخزين المؤشرات في الكائن.احصل على مصفوفة ثابتة تحتوي على مؤشرات لهذه الوظائف وقم بتخزين الفهرس في الكائن.

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

تسلسل أنواع متعددة الأشكال

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

تحتاج إلى حل هذه المشكلة باستخدام علامات الكتابة والاتحادات.

الإصدار

على رأس كل ما سبق.قد ترغب في أن تتفاعل إصدارات مختلفة من البرنامج.

في هذه الحالة، يجب على كل كائن كتابة رقم إصدار في بداية تسلسله للإشارة إلى الإصدار.

عند تحميل الكائن على الجانب الآخر، قد تكون الكائنات الأحدث قادرة على التعامل مع التمثيلات الأقدم ولكن الكائنات الأقدم لا يمكنها التعامل مع الأحدث لذا يجب عليهم طرح استثناء حول هذا الأمر.

في كل مرة يتغير شيء ما، يجب عليك رفع رقم الإصدار.


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

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