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

Start Network Programming In Java

رائج
بدأه Wajdy Essam في 2 مارس 2008 · 95 رد · 46,599 مشاهدة · في JavaSE
مشاركة: واتساب X فيسبوك تيليجرام
#51
اقتباس
لكن فى printwriterاستخدم true لعمل autoFlush

حتى لا اجبر على استخدام الميثود flush لدفع البيانات----لاحظى هو مرة استخدمها فى احد البرامج ومرة اخرى لم يكتب true

معلومة حلوة :) شكراً عزيزتي الدكتورة

لا اله الا الله .. محمد رسول الله

(* ربِ اجعلني مقيم الصلاة و من ذريتي ، ربنا و تقبل دعـاء *)

يا حيّ يا قيـوم ... برحمتك استغيث ... اصلح لي شأني كله و لا تكلني الى نفسي طرفة عين

#52

في حلك الأول dr.sara (لم أقرأ الثاني الا الأن) :

بالنسبه لـ Dir فهناك أحتمالين ، الأول هو أن يقوم العميل بارسال Dir فقط ، والثاني هو أن يقوم العميل بارسال Dir path بمسار ما ، لذلك لن تستطيع اختبار فقط

if (msg.equals("Dir"

لأن سيعطينا خطأ في حال أرسل العميل dir بمسار .. والحل هنا يمكن أن يكون :

على فرض أن cmd هي الكلمه القادمه من الكلاينت :

				else if ( cmd.startsWith("dir") )
				{
					if ( cmd.endsWith("dir") )
					{
						File f = new File(".");
						String st[] = f.list();

						String rsl = "";

						for (int i=0; i<st.length; i++)
							rsl += st;

						out.println(rsl);
					}
					else
					{
						Scanner getPath = new Scanner(cmd);
						String p = getPath.next();
						p = getPath.next();

						File f = new File(p);

						String st[] = f.list();

						String rsl = "";

						for (int i=0; i<st.length; i++)
							rsl += st;

						out.println(rsl);

					}
				}

لاحظ أننا بدأنا بأختبار هل بدأ الأمر بكلمه dir ، في حال كان كذلك نقوم باختبار هل أنتهي Dir وهنا سوف نعرف أن العميل فقط أرسل dir ، والا سوف يكون هناك مسار ونقوم بالحصول عليه عن طريق StringTokenizer أو Scanner كما في المثال :

Scanner getPath = new Scanner(cmd);
String p = getPath.next();
p = getPath.next();

وسأرفق لكم حل مبسط جدا للسؤال ، وبعض المتطلبات غير كامله ، حيث كنت قد كتبته لأحدهم :) ، بالاضافه الى حلي أيضا (قمت بحله باستخدام UDP ) . وهي في المرفقات في الرد القادم .

بالنسبه لـ RMI - Remote Method Invocation فهي كما واضح من الأسم أنها عباره عن أستدعاء لدوال تكون موجوده في السيرفر ، والنقطه الجيده في RMI هي أنه يبعدنا تماما عن تفاصيل الSocket والأرسال وما الى ذلك ، فقط نحصل على reference للكائن البعيد ومن خلاله نقوم باستدعاء الداله الموجوده هناك . والأخ مبتدئ الجافا كفى ووفى .

أما بالنسبه للtrue في الـ PrintWriter فهي لعمل AutoFlush للبفر Buffer ، أي بمجرد لما أرسل البيانات تذهب للسوكت في الجهه الأخرى ولا تبقى في البفر .

أما عندما نستخدم ObjectOutputStream ، لا توجد داله بناء من خلالها نستطيع عمل هذه الخاصيه ، لذلك يجب أن أضيفها صراحه بعد كل عمليه أرسال .

بالنسبه لتقنيه CORBA - فهي بنفس مفهوم الـ RMI لكنها تستدعي دوال مكتوبه بلغات برمجه أخرى ، وهي أعقد من الأولى بالطبع . باذن الله نتناول هذه التقنيات في الجلسه الثانيه Session 2 .

بالنسبه لأسئتلكم حول نقل شاشه العميل الى السيرفر أو التحكم به أو عمل Video Conference ، أو أي شيء من هذه النوعيه من البرامج ، فالجواب بالطبع تستطيع ذلك ، كيف ؟ الله أعلم :D

صراحه لم أجرب كتابه أحد هذه البرامج ، لذلك لن أستطيع الأفتاء فيها ، لكن أعتقد أنها ليست بهذه الصعوبه ... وحتى نقطع الشك باليقين سأضع لكم تمرين وهو كتابه أحد هذه البرامج :lol: .

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

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

كما ذكرت لم أقم بتجريب كتابه مثل هذا البرنامج ، على العموم يمكننا تجريب مثال screen shot ، وذلك بأخذ صوره كل ثانيه أو جزء من الثانيه ونقوم بارسالها ، وهكذا سننقل صوره حيه للجهاز . ربما تكون الطريقه سئيه للغايه ، ولكنها مجرد بدايه فقط .

http://informatic-ar.com منصة تعليمية عربية في علوم الحاسب والبرمجة

https://moalfat.com  للكتب الالكترونية والكورسات التعليمية

Everything we see now is just an engineering solution based on old science

#53

السلام عليكم ورحمه الله وبركاته ،

تناولنا المره السابقه موضوع TCP Client/Server وقمنا بتطبيق بعضا من البرامج البسيطه ، أيضا كنا قد ذكرنا أن بروتوكول TCP برتوكول Connection Oriented بالأضافه الى أنه موثوق بمعني أنه قد يعيد أرسال الرساله في حال لم تصل أو وصلت بشكل ناقص (هذه التفاصيل يقوم بها البرتوكول وليس المبرمج) وهذا يؤدئ الي بطئ في عمليه الأرسال ، وفي بعض التطبيقات قد نحتاج الى عامل السرعه ونهمل عامل الوثوقيه ، مثال على ذلك سيرفر يحتوي على مجموعه من الأفلام ، ويقوم الكلاينت بالأتصال بهذا السيرفر وأختيار أحد هذه الأفلام لكي يشاهدها ، في حال قمنا باختيار برتوكول TCP وحصلت مشكله في أثناء مشاهده الفلم (مثلا تم ارسال باكت بشكل ناقص ) المهم يقوم TCP باعاده ارسال هذا الباكت مره أخرى ، وهكذا في كل بت ناقص سوف يعيد الأرسال مره أخرى وهو أمر غير مرغوب فيه حتما في مثل هذا التطبيق . لذلك الحل في استخدام برتوكول UDP ، وهذا البرتوكول لا يهتم هل تم ارسال الباكت بشكل صحيح أم خاطئ ، فقط يقوم بالأرسال لذلك هو أسرع من الأول وهو المناسب في هذا التطبيق .

أيضا في UDP لا يكون هناك أتصال بمجرد عمل socket في الكلاينت كما في TCP ، الأتصال لا يكون الا في حاله ارسال أو استقبال فقط وهي معلومه مهمه جدا حيث أن أي كلاينت يريد أن يتصل بالسيرفر لن يستطيع الأتصال بانشاء سوكت فقط كما في TCP ، لكن يجب عليه أن يقوم بالارسال للسيرفر حتى يكون الأتصال . ومن هذا الكلام نستنتج أن السيرفر في UDP دائما يستقبل في البدايه والكلاينت يرسل في البدايه .

الان الأرسال والأستقبال في UDP يختلف عن TCP ، حيث يكون هنا الأرسال عن طريق الباكت Packet ولن نستطيع أن نرسل أو نستقبل الا عن طريق الباكت ، وكما سنرى بعد قليل أنه هذا الأمر سهل كثيرا في برمجه الكلاينت والسيرفر .

في موضوعنا اليوم ، سنتناول UDP Client/Server ، ولن تكون هناك أي مشاكل فيه خاصه لمن فهم النوع الأول ، لأن الفكره نفسها مجرد أختلافات قليله . وكما في المره السابقه ، سنتناول الأن كيفيه أنشاء كلاينت وسيرفر بهذا البرتوكول بشكل عام ، بعدها نقوم بشرح وتوضيح الكلاسات والدوال المهمه . وبشكل عام برمجه كلاينت - سيرفر باستخدام UDP تعتمد على كلاسين رئيسين هما : DatagramSocket و DatagramPacket ، الأولى تقوم بعمليه الأرسال والأستقبال (وسوف ننشئها في السيرفر والكلاينت) والكلاس الثاني هو الذي سوف نرسله لأن الأرسال والأستقبال كما ذكرنا يكون في صوره باكت (وسوف ننشئه أيضا في الكلاينت والسيرفر) .

خطوات أنشاء UDP Server :

1- انشاء كائن من الكلاس DatagramSocket برقم المنفذ الذي تريد -أختر من 1024 الى 65535- :

DatagramSocket socket  = new DatagramSocket(5000);

-2 استقبال باكت Packet قادم من الكلاينت - كما ذكرنا دائما السيرفر هو من يستقبل أولا ، وذلك لأنه لا يكون هناك أتصال الا من خلال الأرسال أو الأستقبال فقط- :

DatagramPacket inPacket;
byte buffer[] = new byte[1024];
inPacket = new DatagramPacket(buffer,buffer.length);
socket.receive(inPacket);

3- بعد استقبال الباكت من الكلاينت ، نقوم باستخراج المعلومات من هذا الباكت ، وهذه المعلومات هي رساله الكلاينت ، ورقم البورت للكلاينت ، وعنوان الكلاينت . ومن هذه المعلومات أقوم بالرد عليه .

int port = inPacket.getPort();
InetAddress address = inPacket.getAddress();
String msgIn = new String ( inPacket.getData(),0,inPacket.getLength());

4- الرد على الكلاينت وارسال باكت له - طبعا سنستخدم رقم البورت وعنوان الكلاينت الذي حصلنا عليهم من الباكت القادم من الكلاينت .

String msgOut = " OK ";
 DatagramPacket outPacket = new DatagramPacket( msgOut.getBytes() , msgOut.length(), 
address , port );				
socket.send( outPacket );

5- نغلق السوكت :

socket.close();

وعاده السيرفر يجب أن يكون شغال على مدار 24ساعه .

أنتهت خطوات السيرفر ، تأتي الأن للكلاينت وسنرى أنها هي بالضبط كالسيرفر ولكن نبدأ أولا بالأرسال وبعدها بالأستقبال ، وهذا هو الأختلاف فقط .

خطوات إنشاء الكلاينت UDP Client :

1- ننشئ DatagramSocket كما في السيرفر ، ولكن بدون رقم بورت ، في الحقيقه جميع الDatagramSocket يجب أن نحدد لها بورت ما حتى تستطيع الأستقبال والأرسال من خلاله ، لكن في الكلاينت هنا نحن لسنا بحاجه الى معرفه هذا البورت ، فيقوم النظام باختيار أي بورت متاح له ، لكن في السيرفر نحن نحتاج الى معرفه البورت لذلك نقوم بتحديده حتى يستطيع الكلاينت الأتصال به . فعندما ننشيء DatagramSocket من غير بورت يقوم النظام بفتح بورت ما لهذا السوكت . وعند ارسالنا باكت من الكلاينت للسيرفر سوف يوضع هذا البورت "المجهول" في الهيدر الخاص بالباكت بالاضافه الى عنوان الكلاينت ، ومنه سوف يستطيع السيرفر معرفه البورت والعنوان الخاص بالكلاينت حتى يقوم بالرد عليه .

socket = new DatagramSocket();

2- نقوم بارسال باكت للسيرفر مع تحديد رقم بورت السيرفر وعنوانه :

String msgOut = " Hello Im Client ";
 DatagramPacket outPacket = new DatagramPacket( msgOut.getBytes() , msgOut.length(), 
address , port );				
socket.send( outPacket );

3- نقوم باستقبال الباكت القادم من السيرفر :

byte buffer[] = new byte[1024];
DatagramPacket inPacket = new DatagramPacket(
buffer,buffer.length);				
socket.receive(inPacket);

(لاحظ عمليه الأرسال والأستقبال هي نفسها بالضبط سواء في السيرفر أو في الكلاينت) .

4- نقوم باستخراج المعلومات من الباكت القادم ، وبما أنه من السيرفر فلا حاجه لاستخراج البورت والعنوان لأننا على علم بهم ، فقط نستخرج الرساله :

msgIn = new String( inPacket.getData(),0,inPacket.getLength());

5- نغلق السوكت :

socket.close();

وأنتهت الخطوات للكلاينت ، واذا تمعنت النظر فيهم ، ستجد أنهم متشابهين 99% من بعض ، فقط تغير ترتيب الأرسال والأستقبال ، أما الباقي فكما هو وهذه ميزه الUDP أنه سهل في التعامل . أضافه الى أنه كما قد تكون لاحظت أن الباكت يتعامل فقط مع بيانات البايت Byte .

لذلك أذا أردت أن ترسل أي شيئ يجب أن تحوله الى Byte . وهذا أمر جيد خصوصا أن ملفات الصور والصوت والفيديو يتم التعامل معها على شكل بايت .

لكن المشكله الكبيره جدا في برتوكول UDP وهو أن هناك حجم ثابت للباكت ، وهو تقريبا 60 كيلو بايت KB ، وحقيقه هو أقل قليلا حيث هناك 2 KB محجوزه للترويسه (تحتوي على العنوان والبورت وبضعه أشياء أخرى). وهذه المشكله لم أكن أعلم بها الا عندما بدأت برمجه FTP Server/Client بهذا البرتوكول حيث أردت أن أرسل صور بحجم كبير وتفاجأت بـ Exception يقول بأن الباكت تعدى الحجم المسموح له . فقمت بكتابه حل سيء لكنه يعمل بشكل جيد ، حيث نقوم أقوم أولا بمعرفه الحجم الذي أريد أن أرسله ، فاذا كان أصغر من الحجم المسموح وهو 58 KB فأرسل الباكت مباشره ، أما اذا كان أكبر فأقوم باقتطاع أول 58 KB من الحجم الكلي ، وأقوم بارساله في الباكت الأول ، وبعدها أنظر للحجم ، فاذا كان أكبر من 58 KB فأقوم بأخذ 58 KB التاليه وهكذا .... الخوارزميه التي كتبتها سيئه وكان من الممكن أن أستخدم داله جاهزه لهذا الأمر لكني لم أكن على علم بها ، ولكنها عملت بأفضل وجه ، وستجد البرنامج كاملا في المرفقات .

الدوال الرئيسيه في الكلاس DatagramPacket :

public DatagramPacket(byte[] buffer, int length) 
public DatagramPacket(byte[] data, int length,  InetAddress destination, int port)

public InetAddress getAddress( )
public int getPort( )
public byte[] getData( )
public int getLength( )


public void setData(byte[] data)
 public void setData(byte[] data, int offset, int length)
public void setAddress(InetAddress remote)
public void setPort(int port)
public void setLength(int length)

دوال البناء -وهي أما للأرسال أو للأستقبال- وهي :

public DatagramPacket(byte[] buffer, int length) 
public DatagramPacket(byte[] data, int length,  InetAddress destination, int port)

الداله الأولى ، للأستقبال ، وهنا سوف أحدد مصفوفه ما ، وهي التي سوف تضع فيها القيم القادمه من الجهه الأخرى ، بالأضافه الى طول هذه المصفوفه ، مثال :

byte[] buffer = new byte[8192];
DatagramPacket dp = new DatagramPacket(buffer, buffer.length);
socket.receive(dp);

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

مثال :

String s = "This is a test";
byte[] data = s.getBytes("ASCII");
  InetAddress ia = InetAddress.getByName("www.ibiblio.org");
  int port = 7;

  DatagramPacket dp = new DatagramPacket(data, data.length, ia, port);
  // send the packet...

المجموعه الثانيه من الدوال ، وهي دوال get :

public InetAddress getAddress( )
public int getPort( )
public byte[] getData( )
public int getLength( )

ووظيفه هذه الدوال تتضح من الأسم . ونستخدم دائما هذه الدوال بعد عمليه استقبال باكت ما ، حتى نعرف من الذي أرسله ، وما هي محتويات هذا الباكت (البيانات التي فيه) .

أما في حال أستخدمت هذه الدوال لباكت أنشئته لغرض الأرسال ، فسوف تعيد هذه الدوال المعلومات في الباكت الحالي ، ونادرا ما نحتاج لمثل هذا الأمر ...

وهذا مثال لكي نخرج معلومات باكت أنشئناه محليا لغرض أرساله لجهه أخرى .

// Get Information on local packet to be sent to other side

import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.UnknownHostException;

public class Demo
{
	public static void main (String args[])
	{
		try
		{
			InetAddress address = InetAddress.getByName("127.0.0.1");
			int port = 100;
			String message = "Hello Im Romansy";

			DatagramPacket outPacket = new DatagramPacket (message.getBytes(),message.length(),address,port);

			System.out.println("This Packet is Sent to : " + outPacket.getAddress() + "\n"+
							   "in Port : " + outPacket.getPort() + "\n" +
							   "Thare are : " + outPacket.getLength() + " Number of Byte in Packet\n" +
							   "Message is : " + new String(outPacket.getData(),0,outPacket.getLength()));
		}
		catch ( UnknownHostException e)
		{
			e.printStackTrace();
		}
	}
}

المخرج :

java Demo

This Packet is Sent to : /127.0.0.1

in Port : 100

Thare are : 16 Number of Byte in Packet

Message is : Hello Im Romansy

المجموعه الثالثه من الدوال وهي دوال set :

public void setData(byte[] data)
 public void setData(byte[] data, int offset, int length)
public void setAddress(InetAddress remote)
public void setPort(int port)
public void setLength(int length)

وهي تستخدم لتغيير معلومات datagramPacket ما ، وغالبا لن نحتاج لهذه الدوال حيث أننا نحدد هذه المعلومات في داله البناء عندما ننشء الباكت ، لكن هناك حالات يجب أن نستخدم هذه الدوال ، فمثلا اذا كان حجم الباكت أكبر من المسموح ، نقوم باستخدام الداله الثانيه ، وهنا نحدد القيم التي نريدها من المصفوفه أي من المنطقه 0 الى الخانه مثلا 100 ، وبعدها بعد ارسال الباكت ، نقوم بتغير البيانات مره أخرى وهنا نمرر نفس المصفوفه ولكن من الخانه 100 الى 200 وهكذا ..

أيضا setAddress نستخدم لتغير العنوان في الباكت ، مثلا لو أردنا أن نرسل الباكت لأكثر من عنوان

String s = "Really Important Message";
		byte[] data = s.getBytes();

		DatagramPacket dp = new DatagramPacket(data, data.length);

		dp.setPort(2000);

		int network = "128.238.5.";

		for (int host = 1; host < 255; host++)
		{
			try 
			{
				InetAddress remote = InetAddress.getByName(network + host);
				dp.setAddress(remote);
				socket.send(dp);
			}
			catch (IOException ex)
			{
				// slip it; continue with the next host
			}
		}

واذا كان الغرض الأرسال لجميع العنواين ، فيمكن أن تستخدم عنوان النشر broadcast address وأجعل الشبكه تقوم بالباقي . عنوان النشر تكون دائما تحتوي على 255 . مثلا العنوان : 128.238.0.0 عنوان النشر له هو 128.238.255.255 .

لاحظ الطريقه السابقه سواء بالكود السابق أو باستخدام عنوان النشر ، سوف نرسل الباكت لجميع الأجهزه في الشبكه فقط يعني لن نستطيع الوصول الى شبكه أخرى .. واذا أردنا أن نمكن هذه الخاصيه فيجب أن نستخدم الـ Multicasting ، وهنا سوف نستخدم نفس الباكت DatagramPacket ، ولكن سوف نستخدم سوكت من نوع MulticastSocket . سوف نتكلم عنها المره القادمه باذنه تعالى .

ننتقل في الحديث الى الكلاس الثاني في UDP وهو DatagramSocket ، وسوف نناقش أهم الدوال فيه ، وهي :

public DatagramSocket( ) throws SocketException
public DatagramSocket(int port) throws SocketException

public void send(DatagramPacket dp) throws IOException
public void receive(DatagramPacket dp) throws IOException

public void close( )
public int getLocalPort( )
public InetAddress getLocalAddress( )

داله البناء الأولى :

public DatagramSocket( ) throws SocketException

وهي تقوم بانشاء DatagramSocket ، وكما ذكرنا أن أي DatagramSocket يجب أن نحدد له بورت معين ، وفي حال أستخدمنا هذه الداله سوف يقوم النظام بنفسه باختيار "بورت مجهول" ، ويمكنك معرفه هذا البورت اذا أردت باستخدام الداله getLocalPort .

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

هذه الداله تولد SocketException لكنه نادر الحدوث ، لأن البورت يقوم بتحديده النظام بنفسه ، وهنا لن يقوم النظام باختيار بورت مفتوح مسبقا . لذلك هذا الException نادرا ما يحدث .

داله البناء الثانيه :

public DatagramSocket(int port) throws SocketException

هنا سوف ننشئ DatagramSocket ويقوم بفتح البورت المحدد ، والـ Exception هنا قد يكون أما تم فتح بورت مفتوح مسبقا من قبل UDP Server (في حال كان البورت نفسه مفتوح من خلال TCP فلا توجد مشكله ، لأن البورتات في TCP تختلف عن UDP ) . أو تكون المشكله أنك قمت بفتح بورتات من 1 الى 1024 وأنت لا تملك صلاحيات root (تحدث هذه المشكله في أنظمه يونكس) .

نقوم الأن بكتابه UDP Port Scanner ، وكما ذكرنا أن البورتات في TCP تختلف عن UDP فاذا فتحت بورت بTCP فتستطيع فتحه بلا مشاكل باستخدام UDP والعكس صحيح .

// Local UDP Port Scanner

import java.net.DatagramSocket;
import java.net.SocketException;

public class Demo
{
	public static void main (String args[])
	{	
		for (int i=1; i<=65535;i++)
		{
			try
			{
				DatagramSocket socket = new DatagramSocket(i);
				socket.close();
			}
			catch ( SocketException e)
			{
				System.out.println("There is Server on Port : " + i);
			}
		}
	}
}

المخرج :

java Demo

There is Server on Port : 123

There is Server on Port : 445

There is Server on Port : 1900

الان بقيه الدوال في الكلاس DatagramSocket هي :

public void send(DatagramPacket dp) throws IOException
public void receive(DatagramPacket dp) throws IOException

public void close( )
public int getLocalPort( )
public InetAddress getLocalAddress( )

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

الداله الثانيه ، وهي لاستقبال الباكت القادم من الجهه الأخرى ، والIOException غير متوقع أبدا حدوثه . أهم نقطه وهي أن الداله receive مثل الداله accpet في ServerSocket حيث تقوم بعمل Block للThraed الحالي ، الا أن تستقبل الباكت من الجهه الأخرى ، وفي حال لم يصل فيظل البرنامج معلق هكذا . لذلك اذا كنت تريد عمل أمور أخرى أثناء استقبالك لباكت فقم بوضع هذه الجمله في Thread منفصل .

الدوال الباقيه تتضح عملها من أسمها ، ولا يوجد جديد في الأمر ، حيث close تقوم بغلق السوكت ، و getLocalPort تخرج البورت الحالي للسوكت ، getLocalAddress تخرج العنوان الحالي ونادرا ما نحتاج لهاتين الدالتين .

نقوم الأن بعرض مثال شامل Echo UDP Client/Server ونضع فيه جميع ما تعلمناه هنا :

كود السيرفر :

// UDPEcho Server
// Server Received Message From User  , Pint It , Send OK to Clinet

import java.net.DatagramSocket;
import java.net.DatagramPacket;
import java.net.SocketException;
import java.net.InetAddress;
import java.io.IOException;

public class UDPEchoServer
{
	private static final int PORT = 6000;
	private static DatagramSocket socket;

	public static void main (String args[])
	{
		try
		{
			socket = new DatagramSocket(PORT);
			System.out.println("********* Server Open Connection ***********");
		}
		catch ( SocketException e)
		{	System.out.println("Unable To Attach To Port !"); }

		accessClient();
	}

	public static void accessClient()
	{

		try
		{
			do{
			DatagramPacket inPacket, outPacket;

			byte buffer[] = new byte[1024];
			inPacket = new DatagramPacket(buffer,buffer.length);

			socket.receive(inPacket);

			int port = inPacket.getPort();
			InetAddress address = inPacket.getAddress();
			String msgIn = new String ( inPacket.getData(),0,inPacket.getLength());

			System.out.println("Cleint > " + msgIn );

			String msgOut = " OK ";
			outPacket = new DatagramPacket( msgOut.getBytes() , msgOut.length(), 
					address , port );

			socket.send( outPacket );
			}while ( true );
		}
		catch ( IOException e)
		{	e.printStackTrace();	}
		finally
		{
			System.out.println("******* CLOSE Connection **********");
			socket.close();
		}
	}
}

كود الكلاينت :

// UDPEchoClient
// send msg to Server , Received OK 

import java.net.DatagramSocket;
import java.net.DatagramPacket;
import java.net.SocketException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.io.IOException;
import java.util.Scanner;

public class UDPEchoClient 
{
	private static final int PORT = 6000;
	private static InetAddress address;

	public static void main (String args[])
	{
		try
		{
			address = InetAddress.getLocalHost();
		}
		catch ( UnknownHostException e)
		{
			System.out.println("Cannot Find ID Host !");
			System.exit(1);
		}

		accessServer();
	}

	public static void accessServer ()
	{
		DatagramSocket socket = null;
		try
		{
			socket = new DatagramSocket();
			Scanner input = new Scanner(System.in);

			String msgIn ="" , msgOut="";

			while ( ! msgOut.equals("CLOSE") ) 
			{
				System.out.print("Enter Message : " );
				msgOut = input.nextLine();

				DatagramPacket outPacket = new DatagramPacket(
					msgOut.getBytes(),msgOut.length(),address,PORT);

				socket.send(outPacket);

				byte buffer[] = new byte[1024];
				DatagramPacket inPacket = new DatagramPacket(
					buffer,buffer.length);

				socket.receive(inPacket);

				msgIn = new String( inPacket.getData(),0,inPacket.getLength());

				System.out.println("Server > " + msgIn );
			}
		}
		catch ( IOException e)
		{	e.printStackTrace();	}
		finally
		{
			socket.close();
			System.out.println("******* CLOSE Cleint Connection *******");
		}

	}
}

يمكنك الان تطبيق البرامج السابقه التي طرحناها في TCP باستخدام UDP اذا أردت . مثلا DayTimeServer , Chatting .

وفي المرفقات برنامج FTP Client/Server Using UDP . وقد قمت بتقسيم البرنامج الى عده كلاسات حتى أقوم باستخدامها مره أخرى في حال أردت تطوير البرنامج وأستخدم الواجهات GUI .

SocketManager وهو مسؤول عن عمليه الأرسال والأستقبال الباكتات

UploadFile وهو مسؤول عن استلام ملف من الجهه الأخرى

DownloadFile وهو مسؤول عن تحميل ملف من جهه ما

FTPClient الكلاينت

FTPServer السيرفر

لتشغيل البرنامج ، شغل السيرفر أولا من Command Line وأرسل له أي بورت تريد :

java FTPServer 5000

بعدها شغل الكلاينت ، وأكتب عنوان السيرفر ورقم البورت الخاص به :

java FTPClient 127.0.0.1 5000

واستمتع بعدها بالنتائج :) :) .

