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

كلاس الونسوك اللامتزامن Asynchronous Socket class

بدأه راكان الحنيطي في 10 أغسطس 2007 · 6 رد · 3,477 مشاهدة · في Microsoft Visual C#.NET
مشاركة: واتساب X فيسبوك تيليجرام
#1 صاحب الموضوع

السلام عليكم

اشارك معكم هذا الكلاس في إصدارة ال Beta Version :D و الذي قمت ببرمجته لكنه يحتاج الي بعض التعديل اللازم.

Asynchronous Sockets هي كلاسات موجودة في الدوت نت لعملية الإتصال بالشبكات اللامتزامنة بحيث يعمل البرنامج على إرسال و إستقبال المعلومات من و الي الشبكة بدون إيقاف البرنامج لإنتظار عملية الإرسال او الأستقبال(Synchronous Sockets).

using System;
using System.Collections.Generic;
using System.Text;
using System.Net.Sockets;
using System.Net;
namespace ClientSocket
{
	class ClientSocket
	{

		#region Declarations
		Socket sckClient;
		String mHost;
		int mPort;


		public enum SocketState { Closed, Connecting, Connected }

		SocketState mState;

		#endregion

		#region Events
		public delegate void ConnectedHandler(Object Sender);
		public delegate void DisconnectedHandler(Object Sender);
		public delegate void DataReceivedHandler(Object Sender, String Text);
		public delegate void DataSendHandler(Object Sender);

		public event ConnectedHandler Connected;
		public event DisconnectedHandler Closed;
		public event DataReceivedHandler DataReceived;
		public event DataSendHandler DataSent;

		#endregion

		#region Helper Functions

		public IPAddress ResolveAddress(String host)
		{
			IPHostEntry iph = Dns.GetHostEntry(host);
			return iph.AddressList[0];
		}

		#endregion

		#region Properties
		public String Host
		{
			set
			{
				mHost = value;
			}
			get
			{
				return mHost;
			}
		}
		public int Port
		{
			set
			{
				mPort = value;
			}
			get
			{
				return mPort;
			}

		}
		public SocketState SockState
		{
			get
			{
				return mState;
			}
		}

		#endregion


		public ClientSocket()
		{
			//Create new Socket 
			sckClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 
			mHost = "";
			mPort = 0;

			mState = SocketState.Closed;
		}

		#region Public functions
		public void Connect()
		{
			//Start connection
			if (mHost == String.Empty)
			{
				throw new ArgumentException("Host was not specified!");
			}
			else
			{
				try
				{
					EndPoint ep = new IPEndPoint(ResolveAddress(Host), mPort);

					sckClient.BeginConnect(ep, new AsyncCallback(ConnectedCallback), sckClient);

					mState = SocketState.Connecting;
				}
				catch (SocketException)
				{
					if (sckClient.Connected) mState = SocketState.Connected;
					else
					{
						mState = SocketState.Closed;
						Closed(this);
					}
				}

			}
		}
		public void Close()
		{
			if (sckClient != null && sckClient.Connected)
			{
				sckClient.Shutdown(SocketShutdown.Both);
				sckClient.Close();

				mState = SocketState.Closed;

				sckClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
				Closed(this);
			}
		}
		public void Send(String Data)
		{
			try
			{
				Byte[] buffer = Encoding.ASCII.GetBytes(Data);
				sckClient.BeginSend(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(DataSendCallback), sckClient);
			}
			catch (SocketException)
			{
				if (sckClient.Connected) mState = SocketState.Connected;
				else
				{
					mState = SocketState.Closed;
					Closed(this);
				}
			}
		}
		public void Send(Byte[] Buffer, int offset, int length)
		{
			try
			{
				sckClient.BeginSend(Buffer, offset, length, SocketFlags.None, new AsyncCallback(DataSendCallback), sckClient);
			}
			catch (SocketException)
			{
				if (sckClient.Connected) mState = SocketState.Connected;
				else
				{
					mState = SocketState.Closed;
					Closed(this);
				}
			}
		}
		#endregion
		#region Callbacks
		public void ConnectedCallback(IAsyncResult ar)
		{
			try
			{
				Socket s = (Socket)ar.AsyncState;
				s.EndConnect(ar);

				mState = SocketState.Connected;

				//Begin recevie
				StateObject sb = new StateObject();
				sb.ClientSocket = sckClient;
				s.BeginReceive(sb.Buffer, 0, StateObject.BUFFER_SIZE, SocketFlags.None, new AsyncCallback(DataReceiveCallback), sb);

				//Raise connection event

				Connected(this);
			}
			catch (SocketException)
			{
				if (sckClient.Connected) mState = SocketState.Connected;
				else
				{
					mState = SocketState.Closed;
					Closed(this);
				}
			}

		}
		public void DataReceiveCallback(IAsyncResult ar)
		{
			try
			{
				StateObject sb = (StateObject)ar.AsyncState;
				int BytesToRead = sb.ClientSocket.EndReceive(ar);

				String RecText = Encoding.ASCII.GetString(sb.Buffer, 0, BytesToRead);

				if (RecText.Trim() != String.Empty)
					DataReceived(this, RecText);

				//Begin recevie
				sb.ClientSocket.BeginReceive(sb.Buffer, 0, StateObject.BUFFER_SIZE, SocketFlags.None, new AsyncCallback(DataReceiveCallback), sb);
			}
			catch (SocketException)
			{
				if (sckClient.Connected) mState = SocketState.Connected;
				else
				{
					mState = SocketState.Closed;
					Closed(this);
				}
			}
		}
		public void DataSendCallback(IAsyncResult ar)
		{
			try
			{
				Socket s = (Socket)ar.AsyncState;
				s.EndSend(ar);
				DataSent(this);
			}
			catch (SocketException)
			{
				if (sckClient.Connected) mState = SocketState.Connected;
				else
				{
					mState = SocketState.Closed;
					Closed(this);
				}
			}
		}
		#endregion

	}
}

