الفريق العربي للبرمجةأرشيف المنتديات · 2000 – 2023
نسخة أرشيفية للقراءة فقط — التسجيل والمشاركة مغلقان، والمحتوى محفوظ كما كان.

برمجة شبكات non-blocking socket

بدأه HGB في 12 مارس 2005 · 6 رد · 3,414 مشاهدة · في قسم المواضيع الهامة في قسم السي /سي++
مشاركة: واتساب X فيسبوك تيليجرام
#1 صاحب الموضوع

في هذه الجلسة السريعة سأتحدث عن نوعين من أنواع ال Sockets , وبالطبع أغلبكم يعرف ماهي Winsock وتحدثنا عن برمجتها سابقا في هذا الرابط :

/index.php?showtopic=37152

المهم ماتجب معرفته أن في البرامج الكبيرة التي تحتاج لتعدد تخاطبات أو Multy sockets , كبرامج chat وبرامج مشاركة الملفات وأي برنامج يحتاج فيه لتكوين أكثر من إتصال , يجب وقتها التفكير مليا قبل الشروع في كتابة الكود حيث يمكن أن تكون Blocking Sockets هي الحل الأمثل وقد تكون Non Blocking Sockets ,

الآن دعونا من الثرثرة ولنعرف ماذا نعني بالمصطلحين Blocking and nono blocking Sockets ,

الأول Blocking Sockets وهي الطريقة العادية التي كنا نتعامل فيها مع برمجة Winsock حيث هي الوضع الإفتراضي دائما عند البدء بمكتبات winsock , وسميت Blocking Socket لأنها تثبت مجرى البرنامج حتى تحصل على إستجابة خارجية External Response ,

مثلا عندما نقوم بعمل Accept Connecton , سيتوقف برنامجنا تماما عند هذه النقطة حتى نحصل في النهاية على Connection خارجي من بريمج في جهاز يحاول الإتصال بجهازنا عن بعد , عندها سيتم الحصول على مقبض ل Socket صالح للتخاطب مع الجهاز البعيد , بالطبع أيضا نفس المشكلة مع الدالة recv وحتى نحصل تماما على مانريد من بيانات من الجهاز أو البريمج المتصل , لن يتحرك البرنامج سطار واحدا حتى ينفذ الدالة recv أو accept ليحصل عل كل مايريد من البرنامج الخارجي ,

الآن في وضع كهذا لو كان لدي مثلا بريمج chat بسيط , وكنت أتحدث مع أكثر من مستخدم , فالبتأكيد لن أستطيع أن أستقبل البيانات إلا من شخص واحد والسبب أن المعالجة Thread الحالية ستتوقف تماما وحتى الحصول على respond بعيد ,

إذا مالحل ؟

الحل كما توقعتم يكون في بعض الأحيان بإستخدام Multy threading حيث يكون لكل socket أو إتصال Thread منفصل تماما عن غيره , يتوقف كما يريد أن يتوقف حتى يحصل على recv وبالطبع سيكون لدينا آخر لعمل send لكل جلسة مع مستخدم بعيد , وبالتأكيد thread منفصل جديد ينتظر طلبات التخاطب الجديدة لينشيء بدوره لها حسابات Socket جديدة في thread جديد هو الآخر !!

يمكن تكوين هذه الشبكة ببساطة , ولاتأسى ولاتقلق على عدد threads القصوى التي يمكن إنشاءها , فبعض البريمجات تأخذ حوالي 100 معالجة thread مستقل ويمكن أن تلاحظ لذلك برؤية عدد threads في البرامج المقيمة في الذاكرة قيد العمل من Task manger بالضغط على ctrl+alt+delete , ثم التبويب View - > select colums->thread count , وسترى في الشاشة Process عدد threads لكل بريمج موجود ,

المهم يجب أن يحظى برنامجك بتخطيط لابأس به يوضح سريان العمل وبدون أخطاء مع تعاطي كبير في تعدد المعالجات وهي من التقنيات المعقدة في عملية Debugging , بالطبع تزامن المسالك يجب أن يكون في قائمة أولوياتك لأن حتى Socket الذي ستستخدمه في الإستقبال والإرسال لمستخدم معين سيكون مشترك بين معالجيتين , ودعك من بقية المتغيرات في الكود .

الآن هذا كود مبسط يوضح عملية إستقبال أكثر من أكثر من Socket بدون تعدد معالجات :

