English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
رأيت سابقًا مقالًا يشرح خمس طرق للتواصل بين التطبيقات،وهي URL Scheme،Keychain،UIPastedboard،UIDocumentInteractionController،وحلول socket للتواصل المحلي. استخدمت الأربعة الأولى،وكانت بسيطة نسبيًا،أمر بسيط من بضع سطور من البرمجية. بالنسبة للنوع الخامس لم أستخدمه قط (عذرًا أنني ما زلت مبتدئًا)،لذا حاولت كتابته اليوم وسجلت هنا لأشاركه معكم.
حسنًا،لا أريد أن أتحدث عن الشيء الكثير،دعونا نبدأ:
أولاً،دعونا نتحدث عن مبدأه،في الواقع هو بسيط،يقوم تطبيق في نفس المنفذ المحلي بتحديد TCP وbind وlisten،وآخر تطبيق في نفس المنفذ المحلي بتحديد connect،على هذا النحو يمكن إنشاء اتصال TCP عادي،ويمكن نقل أي بيانات تريدسنبدأ أولاً بإنشاء الخادم:
1،أولاً،استخدم دالة socket() لإنشاء واجهة الاتصال
/* * يعود socket قيمة int،-1 إذا كانت عملية إنشاء الفشل * المعلمة الأولى تحدد عائلة الاتفاقية/النطاق،عادة ما تكون AF_INET(IPV4)،AF_INET6(IPV6)،AF_LOCAL * المعلمة الثانية تحدد نوع واجهة الاتصال: SOCK_STREAM, SOCK_DGRAM, SOCK_SEQPACKET * الثالثة معلمة تحدد الاتفاقية المناسبة للنقل،مثل TCP/UDP،عادة ما تكون 0 لتستخدم القيمة الافتراضية */ int sock = socket(AF_INET, SOCK_STREAM, 0); if(sock == -1){ close(sock); NSLog(@"خطأ套بيكت: %d",sock);<br> return; }
2،ربط عنوان المضيف ورقم المنفذ
// هيكل العنوان،يحفظ عنوان IP ورقم المنفذ struct sockaddr_in sockAddr; // إعلان البروتوكول المستخدم sockAddr.sin_family = AF_INET; // الحصول على عنوان IP الخاص بالمضيف،تحويله إلى نوع char const char *ip = [[self getIPAddress] cStringUsingEncoding:NSASCIIStringEncoding]; // تعيين ip في هيكل،inet_addr() هي دالة تحويل عنوان IP من نظام العد العشري إلى عدد طبيعي sockAddr.sin_addr.s_addr = inet_addr(ip); // إعداد رقم المنفذ،htons() هي دالة تحويل متغيرات الصيغة من ترتيب الحواسيب إلى ترتيب الشبكة sockAddr.sin_port = htons(12345); /* * تستخدم دالة bind لربط السكيتش بمعرف العنوان،تعود قيمة int،-1 في حالة الفشل * هو السكيتش المحدد،هو نفس السكيتش الذي أعادته دالة socket * هو العنوان المحدد * هو حجم بيانات العنوان */ int bd = bind(sock,(struct sockaddr *) &sockAddr, sizeof(sockAddr)); if(bd == -1){ close(sock); NSLog(@"خطأ الاتصال : %d",bd); return; }
3،الاستماع إلى العنوان المربوط
/* * تجعل دالة listen منفذ الاتصال نشطاً ويجعله قابلاً للاستقبال،عندما يتم استقبال طلب من عملية أخرى،تعود قيمة int،-1 في حالة الفشل * هو الدالة السابقة التي أعادت كائن socket * يمكن فهم الثانية كحد أقصى للاتصالات */ int ls = listen(sock,20); if(ls == -1){ close(sock); NSLog(@"خطأ الاستماع : %d",ls); return; }
4،الآن ينتظر الاتصال بالعميل،استخدام accept()(بسبب أن دالة accept ستعطل السطر،في أثناء انتظار الاتصال سيكون السطر معطل،لذا يُنصح بوضعها في سطر فرعي)
// 1،فتح سطر فرعي NSTread *recvThread = [[NSThread alloc] initwithTarget:self selector:@selector(recvData) object: nil]; [recvThread start]; - (void)recvData{ // 2،الانتظار لاتصال العميل // يتم إعلان هيكل العنوان،للاستخدام في استقبال عنوان العميل المستلم لاحقًا struct sockaddr_in recvAddr; // حجم العنوان socklen_t recv_size = sizeof(struct sockaddr_in); /* * يعود accept() ملف اتصال جديد (self.newSock) بعد إتمام الاتصال الناجح،ويستخدم لتبادل البيانات مع هذا العميل * الأول هو ملف الاتصال الذي نستمع إليه،الذي كان متغيرًا محليًا،ولكن الآن يجب تحويله إلى متغير عالمي * الثانية هي أيضًا معامل نتيجة،تستخدم لاستقبال قيمة العودة،تحدد عنوان العميل * الثالثة هي أيضًا معامل نتيجة،تستخدم لاستقبال معامل recvAddr،لإيضاح عدد البايتات التي تشغلها */ self.newSock = accept(self.sock,(struct sockaddr *) &recvAddr, &recv_size); // 3،إذا وصلنا إلى هنا فهذا يعني أننا قد وصلنا إلى عميل جديد،والآن يمكننا إرسال واستقبال البيانات،والمعتماد الرئيسي هو send() و recv() ssize_t bytesRecv = -1; // حجم البيانات المستلمة char recvData[128] = ""; // منطق التخزين للبيانات المستلمة // إذا انقطع الاتصال من أحد الطرفين،ستعود recv مباشرة،bytesrecv ستكون تساوي 0،ثم سيستمر الدوران في الحلقة while،لذا فإن التحقق من تساوي 0 هو للخروج من الدورة while(1){ bytesRecv = recv(self.newSocket,recvData,128,0); // recvData هو البيانات المستلمة if(bytesRecv == 0){ break; } } }
5،إرسال البيانات
- (void)sendMessage{ char sendData[32] = "hello client"; ssize_t size_t = send(self.newSocket, sendData, strlen(sendData), 0); }
العميل منقسم بشكل رئيسي إلى: إنشاء ملف الاتصال، الحصول على عنوان المضيف للخادم بناءً على عنوان IP ورقم المنفذ، ثم الاتصال، وبعد إتمام الاتصال الناجح يمكننا إرسال واستقبال البيانات من الخادم، لنتابع الكود الآن.
1،استخدام وظيفة socket لإنشاء socket مثل الخادم
int sock = socket(AF_INET, SOCK_STREAM,0); if(sock == -1){ NSLog(@"خطأ socket : %d",sock); return; }
2،الحصول على عنوان الخادم
NSString *host = [self getIPAddress]; // الحصول على عنوان IP الخاص بالمستخدم // تعود بناءً على اسم الخادم المحدد بنقطة، بنقطة تحتوي على معلومات اسم الخادم والعنوان struct hostent *remoteHostEnt = gethostbyname([host UTF8String]); if(remoteHostEnt == NULL){ close(sock); NSLog(@"لا يمكن تحليل اسم الخادم للخادم"); return; <br>// إعداد عنوان IP والمعرف المنتهي بالبورتفوليو للخادم الذي سيتم الاتصال به، لاستخدام وظيفة connect() struct in_addr *remoteInAddr = (struct in_addr *)remoteHost->h_addr_list[0]; struct sockaddr_in socktPram; socketPram.sin_family = AF_INT; socketPram.sin_addr = *remoteInAddr; socketPram.sin_port = htons([port intValue]);
3،استخدام وظيفة connect() للاتصال بالخادم
/* * تستخدم وظيفة connect عادةً لإنشاء اتصال TCP على مستوى العملاء، لاتصال الخادم المحدد بالعنوان، وتعطي الوظيفة قيمة int،-1 للفشل * العنصر الأول هو套اجت الذي تم إنشاؤه بواسطة وظيفة socket، يمثل هذا套اجت الاتصال بالخادم المحدد * العنصر الثاني هو عنوان الخادم والمعرف المنتهي بالبورتفوليو الذي يريد sokcet sokcet الاتصال به * حجم العنصر الثالث هو حجم عنوان الخادم */ int con = connect(sock, (struct sockaddr *) &socketPram, sizeof(socketPram)); if(con == -1){ close(sock); NSLog(@"فشل الاتصال"); return; } NSLog("الاتصال الناجح"); // هنا يعني الاتصال الناجح
4،بعد من الاتصال الناجح يمكنك استقبال وإرسال البيانات
- (IBAction)senddata:(id)sender { // إرسال البيانات char sendData[32] = "hello service"; ssize_t size_t = send(self.sock, sendData, strlen(sendData), 0); NSLog(@"%zd",size_t); } - (void)recvData{ // استقبال البيانات، وضعها في نواة الفرع ssize_t bytesRecv = -1; char recvData[32] = ""; while (1) { bytesRecv = recv(self.sock, recvData, 32, 0); NSLog(@"%zd %s",bytesRecv,recvData); if (bytesRecv == 0) { break; } } }
حسنًا، هذا هو كل ما يجب القيام به لاستخدام socket للتواصل بين تطبيقين محليين. هذه المرة أكتب مقالًا لأول مرة، لأجل تسجيل تجربتي الخاصة، وأيضًا لشاركها معكم، إذا كانت هناك أي أخطاء في النص، فأرجو أن تشاركوني في إصلاحها. وأرفق أيضًا عنوان Demo، هناك مشاريعان، يمكن للذين يهمهم الأمر تنزيلها واختبارها.
https://pan.baidu.com/s/1nvcvC8p
هذا هو جمع المعلومات حول إتصال تطبيقات iOS -local socket، وسنواصل إضافة المعلومات ذات الصلة لاحقًا، شكرًا لكم على دعمكم لهذا الموقع!
إعلان: محتوى هذا المقال تم جمعه من الإنترنت، ويعود حقوق الطبع والنشر إلى المالك الأصلي، تم جمع المحتوى من قبل المستخدمين على الإنترنت الذين قدموا المساهمة بذاتهم وتم تحميله، ويملك هذا الموقع حقوق الملكية، لم يتم تعديل المحتوى بشكل يدوي، ولا يتحمل هذا الموقع أي مسؤولية قانونية. إذا كنت قد وجدت محتوى يشتبه في انتهاك حقوق النسخ، فيرجى إرسال بريد إلكتروني إلى: notice#oldtoolbag.com (يرجى استبدال # ب @ عند إرسال البريد الإلكتروني) لإبلاغنا، وقدم الدليل على الدليل، وسنقوم بإزالة المحتوى المزعوم فور التحقق منه.