هذا الكلاس هو كلاس شبيه بأداة الونسوك و التي تقدم خدمات ال Event-Driven Network Programming و التي كانت اكثر من رائعة بصراحة, و اقدم لكم هذا الكلاس المتواضع و الشبيه بالأداة نوعا ما و الموجودة في الفجوال بيسك 6.0.

كيفية الإستخدام:

لتعريف المتغير من نوع هذا الكلاس تقوم بوضع الكود التالي:

ClientSocket cs;

و من ثم يجب علينا ان نقوم بعمل Initialize لهذا الObject كالتالي:

			cs = new ClientSocket();
			cs.Connected += new ClientSocket.ConnectedHandler(Connected);
			cs.Closed += new ClientSocket.DisconnectedHandler(onClose);
			cs.DataSent += new ClientSocket.DataSendHandler(DataSent);
			cs.DataReceived += new ClientSocket.DataReceivedHandler(DataReceived);

طبعا الكود الذي يلي سطر ال New هو كود لعملية ربط الأحداث بدالات قمنا بتعريفها لإستقبال المعلومات عن الConnection.

الأول يقوم بربط دالةConnected في الفورم الخاص بنا بالحدث Connected في السوكيت. و الثاني لإستقبال حدث ال Close لل Connection. اما الثالث و الرابع لعمليات أرسال البيانات و إستقبالها.

هذه هي تعريفات الدالات التي تستعدى عند قيام الحدث

void onClose(object sender)
		{
			MessageBox.Show("Connection closed");
		}

		void DataSent(object sender)
		{
			MessageBox.Show("Data sent");
		}

		void DataReceived(object sender, String RecText)
		{
			txtMsgs.Text += "Received\n";
			txtMsgs.Text += RecText;
		}
void Connected(object sender)
		{
			MessageBox.Show("Connected");
		}

و كود الزر للقيام بعملية البدء ال Connection

private void btnConnect_Click(object sender, EventArgs e)
		{
			cs.Host = txtHost.Text;
			cs.Port = Int32.Parse(txtPort.Text);

			cs.Connect();


		}

حيث قمنا بأخذ قيم ال Host و Port من مربعات نصوص. و اعطيناها للكلاس ليقوم بعملية بدء الإتصال.

اما بالنسبة لإرسال رسالة

private void btnSend_Click(object sender, EventArgs e)
		{
			cs.Send(txtMsg.Text + "\n");
		}

طبعا الرجاء الإبلاغ عن الأخطاء عند إستخدام الكلاس و انا مستعد لأي سؤال.

طبعا يمكن إستخدام هذا الكلاس لتسهيل عملية عمل برامج المحادثة Client-Server وغيرها من برامج الشبكات

سوف اقوم بوضع كلاس ال ServerSocket قريبا أن شاء الله.