المفترض الأن أننا أنهينا هذه الجلسه Session one ، لكن تبقت المواضيع وأعتقد أن يجب أن نمر عليها ولو مرور الكرام فقط :)

Non-Blocking Server Using Channels

Mail Programming

Multicasting Socket

HttpServer Programming

الى اللقاء .

FTP_Client_Server_Using_UDP.rar

FTP_ClientServer_Using_TCP.rar

http://informatic-ar.com منصة تعليمية عربية في علوم الحاسب والبرمجة

https://moalfat.com  للكتب الالكترونية والكورسات التعليمية

Everything we see now is just an engineering solution based on old science

#54

طرف الخيط :

http://java.sun.com/products/java-media/jmf/

ويمكنكم البحث أكثر في قووقل وستجدوا ما تريدوا :rolleyes:

http://informatic-ar.com منصة تعليمية عربية في علوم الحاسب والبرمجة

https://moalfat.com  للكتب الالكترونية والكورسات التعليمية

Everything we see now is just an engineering solution based on old science

#55

لوضع نسخة تنفيذية من البرنامج

يتم الرجوع للمجلد المحفوظ فيه مجلدات المشروع , يوجد مجلد تحته اسمه dist

داخل هذا المجلد يوجد ملفات ال jar الخاصة بالمشروع .