// Server_Final.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <winsock.h>
#include <process.h>



#pragma comment(lib,"wsock32.lib")
using namespace std;

#define SEARCH_PORT 2222
#define DOWN_PORT 2223
#define COM_PORT 2224
#define MAXCONNECTION 10


//---Global Variabules ------------
SOCKET server_socket;
sockaddr_in soc;

//--------------------------------

struct Client
{
	SOCKET soc;


};

void Accept()
{



}

void StartServer()
{

WSADATA wsa;
WSAStartup(MAKEWORD(1,1),&wsa);

server_socket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);

soc.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
soc.sin_family = AF_INET;
soc.sin_port = htons(SEARCH_PORT);

//memcpy ( &server_socket_address, &server_address, sizeof ( SOCKADDR_IN ) );

bind(server_socket,(SOCKADDR*)&soc,sizeof(soc));


listen(server_socket,MAXCONNECTION);

}


int x = 0;
void Acception()
{
int size = sizeof(soc);

char buf[1000];
for(int q=0;q<1000;q++)
{
	//Sleep(100);
SOCKET to_client = accept(server_socket,(SOCKADDR*)&soc,&size);

cout << x++;

if (to_client==0)
{


}
else if (to_client == SOCKET_ERROR)
{

}

else 
{
	cout << "Connection Established ... "<<"   :  ";

	ZeroMemory(buf,sizeof(buf));


	int ret = recv(to_client,buf,1000,0);
	if(ret)
	{
  cout << ret;
	}

	cout << buf << endl;

}


}

}


int _tmain(int argc, _TCHAR* argv[])
{

	StartServer();
	Acception();


	return 0;
}

لاحظ للدالة :

Acception , والكود :

int size = sizeof(soc);