مع تمنياتي لكم بالتوفيق

راكان الحنيطي

راكان الحنيطي

Be Open Source

opensource-550x4752.gif

#2

ما شاء الله عليك

ألف شكر لك

يا أيها الناس قولو لا إله إلا الله تفلحوا وتملكوا بها العرب وتذل لكم العجم وإذا آمنتم كنتم ملوكا في الجنة

#3

السلام عليكم

اقتباس
ما شاء الله عليك

ألف شكر لك

أخي إسماعيل هل جربت الكود؟؟

أخيMaverick شكرا على هذا الموضوع القيم ولكنك نسيت إضافة تعريف القسم StateObject

	public class StateObject
	   {
		   // Client socket.
		   public Socket ClientSocket = null;
		   // Size of receive buffer.
		   public const int BUFFER_SIZE = 256;
		   // Receive buffer.
		   public byte[] Buffer = new byte[BUFFER_SIZE];
		   // Received data string.
		   public StringBuilder sb = new StringBuilder();
	   }

كما نسيت أيضا بدأ التصنت ما إن كان هناك بيانات مرسلة من الطرف الآخر أم لا StartListening

بإمكانك الإعتماد على هذا الرابط

عند إستدعاء دالة غلق الربط بين الطرفين يجب غلقها فعليا ليس إرسال رسالة بذلك فقط

private void btn_Close_Click(object sender, EventArgs e)
	{ cs.Close();
	  MessageBox.Show("Connection Closed", "Close connection", MessageBoxButtons.OK, MessageBoxIcon.Information);
	}

...

#4

السلام عليكم اخي و شكرا لك على مداخلتك.

http://msdn2.microsoft.com/en-us/library/bbx2eya8.aspx

بالنسبة لل StateObject فهو نفس الكلاس لكن بدون ال String Builer و انا كتبت الكلاس بناءا على tutorial قرأتها في ال MSDN بالإضافة الى إضافة اكواد لجعل الكلاس Event-Driven. بالنسبة لعملية الإغلاق الكود المرفق من قبلك يعتمد على الضغط على Button يستدعي كود الإغلاق بينما

void onClose(object sender)
		{
			MessageBox.Show("Connection closed");
		}

هي لجعل المبرمج قادرا على معرفة حدث قطع الإتصال حيث انه من الممكن ان يحصل خطأ يؤدي الى قطع الإتصال.

اما بالنسبة لعملية التنصت لإستقبال الإتصالات كسيرفر فقد ذكرت انه هذا كلاس منفصل :) و سأقوم بوضعه هنا عند الإنتهاء منه.

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

تم تعديل هذه المشاركة بواسطة Maverick في 11 أغسطس 2007 في 20:46

راكان الحنيطي

Be Open Source

opensource-550x4752.gif

#5

تم تعديل الكود لبعض الأخطاء مع إضافة خاصية جديدة و هي معرفة حالة ال Socket

بحيث يمكن ان تكون

Closing, Closed, Connecting, Connected

cs.StateChanged += new ClientSocket.StateChangeHandler(StateChanged);
void StateChanged(object Sender)
		{
			this.Text = cs.SockState.ToString();
		}

الكود مرفق

AsynchSocket.zip

راكان الحنيطي

Be Open Source

opensource-550x4752.gif

#6

السلام عليكم :

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

اللَّهُمَّ إني ضَعِيْفٌ فَقَوِّنِي ، اللَّهُمَّ إني ذَلِيْلٌ فَأعِزَّنِي ، اللَّهُمَّ إني فَقِيْرٌ فَأَغْنِنِي

#7

الف شكر اخ راكان ومشرفنا ابن العيد

الموضوع ده يفيدنى لو انا هاعمل ماسنجر لموقع معين مثلا اظن انى احتاج لشيئين

الـSocket Programming و الــ MultiThreading

فسؤالى الكلاس دى تفيدنى طبعا ما نبص فيها كويس ونغير فيها اللى يتماشى معانا

؟؟

ولدي إليك وصيتي عهد الأسودْ

العز غايتنا نعيش لكي نسود

و عريننا في الأرض معروف الحدود

فاحم العرين و صنه عن عبث القرود

أظفارنا للمجد قد خُلقت فدى

و نيوبنا سُنَّت بأجساد العدى

و زئيرنا في الأرض مرهوب الصدى

نعلي على جثث الأعادي السؤددا

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