لى ملاحظة , لماذا لم تضعى الأكواد فى ملفات وترفقيها مع الرسالة بدلا من وضعها مباشرة فى المشاركة .

#56

السلام عليكم ،

أولا أحب أشكر dr.sara على المجهود والمتابعه الأكثر من رائعه ، فجزاك الله خيرا وجعله في ميزان حسناتك ...

وأعتذر عن المغيب الفتره السابقه وذلك نظرا لظروف الدراسه ..وسأقوم بقرائه الأكواد التي تم وضعها وأعلق عليها باذن الله .

على العموم سنكمل قريبا باذن الله في Session 2 ، وباذن الله نتناول الدورس التى أوضحتها في مشاركتي الأخيره ، اضافه الى دروس في التعامل مع Media وعمل Streaming Video وما الى ذلك ... طبعا كما ذكرت لا توجد لدى خبره كافيه ، وكل ما تقدمنا كلما يزداد الوضع سوءا :) ، على العموم بالمشاركه الجماعيه كل شيء يهون خاصه مع وجود أعضاء أمثال dr.sara فلا أظن هناك مشكله .

كان هناك من سأل حول كيفيه أرسال BufferedImage و ResultSet الى الجهه المقابله ؟

المهم بالنسبه لـ BufferedImage كما ذكرت في تلك المشاركه هناك Stream لارسال الـ BufferedImage ولكني لم أتعامل معه الى الأن ، على العموم كنا ذكرنا طريقه سيئه وهي حفظ الصوره في ملف ، وارسال محتويات الملف كBytes ومن ثم قرائه تلك المحتويات وحفظها على الجهاز الأخر ، المشكله كانت عندما نريد عرض تلك المعلومات على الجهاز الأخر ، فسوف أضطر مره أخرى لفتح ذلك الملف وأقوم بقرائه محتواياته ومن ثم عرضها هناك !! بالطبع طريقه سيئه جدا ...