char buf[1000];
for(int q=0;q<1000;q++)
{
	//Sleep(100);
SOCKET to_client = accept(server_socket,(SOCKADDR*)&soc,&size);

cout << x++;

if (to_client==0)
{


}
else if (to_client == SOCKET_ERROR)
{

}

هنا أضفت حلقة تكرار بعدد كبير 1000 إتصال منفصل , ولن يتم التحرك من الدالة Acception مالم يحدث إتصال من البريمج البعيد , وسكون على الشكل :

// client.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <winsock.h>
#include <windows.h>

using namespace std;


#pragma comment(lib,"wsock32.lib")

int _tmain(int argc, _TCHAR* argv[])
{


	WSADATA wsa;
	WSAStartup(MAKEWORD(1,1),&wsa);

	SOCKET soc;
	SOCKADDR_IN addr;
	soc = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

	addr.sin_port=htons(2222);
	addr.sin_addr.S_un.S_addr=inet_addr("127.0.0.1");
	addr.sin_family = AF_INET;
	connect(soc,(sockaddr*)&addr,sizeof(addr));

	char* buf=new char[1000];
	ZeroMemory(buf,1000);

	strcpy(buf,"Hello");

	cout << buf;

	send(soc,buf,10,0);

	cin.get();

	return 0;
}

المثال السابق واضح يوضح عيب Blocking Sockets دون إستخدام تعدد المعالجات , سنعدل عليه لكي لايوقف سير البرنامج نهائيا حيث ربما نحصل على recv بيانات من كونيكشن متصل سابقا ولن نستطيع ذلك مالم يحدث إتصال جديد ل Accept ,

لحل الإشكالية يجب وضع الدالة recv والدالة send والدالة accept كل منها في معالجة منفصلة لكي لاتؤثر على سير البرنامج .

non Blocking Sockets : وهي من إسمها لاتثبت البرنامج ككل في حال الإنتظار في دالة ك Accept , حيث سيمر فيها البرنامج حقيقة وكأنها غير موجودة , لكنه يعود لها فور حصول إتصال مع جهاز آخر , وهي كما ترون حل جذري لبرنامجنا السابق , حيث سيمر التنفيذ في الدالة Accept حتى يصل للدالة recv بشكل طبيعي , وسيظل يدور فيها حتى يحدث شيء إما بالحصول على recv أو حدوث connection مع accept .

يتم التحول لوضع non blocking Sockets بإستخدام ioctlsocket كالتالي :

unsigned long b = 1;
ioctlsocket ( SocCom, FIONBIO, &b );

حيث SocCom هو Socket الذي نريد جعله non Blocking , ونريد جعل الدوال التي تتعامل به non blocking ,

كل الدوال مابعد السطر :

ioctlsocket ( SocCom, FIONBIO, &b );

تعامل معاملة Non blocking Socket ,

عند الرغبة للعودة مرة أخرى لنظام blocking Socket فقط يكفي تغيير القيمة :

unsigned long b = 1;

إلى صفر مرة أخرى وإستدعاء :

ioctlsocket ( SocCom, FIONBIO, &b );

قد يكون الكلام مربك , لكن عموما هذا الكود سيعمل مباشرة مع كود client الموجود في الأعلى ويجب عليك القيام بالكثير من التجارب للتتقن هذه العمليات :

nonblocking.txt

banner_60_468.gif

NOTHING IS IMPOSSIBLE

#2

موضوع ولا أجمل أخي هيثم

مفروض نسميك HGB Winsock

وبالتوفيق ,,,

http://www.jaascois.com

*************************************************

مجموعة مواضيع - إحتراف البرمجة -

ّ~~~~~~~~~~~~~~~~~~~~~~

البرمجة المتقدمة & الهندسة العكسية & برمجة وأمن الأنظمة

/index.php?showtopic=45002

آخر المواضيع :

+- تحليل جرائم الكمبيوتر -+

أنظمة اليونكس(Solaris,HP, AIX,SCO)وانواع المعالجات

ثغرة SMS لأجهزة الجوال Siemens 3568i !

أخطاء وثغرات البرامج العربية !!!

سلسلة مواضيع - أمن وحماية مواقع الويب -

E البرمجة المتقدمة X للملفات التنفيذية E

سلسلة مواضيع ثغرات الأنظمة وإختراق الأجهزة

**************************************************

<span style='font-size:14pt;line-height:100%'>الإرادة تحـــقق السيـــادة</span>

**************************************************

#3

موضوع رائع

لكني لم افهم شي

لاني مبتدء

وتحياتي

52gv0m.gif
#4

السلام عليكم

أخي HGB كل الشكر والتقدير لما تقدمه من نفيس وغالي وأنا متابع كل ما تطرحه من مواضيع وأكثر ما يهمني هو هذا الموضوع وهو برمجة الsockets حيث انني طالب شبكات وأحضر الأن مشروع تخرجي في هذا المجال وأريد منك بعد إذنك طبعاً وإذا ما في مانع أن أستفيد من خبراتك في هذا المجال ولكن حسب ما علمت سابقاً من خلال هذا المنتدى انه ممنوع مخاطبة أشخاص بعينهم في المنتدى فلا ما هي طريقة التواصل معك بشكل أخر غير المنتدى ...............؟ مع كل الشكر والتقدير .............. أخوك

#5

مشكوووووووور HGB :)

الحين عرفت ليش الخادم مايقبل اتصال من جديد اذا حصل خطأ في ارسال بيانات من العميل للخادم

راح احاول تطبيق ماذكرته لكن عندي سؤال بسيط

لو فرضنا حجم البرنامج باستخدام Blocking Sockets هو 20 ك.ب فقط

اذا تحول البرنامج من طريقة Blocking Sockets الى Non Blocking Sockets

هل راح يتغير الحجم بشكل كبير بسبب الاضافات الجديده ؟

#6
اقتباس
لو فرضنا حجم البرنامج باستخدام Blocking Sockets هو 20 ك.ب فقط

اذا تحول البرنامج من طريقة Blocking Sockets الى Non Blocking Sockets

بالنسبة للزيادة فلن يزيد الحجم شيئا , لكن كما قلت أحينا ستحتاج لخلط النوعين سويا لتحقيق أفضل نتيجة .

يامراد صبري :

لامشكلة أنا متواجد يوميا في المنتدى للرد على أسئلة الأعضاء في القسم , فيمكن أن أراقب كل مشاركاتك وأجيب عليها يوميا وهذا لتعم الفائدة ويستفيد الكل من الأسئلة وإجاباتها , فبإذن الله أتابع كل أسئلتك "بمراد صبري" وسأرد عليها يوميا بحول الله .

إستاذ jaas والأعضاء الكرام مشكورين , ونحو المزيد :)

banner_60_468.gif

NOTHING IS IMPOSSIBLE

#7

رد ولا أجمل اخي العزيز .......... وكثر الله من أمثالك

مواضيع مشابهة