المهم ، طريقه أخرى وهي أفضل بكثير جدا ، وهي تحويل ال BufferedImage قبل أرساله الى ImageIcon ومن ثم ارساله عن طريق ObjectOutputStream ، ولن تكون هناك مشكله حيث أن ImageIcon هو Serialazble والداله write في الكائن ObjectOutputStream تتطلب ذلك .

قمت بكتابه كلاس أسميته ScreenShot يقوم بالتقاط الصوره وارجاعها كـBufferedImage ، كل ما علينا بعد عمل object من هذا الكلاس تحويل الناتج الى ImageIcon وارساله الى الجهه الأخرى .

ScreenShot sc = new ScreenShot(ScreenShot.SCREEN_SIZE);
BufferedImage img = sc.getShot();

ImageIcon icon = new ImageIcon( img );
out.flush();

out.writeObject(icon);
out.flush();

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

المهم بعد ارسال الImageIcon الى الجهه الأخرى ، نقوم بتحويل الناتج الى ImageIcon ونضعها في مثلا JLabel

ImageIcon icon = (ImageIcon) objIn.readObject();
lbl.setIcon(icon);

وفي المرفقات الكود الكامل ، للكلاينت والسيرفر ، كل ما يضغط الكلاينت على زر get فسوف تأتيه الصوره كامله من السيرفر وتتعرض أمامه .

وفي حال أردت أن تقوم بالمتابعه بشكل دوري أي تقوم بالتقاط الصوره كل فتره ممكن ان تتعامل مع Timer وتتلقط الصوره كل ثانيه .

بالنسبه لإرسال ResultSet (نتيجه أستعلام ) فلا يمكن أن ترسلها بهذا الشكل ولذلك يعود الى أن الكلاس ResultSet لا يطبق الInterface الـ Serializable .

ResultSet data;
out.writeObject(data)

ويبدوا من الكود أنك تريد أرسال ResultSet لكي تجعل الكلاينت يستعلم من قاعده البيانات ، ولا أظنها طريقه جيده في حال كانت تعمل ، والحل الأفضل هو أن تقوم أنت بارسال الأستعلام الى السيرفر ، ويقوم السيرفر بالرد عليك ، ويرسل لك الناتج مثلا على شكل Object ومن ثم تحوله الى String وتقوم بطباعته على الشاشه .

أي أن الكلاينت لا يفترض أن يعلم بـ ResultSet ولا أي metaData ولا connection ... كل ما عليك أن ترسل الأستعلام كString الى السيرفر ، والسيرفر يستخدم ResultSet ويعود لك بالناتج ، وفي حال حصل خطأ يعود لك مثلا null ، وأنت في الكلاينت أختبر القادم أولا فاذا كان null فمعناه ان الأستعلام خاطئ .

في حال لم تفهم أو كانت هناك مشكله ، أذكرها وسنقوم بكتابه مثال لهذا الأمر .... وان كنا سنتكلم عن هذا الموضوع قريبا في Session 2 . وسوف نرى أنه يمكن أن نستخدم RMI في هذه الحاله ....

الى اللقاء .

ScreenShot_ClientServer.rar

http://informatic-ar.com منصة تعليمية عربية في علوم الحاسب والبرمجة

https://moalfat.com  للكتب الالكترونية والكورسات التعليمية

Everything we see now is just an engineering solution based on old science

#57
romansy كتب:

ويبدوا من الكود أنك تريد أرسال ResultSet لكي تجعل الكلاينت يستعلم من قاعده البيانات ، ولا أظنها طريقه جيده في حال كانت تعمل ، والحل الأفضل هو أن تقوم أنت بارسال الأستعلام الى السيرفر ، ويقوم السيرفر بالرد عليك ، ويرسل لك الناتج مثلا على شكل Object ومن ثم تحوله الى String وتقوم بطباعته على الشاشه .

أي أن الكلاينت لا يفترض أن يعلم بـ ResultSet ولا أي metaData ولا connection ... كل ما عليك أن ترسل الأستعلام كString الى السيرفر ، والسيرفر يستخدم ResultSet ويعود لك بالناتج ، وفي حال حصل خطأ يعود لك مثلا null ، وأنت في الكلاينت أختبر القادم أولا فاذا كان null فمعناه ان الأستعلام خاطئ .

في حال لم تفهم أو كانت هناك مشكله ، أذكرها وسنقوم بكتابه مثال لهذا الأمر .... وان كنا سنتكلم عن هذا الموضوع قريبا في Session 2 . وسوف نرى أنه يمكن أن نستخدم RMI في هذه الحاله ....

الى اللقاء .

بارك الله فيك أخي رومنسي على هذا الشرح ... لكن حقيقة انا و لله الحمد عندي خلفية جيدة نوعا ما عن Sockets و RMI , و مشكلتي ليست فيهم أبدا , و لكن المشكلة الحقيقية تواجهني في فهم Streams , و اشكالها , وماهي نوع البيانات التي تمر خلالها , ولماذا نستخدمها , و ماهي Objects التي يمكن ارسالها كما هي عبر الشبكة مثل ImageIcon , ولماذا لا نستطيع ارسال مثلا ResultSet , طبعا بسبب انها غير non Serializable , لكن كيف نحدد ان هذا العنصر ليس Serializable , بمعنى لماذا ImageIcon يمكن ارسالها , و ImageBuffered لا يمكنها ذلك.

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

تحياتي أخي العزيز....

#58

بالنسبه للحديث عن الثريد

الثريد هي تجزئ برنامجك الى قطع او مهمات tasks

لكي تعرف متى تستخدم ثريد ومتى لاتستخدمها الامر يعتمد على ماذا تريد ان تعمل

اعد النظر في برامجك ان كان هناك عمليه تاخذ وقت طويل في تنفيذها وعليها يتاخر تنفيذ ماتبقى من برنامجك

هنا انت بحاجه للثريد

سوائا كان جهازك بروسسيسور واحد او ملتبل بروسيسور

انت لاتريد جعل البروسيسور فاضي وينتظر حدث ما ( كتابة ملف او استعمال اي resource بجهازك )

وهناك امور اخرى ببرنامجك لم تنفذ

فاذا طلب برنامجك اتصال بالشبكه او كتابه على الديسك ( التي تعتبرها انها تاخذ وقت ) بامكانك جعل هذا في ثريد

وبقية برنامجك في ثريد اخر

انت هنا لم تجعل البروسسور ينتظر لانك فصلت بين العمليات فهذا كفيل بجعل برنامجك اكثر سرعه من كونه ينفذ في ثريد واحد

#59
MKSoft كتب:
بارك الله فيك أخي رومنسي على هذا الشرح ... لكن حقيقة انا و لله الحمد عندي خلفية جيدة نوعا ما عن Sockets و RMI , و مشكلتي ليست فيهم أبدا , و لكن المشكلة الحقيقية تواجهني في فهم Streams , و اشكالها , وماهي نوع البيانات التي تمر خلالها , ولماذا نستخدمها , و ماهي Objects التي يمكن ارسالها كما هي عبر الشبكة مثل ImageIcon , ولماذا لا نستطيع ارسال مثلا ResultSet , طبعا بسبب انها غير non Serializable , لكن كيف نحدد ان هذا العنصر ليس Serializable , بمعنى لماذا ImageIcon يمكن ارسالها , و ImageBuffered لا يمكنها ذلك.

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

تحياتي أخي العزيز....

طبعا بعد الاستئذان من romansy وليسمح لي بالمشاركه معكم

كلنا نتفق ان البيانات تتمثل في 0s1s في قاع التمثيل representation

الان كلما ارتفعنا فوق اصبح التمثيل للبيانات او Streams التدفقات اكثر وضوحا من ذي قبل

فهناك التمثيل الذي نفهمه والمتمثل مثلا في Scanner BufferedInput Output مثلاً

فانت هنا تتعامل مع Strings

طبعا هذا كلام على السريع انت تستطيع معرفة كل كلاس representation تبعه من javadoc

بالنسبه لSerialization

اي اوبجكت Serializable نستطيع ارساله عبر الشبكه

اما الذي مش Serializable فهو لسبب وظيفي بحت

مثلاً ResultSet منطقيا لايمكنك ارسالها لانها مرتبطه بكونكشن معين ودرايفر له

طبعا هناك مشاريع عملت هالشغله لكني ماعرف تفاصيلها

بامكانك عمل ArrayList وتضيف البيانات فيها وترسلها للكلاينت عندك في RMI

او انك تقوم بانشا كلاس جديد Business class وترسل instance منه للعميل ( وانا افضل هالحل )

#60

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

تحياتي.

#61

السلام عليكم

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

يبدو أنه قد فاتني الكثير وأنا لا أدري

لكن ولله الحمد هناك الكثير مما أعرفه

هذا لا يمنع أني استفدت كثيراً

جيد كان لي موضوع في القسم عن موضوع JEditorPane

وقد قمت بعمل متصفح عليه قديماً

بالطبع متصفح بسيط جداً

أظن أني أضفت إلى الأمام وإلى الخلف

بالنسبة لموضوع Serilaizable

ببساطة لكي تعلم إن كنت تستطيع نقل الكائن أولأ تأكد من أنه يقوم ببناء implements للواجهة Serilaizable

هذا الواجهة interface لا تحتوي على أي دوال

وتسمى هذه النوعية من الواجهات Markup Interface

وظيفتها الأساسية هي أن تخبر الآلة الإفتراضية VM أن هذا الكائن يمكن عمل Serialize له

بالنسبة لموضوع الخيوط Thread أظن أن هناك موضوع للأخ عيسى

يمكن البحث عنه

كنت أتمنى أن أنضم لكم هنا لكن مشاغل مشروع التخرج

والأخ JBOSS يتسلى بنا

لكني سأكتفي بالمتابعة

لدي ملاحظة للأخ رومانسي

لا أعرف لماذا أجد الأسلوب ممل قليلاً عند عرض الدوال

أفضل أسلوب الأمثلة والتوضيح عليها

جهد رائع ولا يستهان به البتة

تحياتي

حزمة المحرك الإصدارة 0.8

أي أحد يجد أني ظلمته فليراسلني

وبإذن الله لو كان له حق سيأخذه

728x90.png

#62

السلام عليكم ورحمه الله وبركاته ،

بارك الله فيكم أخوتي جميعا ونفع بكم الاسلام والمسلمين ... أعتذر عن التأخير لهذه الفتره الطويله لاسباب خارجه عن الأراده . بالنسبه لك dr.sara فلم أقرا برامجك الى الأن لكن كما وعدتك سأقوم بقرائتها باذن الله وأقوم بالتعليق عليها ...

نكمل أخر درس في هذه الجزئيه ، وحاولت بقصارى جهدي لأن يكون واضح ، خاصه هو موضوع غير متداول بكثره . أضافه الى الساعه الأن متأخره قليلا وحان وقت النوم :) .

تحدثنا المره السابقه عن موضوع الـ URL والـ URI ، وقد قمنا بعرض أمثله على كيفيه معرفه مكونات هذا الـ URL (أي البرتوكول المستخدم ، اسم الموقع ) وهو ما يعرف بـ URL Parsing . حديثنا اليوم عن الـ Parsing أيضا ، ولكن ليس للـ URL أو URI وإنما لصفحه الـ HTML نفسها . فقد يحدث أنك تريد معرفه جزء معين في الصفحه ، فتقوم بعمل Parse للمحتويات الصفحه (HTML Tag ) وتقوم بأخذ أو عرض ما تريد معرفته فقط ، وذلك عن طريق الكلاسات المخصصه لعمل HTML Parser وهو ما سنتكلم عنه الأن .

HTML Parsing :

=============

ان الكلاسات الرئيسيه المستخدمه في موضوع HTML Parse هما :

javax.swing.text.html.HTMLEditorKit 
javax.swing.text.MutableAttributeSet 
javax.swing.text.html.HTML

وبداخل الكلاس HTMLEditorKit يحتوي على عده كلاسات داخليه Inner Class ، من أهمها هم Parser والأخر هو ParserCallback .

public abstract static class HTMLEditorKit.Parser extends Object
public static class HTMLEditorKit.ParserCallback extends Object

الكلاس HTMLEditorKit.Parser هو المسؤول عن عمليه الـ Parser ، ولكنه كلاس abstract أي أنك لن تستطيع عمل كائن منه فقط تستخدم الوراثه معه . هناك كلاس أخر يسمى ParserDelegator يرث هذا الكلاس لكن حتى نستخدمه يجب أن نحصل على كائن من نوع DTD ، وهو موجود في javax.swing.text.html.parser.DTD ، وتبقى مشكله الكلاس DTD أنه صعب التعامل معه ، لذلك لن نحصل على الـ Parser باستخدام الـ ParserDelegator ...

الطريقه الأخرى للحصول على الـ Parser وذلك عن طريق وجود الداله (في نفس الكلاس) getParser ولكنها من نوع protected ، لذلك نقوم بعمل وراثه extends من الكلاس Parser بعدها نقوم بتجاوز هذه الداله وتعديلها من protected الى public .

protected HTMLEditorKit.Parser getParser( )

الكود التالي يقوم بالمهمه :

class GetParser extends HTMLEditorKit
{
	public HTMLEditorKit.Parser getParser()
	{
		return super.getParser();
	}
}

الأن وبعد حصولنا على الـ Parser ، يمكن أن نبدأ عمليه الـ Parse باستخدام الداله parse الموجوده في الكلاس Parser ، وهذه الداله parse تستقبل ثلاثه معاملات ، الأول هو أي كائن من نوع Reader (أي المكان الذي سأقوم القرائه منه) ، والثاني هو أيضا كائن ولكن من نوع HTMLEditorKit.ParserCallback (ويتم استدعائه كل مره يقوم الـ Parser بمشاهده أحد HTML Tag أو أيه نصوص أو حتى مشكله أثناء عمل الـ Parser ) ، المعامل الثالث هو لتجاهل الترميز المستخدم في المعامل الأول ، فاذا وضعنا true معناه تجاهل الترميز ، أما اذا كانت false فمعناه عدم التجاهل وهنا في حال كانت الصفحه تحتوي على ترميز معين (في الرمز Mata Tag ) فسوف يحصل Exception من نوع ChangedCharSetException ويمكنك هنا تغيير الترميز الى ذلك الموجود في الصفحه .

public void parse(Reader in, HTMLEditorKit.ParserCallback callback, boolean ignoreCharacterSet) throws IOException

نتحدث عن المعامل الثاني وهو HTMLEditorKit.ParserCallback لأنه هو الذي يتعامل مع هذه الـ Tag ، وكل الكود سوف يكون فيه . هذا الكلاس ParserCallback هو كلاس داخلي Inner class ، موجود في :

javax.swing.text.html.HTMLEditorKit

ويحتوي على دوال فارغه لا تحتوي على أيه كود ، وعليك باعاده تعريف ما تريد منها ، الدوال هي :

public void handleText(char[] text, int position)
public void handleComment(char[] text, int position)
public void handleStartTag(HTML.Tag tag, MutableAttributeSet attributes, int position)
public void handleEndTag(HTML.Tag tag, int position)

الداله الأولى وهي للتعامل مع النصوص الموجوده داخل الـ Tags ، والثانيه للتعامل مع التعليقات ، والثالثه تتعامل مع بدايه الـ Tag ، والرابعه للتعامل مع نهايه الـ Tag .

نعرض المثال التالي وسوف يوضح أغلب الموضوع بأكمله ان شاء الله ، وهو يقوم بقرائه صفحه html (في المثال localhost ) ومن ثم يقوم بعرض النصوص فقط بدون الـ Tag (وهنا سوف نستخدم الداله الخاصه بالنصوص handleText ) .

// print HTML Page Without Tage

import javax.swing.text.html.HTMLEditorKit;

import java.io.InputStream;
import java.io.Writer;
import java.io.BufferedInputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.IOException;

import java.net.URL;

class GetParser extends HTMLEditorKit
{
	public HTMLEditorKit.Parser getParser()
	{
		return super.getParser();
	}
}

class TagHandler extends HTMLEditorKit.ParserCallback
{
	private Writer writer;

	public TagHandler (Writer w )
	{
		writer = w;
	}

	public void handleText ( char text[] , int position )
	{
		try
		{
			writer.write(text);
			writer.flush();
		}
		catch (IOException e)
		{
			e.printStackTrace();
		}
	}
}

public class Demo
{
	public static void main (String args[])
	{
		try
		{
			GetParser kit = new GetParser();
			HTMLEditorKit.Parser parser = kit.getParser(); 

			TagHandler th = new TagHandler( new OutputStreamWriter(System.out));

			URL url = new URL("http://localhost");
			InputStream in = new BufferedInputStream( url.openStream() );
			InputStreamReader r = new InputStreamReader(in);

			parser.parse(r,th,true);
		}
		catch (IOException e)
		{
			e.printStackTrace();
		}
	}
}

نقوم بشرح المثال بشكل سريع ، أولا كما ذكرنا في البدايه لن نستطيع التعامل مع Parser مباشره ، لذلك يجب أن نلجأ لطريقه ما لنحصل عليه ، فاستخدمنا هنا الكلاس GetParser وقمنا بعمل extends للكلاس Parser واعدنا تعريف الداله getParser لترجع الى Parser .

الكلاس الثاني وهو TagHandler وهو أيضا يرث الـ Callback ، وقمنا باعاده تعريف الداله التي تهمنا وهو handleText لأننا فقط نريد طباعه النصوص ، والـ Parser يقوم باستدعاء هذه الداله كلما وجد نص (ويستدعي باقي الداول ، ولكن هم فارغين الأن) . في الداله handleText قمنا بطباعه النص عن طريق writer وهو كائن أعطيناه القيمه عن طريق داله البناء .

الأن في الداله الرئيسيه main ، نحصل أولا على Parser ، ثم نستدعي الداله parse بالمعاملات الثلاثه وهم reader ، والثاني هو كائن من نوع Callback ، والثالث قيمه منطقيه true .

قم بتشغيل البرنامج ، وستجد أنه قام بطباعه النصوص الموجوده في الصفحه فقط ، لاحظ أنه أي سطر جديد أو عده مسافات يتجاهلها الـ Parser ويجعلها كمسافه واحده ، و في حال أردنا أن نطبع مثلا كل سطر كما هو ، يجب أن نتعامل مع الـ Tag ، وهو ما سنتكلم عنه بعد قليل .

في حال قمنا بتغيير البرنامج الى برنامج ليقوم بطباعه التعليقات في الصفحه ، فنفس البرنامج بالضبط ولكن فقط بتغيير الداله handleText ، بالداله handleComment وتعريف الداله كما هو ، أي فقط نغير اسم الداله ، وبعد تشغيلك للبرنامج سيخرج لك فقط التعليقات الموجوده بالصفحه في حال كانت هناك تعليقات .

نفس البرنامج ولكن مع تغيير الداله الخاصه بالتعامل مع النص الى التعامل مع التعليق ، وستجد أن المخرج هو التعليقات الموجوده بالصفحه :

// print comment in HTML Page

import javax.swing.text.html.HTMLEditorKit;

import java.io.InputStream;
import java.io.Writer;
import java.io.BufferedInputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.IOException;

import java.net.URL;

class GetParser extends HTMLEditorKit
{
	public HTMLEditorKit.Parser getParser()
	{
		return super.getParser();
	}
}

class TagHandler extends HTMLEditorKit.ParserCallback
{
	private Writer writer;

	public TagHandler (Writer w )
	{
		writer = w;
	}

	public void handleComment ( char text[] , int position )
	{
		try
		{
			writer.write(text);
			writer.flush();
		}
		catch (IOException e)
		{
			e.printStackTrace();
		}
	}
}

public class Demo
{
	public static void main (String args[])
	{
		try
		{
			GetParser kit = new GetParser();
			HTMLEditorKit.Parser parser = kit.getParser(); 

			TagHandler th = new TagHandler( new OutputStreamWriter(System.out));

			URL url = new URL("http://localhost");
			InputStream in = new BufferedInputStream( url.openStream() );
			InputStreamReader r = new InputStreamReader(in);

			parser.parse(r,th,true);
		}
		catch (IOException e)
		{
			e.printStackTrace();
		}
	}
}

لنعود لنفس البرنامج الأول ، كما ذكرنا أنه يتجاهل المسافات والسطور ويعتبرها مسافه واحده ، لذلك في حال كان كود html كالتالي :

<H1> Here's   the   Title </H1>



<P> Here's the text </P>

اذا المخرج سوف يكون :

Here's the TitleHere's the text

وهو أمر غير جيد ، لذلك علينا التعامل مع كل Tag ووضع كود للتعامل معه ، مثلا أذا رأينا أحد الـ Tag التاليه فمعناها انه يجب أن ننزل سطر جديد ( أي نختبر اذا كان الtag هو من الموجودين بالأسفل قم بطباعه سطر جديد) :

<BR>

<LI>

<TR>

أما اذا كان نهايه الTag هو أحد الTags التاليه ، فمعناها أنه يجب أن نضع سطرين Paragraph Break:

<P>

</H1> </H2> </H3> </H4> </H5> </H6>

<HR>

<DIV>

</UL> </OL> </DL>

الأن بقي علينا كيف يمكن أن تختبر هل الTag القادم هو مثلا <h1> وهذه وظيفه الكلاس HTML.Tag حيث هي مجموعه من كل الـ Tag معرفه مسبقا .

الكلاس HTML.Tag :

=============

الكلاس Tag هو كلاس داخلي في javax.swing.text.html.HTML ، يحتوي على الدوال التاليه ، وهي تريحنا من أختبار كل Tag على حده :

public boolean isBlock( )
public boolean breaksFlow( )
public boolean isPreformatted( )
public String  toString( )

الداله الأولى isBlock ترجع True في حال كان الـ Tag الحالي يسبب مسافه سطرين مثل P .

الداله الثانيه breaksFlow ترجع True في حال كان الـ Tag الحالي يسبب سطر واحد فقط ،

الداله isPreformatted ترجع True اذا كان الTag ينص على أنه يجب أن يكون كما هو وبدون حذف للمسافات ( وهي خاصه للـ Tag الPRE ) .

الأن نقوم بالتعديل في البرنامج السابق لكي يتعامل مع المسافات ، وذلك عن طريق اضافه الداله handleStartTag ونختبر اذا كان الTag يسبب سطر فنقوم بطباعه سطر، أما اذا كان يسبب سطرين فنقوم بطباعه سطرين ، والا اطبع مسافه . نفس الأمر مع الداله الثانيه handleEndTag ونقوم بنفس الأختبار .

// print HTML Page Without Tage

import javax.swing.text.html.HTMLEditorKit;
import javax.swing.text.html.HTML;
import javax.swing.text.MutableAttributeSet;

import java.io.InputStream;
import java.io.Writer;
import java.io.BufferedInputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.IOException;

import java.net.URL;

class GetParser extends HTMLEditorKit
{
	public HTMLEditorKit.Parser getParser()
	{
		return super.getParser();
	}
}

class TagHandler extends HTMLEditorKit.ParserCallback
{
	private Writer writer;

	public TagHandler (Writer w )
	{
		writer = w;
	}

	public void handleText ( char text[] , int position )
	{
		try
		{
			writer.write(text);
			writer.flush();
		}
		catch (IOException e)
		{
			e.printStackTrace();
		}
	}

	public void handleStartTag ( HTML.Tag tag , MutableAttributeSet attribute , int poisiotn )
	{
		try
		{
			if ( tag.breaksFlow())
			{
				writer.write("\n");

			}
			else if ( tag.isBlock() )
			{
				writer.write("\n");
				writer.write("\n");
			}
			else
				writer.write(' ');

		}
		catch (IOException e)
		{
			e.printStackTrace();
		}
	}

	public void handleEndTag ( HTML.Tag tag , MutableAttributeSet attribute , int poisiotn )
	{
		try
		{
			if ( tag.breaksFlow())
			{
				writer.write("\n");
			}
			else if ( tag.isBlock() )
			{
				writer.write("\n");
				writer.write("\n");
			}
		}
		catch (IOException e)
		{
			e.printStackTrace();
		}
	}
}

public class Demo
{
	public static void main (String args[])
	{
		try
		{
			GetParser kit = new GetParser();
			HTMLEditorKit.Parser parser = kit.getParser(); 

			TagHandler th = new TagHandler( new OutputStreamWriter(System.out));

			URL url = new URL("http://localhost");
			InputStream in = new BufferedInputStream( url.openStream() );
			InputStreamReader r = new InputStreamReader(in);

			parser.parse(r,th,true);
		}
		catch (IOException e)
		{
			e.printStackTrace();
		}
	}
}

وفي الكثير من الأحيان نريد ان تختبر وجود Tag معين ، فاذا كان مثلا الـ Tag هو مثلا a (الخاص بالعنواين) أقوم مثلا بعرض العنوان فقط ، وأتجاهل باقي الـ Tags . في هذه الحاله علينا أختبار الـ Tag بعينه ، وهذه الTags معرفه مسبقا داخل HTML.Tag ، وهي :

HTML.Tag.A
HTML.Tag.FRAMESET
HTML.Tag.PARAM
HTML.Tag.ADDRESS
HTML.Tag.H1
HTML.Tag.PRE
HTML.Tag.APPLET
HTML.Tag.H2
HTML.Tag.SAMP

وهناك الكثير من هذه الـ Tags ، حوالي 73 Tag ، يمكنك مراجعه الـ Documentation لمعرفه الباقي .

نأخذ مثال على عمل Parse لصفحه ، وفي حال وجدنا مثلا Tag الH1 أو H2 الى H6 نقوم بطباعه مثلا Heading Found . هنا لأننا نريد التعامل مع هذا الـ Tag سوف نتعامل مع الداله handleStartTag ونقوم بعمل أختبار هل الTag هو مثلا H1 ، فاذا كان كلذلك نقوم بطباعه العباره ، والا نتجاهل الباقي ..

// print HTML Page Without Tage

import javax.swing.text.html.HTMLEditorKit;
import javax.swing.text.html.HTML;
import javax.swing.text.MutableAttributeSet;

import java.io.InputStream;
import java.io.Writer;
import java.io.BufferedInputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.IOException;

import java.net.URL;

class GetParser extends HTMLEditorKit
{
	public HTMLEditorKit.Parser getParser()
	{
		return super.getParser();
	}
}

class TagHandler extends HTMLEditorKit.ParserCallback
{
	private Writer writer;

	public TagHandler (Writer w )
	{
		writer = w;
	}


	public void handleStartTag ( HTML.Tag tag , MutableAttributeSet attribute , int poisiotn )
	{
		try
		{
			if ( tag == HTML.Tag.H1 || 
				tag == HTML.Tag.H2 || 
				tag == HTML.Tag.H3 || 
				tag == HTML.Tag.H4 || 
				tag == HTML.Tag.H5 || 
				tag == HTML.Tag.H6  )
			{

				writer.write("Found Heading\n");
				writer.flush();
			}
		}
		catch (IOException e)
		{
			e.printStackTrace();
		}

	}

}

public class Demo
{
	public static void main (String args[])
	{
		try
		{
			GetParser kit = new GetParser();
			HTMLEditorKit.Parser parser = kit.getParser(); 

			TagHandler th = new TagHandler( new OutputStreamWriter(System.out));

			URL url = new URL("http://localhost/forum");
			InputStream in = new BufferedInputStream( url.openStream() );
			InputStreamReader r = new InputStreamReader(in);

			parser.parse(r,th,true);
		}
		catch (IOException e)
		{
			e.printStackTrace();
		}
	}
}

الى هنا أصبحنا نصل الى ما نريد ونطبع العباره التي نريد ، ولكن هناك الكثير من الـ Tag فيها خصائص Attribute وبعض الأحيان نريد أن نحصل عليها ، مثلا لدينا الTag الخاص بالوصلات وهو a ، فيه الخاصيه href وفيها نحدد الموقع الذي نريده ، أيضا في الTag الخاص بالخطوط Font هناك الخاصيه size و color ...

كيف يمكن الحصول على الخصائص ؟ .. لو لاحظنا في المعامل الثاني للداول handleStartTag و handleSimpleTag سنجد أنها كائن من نوع MutableAttributeSet ، وهو في الحقيقيه Sub-Interface من الـ AttributeSet .

public abstract interface MutableAttributeSet extends AttributeSet

هناك الكثير من الدوال المعرفه في AttributeSet منها معرفه عدد الخصائص ، وأختبار تساوي خاصيه ، ودوال أخرى ، وأهم دوال سوف نستخدمها هي :

public Enumeration  getAttributeNames( )
public Object	   getAttribute(Object name)

الداله الأولى ، تقوم بارجاع جميع الخصائص في الكائن Enumeration ، ومن خلال هذا الكائن ، نستطيع الحصول على خاصيه من هذه الخصائص على شكل كائن بالداله nextElement ، وعندما نحصل على الكائن (والذي هو الخاصيه) نقوم باستخدام الداله الثانيه getAttribute ونمرر لها الخاصيه التي حصلنا عليها ، والنتيجه هي قيمه هذه الخاصيه ... هذه العمليه تكون بالمقطع التالي:

 Enumeration e = attributes.getAttributeNames( );
  while (e.hasMoreElements( )) {
	Object name = e.nextElement( );
	Object value = attributes.getAttribute(name);
	System.out.println(name + "=" + value);
  }

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

المثال هو عباره عن طباعه جميع الوصلات الموجوده في الصفحه ، طبعا سوف نقوم بعمل parse للصفحه ، وسوف نستخدم الداله handleStartTag وسوف نختبر اذا كان الـ Tag هو a ، فنقوم بالحصول على القيمه -كما ذكرنا قبل قليل- ومن ثم نعرضه على الشاشه :

// Extract Link From URL
// By : Romansy

import javax.swing.text.html.HTMLEditorKit;
import javax.swing.text.html.HTML;
import javax.swing.text.MutableAttributeSet;

import java.io.OutputStreamWriter;
import java.io.InputStreamReader;
import java.io.Writer;
import java.io.BufferedInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.IOException;

import java.net.URL;
import java.util.Enumeration;

class ParserGetter extends HTMLEditorKit
{
	public HTMLEditorKit.Parser getParser ()
	{
		return super.getParser();
	}
}

class TagTake extends HTMLEditorKit.ParserCallback
{
	private Writer out;
	private boolean isLink = false;

	public TagTake (Writer o )
	{
		out = o;
	}

	public void handleStartTag ( HTML.Tag tag , MutableAttributeSet attributes , int position )
	{
		if ( tag == HTML.Tag.A )
		{
			Enumeration e = attributes.getAttributeNames( );

			while (e.hasMoreElements( )) 
			{
				Object name = e.nextElement( );
				Object value = attributes.getAttribute(name);

				System.out.println( value);

			}
		}
	}

}

public class HTMLDemo3
{
	public static void main (String args[])
	{
		ParserGetter kit = new ParserGetter ();
		HTMLEditorKit.Parser parser = kit.getParser();
		HTMLEditorKit.ParserCallback callback = new TagTake( new OutputStreamWriter(System.out) );

		try
		{
			URL u = new URL("http://localHost/forum");
			InputStream in = new BufferedInputStream(u.openStream());
			InputStreamReader r = new InputStreamReader(in);

			parser.parse(r,callback,true);
		}
		catch (IOException e)
		{
			e.printStackTrace();
		}
	}
}

و المخرج بالطبع هو جميع الوصلات الموجوده في الصفحه ...

أخبرا قبل أن ننهي الحديث ، أحب أن اعرض فكره المشروع وهو عباره عن برنامج تحميل مواقع ، أي نقوم بتحديد موقع ما ، ثم يقوم البرنامج بحفظ جميع صفحات هذا الموقع لديه في الجهاز . نظريا الأمر ليس بتلك الصعوبه ، فطريقه العمل ستكون كالتالي ، نقوم أولا بعمل Parse للصفحه ونخرج جميع الوصلات ، ثم نأخذ وصله وصله ، ونقوم بالأتصال بها عن طريق URL ونقوم بحفظ الصفحه في الجهاز -قد تناولنا في أول هذه الدروس كيفيه الأتصال بالـ URL وتحميله - ، ثم نخرج جميع الوصلات ، وندخل للوصله الأولى ونحفظ الصفحه وو ، الى أن ننتهي فنرجع للصفحه الرئيسيه ونكمل مع الرابط التالي ، وهكذا (مع تجاهل الوصلات التي تكون خارج الموقع الحالي) .... أظن الصعوبه سوف تكمن في عمليه الدخول الى الراوبط أو ما تسمى بعمليه الزحف Crwaler ، وهي فكرتها مثل فكره برامج البحث ..

باذن الله ، كم يوم ونبدأ في المرحله الثانيه ... شكرا لكل من تابع معنا .

الحمد لله الذي بنعمته تتم الأمور .

http://informatic-ar.com منصة تعليمية عربية في علوم الحاسب والبرمجة

https://moalfat.com  للكتب الالكترونية والكورسات التعليمية

Everything we see now is just an engineering solution based on old science

#63

السلام عليكم ورحمه الله وبركاته ،

أهلا أختي dr.sara ،

بالنسبه لـ URL فأنا كنت كاتبها صح لأني أختبرت البرامج قبل أن أضعهم هنا ، ولكنها تغيرت تلقائيا هنا ، ربما البرنامج الذي يستخدمه المنتدى يحول بعض الكلمات الى حرف كبير ، على العموم سأصلحها الأن مره أخرى ،

بالنسبه للمشروع ، فأكيد أنا مشارك فيه ان شاء الله ، ولكني سأتأخر قليلا والسبب الدراسه ، على العموم البرنامج كما ذكرت وظيفته تحميل صفحات الموقع للتصفح لاحقا . طبعا هنا يجب أن نستخدم طريقه حتى نتكمن من دخول الروابط في الموقع بصوره مرتبه ، وهذا الأمر قد يدخلنا في موضوع الـ Web Crawling . وهو ليس بالسهل جدا ، لكن مع جافا وتوفر هذه المكتبات الجيده لن نواجه صعوبه باذنه تعالى .

هذا رابط لبرنامج قريب :

http://www.matuschek.net/jobo/

طبعا نحن نريد برنامج بأقل الأمكانيات وليس مثل البرنامج أعلاه .

اقتباس
تجاهل الوصلات التي تكون خارج الموقع الحالي

هنا كنت أقصد مثلا أذا كان هناك رابط لموقع أخر فعلينا تجاهله ، فقط نريد تحميل موقعنا .

مثلا أردت تحميل موقع xx ، وكان أحد الروابط به موقع أخر yy فيجب تجاهل هذا الموقع ، فقط نحمل ملفات موقعنا الحالي xx .

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

وظيفه البرنامج ليست البحث في العنوان ، ولكنه فقط يقوم بالحصول على العنواين التي تكون في الـ Tag المخصص للعنواين (وهو a وبعدها تكون كلمه href ومن ثم يكون العنوان) ، هو فقط يأخذ هذا العنوان ويطبعه على الشاشه .

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

Writing a Web Crawler in the Java Programming Language

Crawling the Web with Java

SearchCrawler

بالتوفيق في دراستك .

تم تعديل هذه المشاركة بواسطة romansy في 8 مايو 2008 في 00:29

http://informatic-ar.com منصة تعليمية عربية في علوم الحاسب والبرمجة

https://moalfat.com  للكتب الالكترونية والكورسات التعليمية

Everything we see now is just an engineering solution based on old science

#64

ما شاء الله ... الموضوع صار اخطر مما توقعت ... :)

الله يكرمك اخي الرومنسي ... و اعتذر عن تقصيري في المشاركة هنا سابقاً و ذلك لاني حالياً مشغولة ببحث ما :)

البركة في العزيزة الدكتورة سارة ... جزاها الله كل خير ايضاً على اثراء الموضوع بحلولها ...

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

كل التقدير ...

لا اله الا الله .. محمد رسول الله

(* ربِ اجعلني مقيم الصلاة و من ذريتي ، ربنا و تقبل دعـاء *)

يا حيّ يا قيـوم ... برحمتك استغيث ... اصلح لي شأني كله و لا تكلني الى نفسي طرفة عين

#65

والله دعيت لكل واحد شارك بهذا الشرح والوافي. انت وفرتم عليه قرأت كتاب من 500 صفحة باللغة الانكليزية بس الي اطلبة من صاحب الموضوع ينزل كلامه الذهب بكتاب pdf ويرفقة مع الموضوع لان هذه دروس افضل من دروس الاساتذة الذين يستلمون كذا مبلغ لكن من دون فائدة ترتجى منهم مع احترامي للاساتذة المتميزين والناجحين منهم واخيراً شكرا على هذا الشرح الوافي>> اخوكم ابتسامة عراقية

#66

جزيتم خيرا .. بالفعل الموضوع قيم ..وشكرا لمن قام برفع الموضوع لأني كنت ابحث عن مثل هذه المعلومات

#67

اولا شكرا علي الموضوع الرائع جدا استاذي وجدي :) هل للموضوع تكمله ام الي هنا انتهي ؟ ... في موضوع ParserHTML في هاد المثال ..

/**
 * @(#)Demo.java
 *
 *
 * @author 
 * @version 1.00 2009/9/8
 */

import javax.swing.text.html.HTMLEditorKit;
import javax.swing.text.html.HTML;
import javax.swing.text.MutableAttributeSet;

import java.io.IOException;
import java.io.InputStream;
import java.io.Writer;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.BufferedInputStream;
import java.net.URL;

class GetParser extends HTMLEditorKit.ParserCallback
{
	public HTMLEditorKit.Parser getParser()
	{
		return getParser();
	}

}

class TagHandler extends HTMLEditorKit.ParserCallback
{
	private Writer writer;
	public TagHandler(Writer w)
	{
		writer = w;
	}
	// handleComment : to Parser Comment ...
	// handleText	: to Parser Text ...
	// handleStartTag: to Parser Space ...
	// handleEndTag  : to Parser Space ...

	public void handleText(char text[],int postition)
	{
		try
		{
			writer.write(text);
			writer.flush();
		}
		catch(IOException e)
		{
			e.printStackTrace();
		}
	}
	public void handleStartTag(HTML.Tag tag ,MutableAttributeSet attribute,int postition)
	{
		try
		{
			if(tag.breaksFlow())
			{
				writer.write("\n");
			}
			if(tag.isBlock())
			{
				writer.write("\n");
				writer.write("\n");
			}
			if(tag == HTML.Tag.H1||
			   tag == HTML.Tag.H2||
			   tag == HTML.Tag.H3||
			   tag == HTML.Tag.H4||
			   tag == HTML.Tag.H5||
			   tag == HTML.Tag.H6)
			{
				writer.write("Heading Found ... ");

			}   	


		}
		catch(IOException e)
		{
		}

	}

		public void handleEndTag(HTML.Tag tag ,MutableAttributeSet attribute,int postition)
	{
		try
		{
			if(tag.breaksFlow())
			{
				writer.write("\n");
			}
			if(tag.isBlock())
			{
				writer.write("\n");
				writer.write("\n");
			}

		}
		catch(IOException e)
		{
		}

	}



}

public class Demo 
{
	public static void main(String arge[])
	{
		try
		{
			GetParser kit = new GetParser();
			HTMLEditorKit.Parser parser = kit.getParser();
			TagHandler th = new TagHandler(new OutputStreamWriter(System.out));
			URL u = new URL("http://www.shababit.ps");
			InputStream in = new BufferedInputStream(u.openStream());
			InputStreamReader r = new InputStreamReader(in);
			parser.parse(r,th,true);	
		}
		catch(IOException e)
		{
			e.printStackTrace();
		}



	}

}

طلع Execption ما مر علي قبل هيك : Exception in thread "main" java.lang.StackOverflowError

ab66i830gh93.gif

i25sctz8qnls.jpg

#68

وعليكــم السـلام ورحمة الله وبركاتـه..

الException المسمى StackOverFlow يحدث عندما يمتلئ المكدس Stack وهذا في الغالب في الجافا بسبب وجود استدعاء ذاتي للدوال Recursive Function ..

في مثالك وضعت :

class GetParser extends HTMLEditorKit.ParserCallback
{
	public HTMLEditorKit.Parser getParser()
	{
		return getParser();
	}

}

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

الصحيح هو استدعاء الدالة التي توجد في الكلاس الأب ، بهذا الشكل :

class ParserGetter extends HTMLEditorKit
{
	public HTMLEditorKit.Parser getParser ()
	{
		return super.getParser();
	}
}

للمزيد أنصح بقرائه :

Java Network Programming ,, 3rd Edition

بالتوفيق أخي الكريم ،،

http://informatic-ar.com منصة تعليمية عربية في علوم الحاسب والبرمجة

https://moalfat.com  للكتب الالكترونية والكورسات التعليمية

Everything we see now is just an engineering solution based on old science

#69

مزيوط انا عملت هيك قبل ما يطلع الغلط هاد بس بيقولي انو الداله getParser () مش معرفه في الكلاس الاب ... كيف ذالك ؟

ab66i830gh93.gif

i25sctz8qnls.jpg

#70

لأنك ورثت من الكلاس الداخلي :

class GetParser extends HTMLEditorKit.ParserCallback

الصحيح أن ترث مباشره من HTMLEditorKit :

class GetParser extends HTMLEditorKit

بالتوفيق ،،

http://informatic-ar.com منصة تعليمية عربية في علوم الحاسب والبرمجة

https://moalfat.com  للكتب الالكترونية والكورسات التعليمية

Everything we see now is just an engineering solution based on old science

#71

لم انتبه الي هذه النقطه راح اعدلها ان شالله .. :) شكرا اخ وجدي :)

تم تعديل هذه المشاركة بواسطة Tigger_it في 9 سبتمبر 2009 في 14:14

ab66i830gh93.gif

i25sctz8qnls.jpg

#72

ربنا يكرمك اخى وجدى

بجد موضوع جامد اخر تلات اربع حاجات.....

بس محتاجة اعرف يعنى ايه برتوكول.... :P

قرات الكلمة دى كتير بس مش عارفة معناه فى البرمجة

انا قرات 3 صفحات و نكمل بعدين بقى اصلى تعبت :)

تم تعديل هذه المشاركة بواسطة اسراء شلبى في 5 يوليو 2010 في 20:12

00020309t.gif

1958_1963.gif
#73
اقتباس
بس محتاجة اعرف يعنى ايه برتوكول....

إنتي موش بتعرفي تتكلمي روسي صح؟

و الروسي غالبا موش بيعرف يتلكم عربي صح؟

طب إيه الحل؟؟ الحل إن يكون فيه بروتوكول معتمد للكلام بين الناس اللي موش بتتكلم لغه واحده.

لننتقل للشبكات:

هناك مئات الشركات التي تصنع كروت الشبكات (الإيثرنت مثلا الموجود عندك في جهازك).

ما الذي يضمن أن منتجات الشركات سوف تعمل معا,, لابد من أن يكون هناك بروتوكول يضمن أن أي شركه مصنعه لجهاز ما, لابد و أن تتبع معايير البروتوكول لكي نضمن أن منتج الشركه س سوف يعمل مكان منتج الشركه ص. و بالتالي ستوجد تنافسيه بين الشركات و سعر أقل.

يمكن النظر له على أنه Interface الذي يحققه (implements) الصناع.

فمثلا يمكن النظر لل JDBC على أنه بروتوكول تعامل برامج الجافا مع قواعد البيانات, و اي مصنع قاعدة بيانات ليجعل الجافا تحدثه, لابد و أن يحقق هذا البروتوكول.

2
#74

شكرا جدا جدا اخى هويدى على ردك

حقيقة فى بداية الرد و انا اقرأه استغربت قولت ايه اللى جاب الروسى و العربى للموضوع :wacko: قولت اكيد دى اثار السى :lol:

بس فعلا انا فهمت

متشكرة جدا جدا

00020309t.gif

1958_1963.gif

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