الشبكات في جافا | Java Networking

 التعامل مع الشبكات في جافا | Java Networking

شبكة تعني Network في اللغة الإنجليزية, الفكرة الأساسية من الشبكات هي ربط الأجهزة على إختلاف أنواعها مع بعض لخلق نوع من التواصل فيما بينهم. فمثلاً الأجهزة الموصولة على الشبكة سواء كانت كمبيوترات أو هواتف أو سيرفرات, يمكنها مشاركة البيانات مع بعضها البعض بواسطة برامج معينة.

Network Programming تعني كتابة برنامج يشارك بياناته مع برنامج آخر من خلال شبكة.
في العادة يكون برنامج مثبت على السيرفر و برنامج مثبت عند المستخدم العادي.
الفكرة هنا بناء برامج للمستخدمين تجعلهم قادرين على التواصل مع بعضهم و مشاركة البيانات فيما بينهم.

عندما نقول مشاركة البيانات من خلال شبكة, نقصد بذلك أن الكمبيوتر سيشارك بياناته مع كمبيوتر آخر.
يمكن أن يكون كلا الكمبيوترات موجودين على نفس الشبكة و يمكن أن يكون كل كمبيوتر منهم في بلد مختلف ( لا يهم ).

لبناء برامج يمكنها مشاركة البيانات مع بعضها عبر الشبكات, نستخدم الحزمة java.net التي تحتوي على مجموعة ضخمة من الكلاسات و الإنترفيسات المصممة خصيصياً لمشاركة البيانات عبر الشبكات.


فائدة بناء برامج تتواصل مع بعضها من خلال شبكة

  1. مشاركة البيانات بين مختلف المستخدمين على الشبكة.

  2. تجميع البيانات التي نريد مشاركتها في مكان واحد, الأمر الذي يجعلنا قادرين على التحكم في طريقة مشاركة هذه البيانات.


أفكار لبرامج تعمل على الشبكة

يوجد أفكار كثيرة لبرامج يستخدمها الناس لمشاركة بياناتهم و التي يمكنك بناءها بنفسك أيضاً, أمثلة:

  • برنامج محادثة, مثل MSN, Yahoo, Telegram, Whatsapp.

  • متصفح, حيث يمكنك بناء متصفح مثل Mozilla FireFox, Google Chrome, Internet Explorer,Opera Mini.

  • ألعاب, حيث أنه يمكنك بناء لعبة يستطيع فيها اللاعبين تحدي بعضهم عن بعد.

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

مصطلحات أساسية في عالم الشبكات

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

المصطلح معناه
NIC NIC إختصار لـ Network Interface Card, و معناه كرت الشبكة.
كرت الشبكة هو قطعة إلكترونية يتم تركيبها في أي جهاز إلكتروني حتى يستطيع الإتصال بالشبكات.
MAC Address MAC Address إختصار لـ Media Access Control Address, و هو عبارة عن رقم كرت الشبكة الخاصة بالجهاز.
كل كرت شبكة يملك MAC Address موحد.
الـ MAC Address يتألف من 12 bytes, كل byte فيهم يمكن أن يكون رقم بين 0 و 9, أو حرف بين A و F.

أمثلة
  • 00:1C:B3:09:85:15

  • 00:B0:D0:86:BB:F7

  • 00:1B:44:11:3A:B7

IP Address IP Address إختصار لـ Internet Protocol Address, و هو عبارة عن عنوان مؤقت يتم إعطائه لأي جهاز يريد الإتصال بالشبكة.
كل جهاز يريد الإتصال بالشبكة يتم إعطائه IP Address مختلف.
الـ IP Address يتألف من أربعة أرقام, كل رقم فيهم يمكن أن يكون بين 0 و 255.

أمثلة
  • 80.10.5.104

  • 192.168.0.1

  • 210.14.92.65

Protocol في العربية أيضاً نقول بروتوكول, و هو عبارة عن مجموعة قواعد أساسية يجب إتباعها في كل عملية تواصل.
في عالم الشبكات يوجد بروتوكولات كثيرة, كل واحد منهم مصمم لغرض معين.

أشهر البروتوكولات
  • TCP: يستخدم عند نقل بيانات على الشبكة, يضمن وصولها إلى الجهة المطلوبة كما هي تماماً.

  • UDP: يستخدم عند نقل بيانات على الشبكة, لا يهمه إذا فقد جزء من البيانات التي تم إرسالها.

  • HTTP: يستخدمه المتصفح عندما تقوم بتصفح المواقع.

  • FTP: يستخدم عند تحميل أي نوع من الملفات.

  • Telnet: يستخدم للتحكم في البرامج عن بعد.

  • POP3: يستخدم من قبل العميل لإستقبال الرسائل إلكترونية الواردة في بريده مع إمكانية حذفها.

  • SMTP: يستخدم من قبل العميل لإرسال رسائل إلكترونية إلى السيرفر.

Port Number في العربية نقول رقم البورت.
كل برنامج يرسل أو يستقبل بيانات على الشبكة يحتاج أن يفتح بورت خاص فيه على الجهاز.
رقم البورت يتيح للمستخدم إستخدام أكثر من برنامج يتعاملون مع الشبكة في نفس الوقت.
إذاً رقم البورت يميز البرامج التي تستخدم الشبكة عن بعضها البعض.
URL إختصار لـ Uniform Resource Locator, و يعني كل المعلومات المذكورة في الرابط و التي تشير إلى مصدر محدد للبيانات.

المعلومات الأساسية في أي رابط:   protocol://prefix.domain:port/path/filename
  1. protocol نضع مكانها إسم البروتوكول المستخدم في عملية الإتصال مثل http

  2. prefix نضع مكانها في العادة www

  3. domain نضع مكانها إسم الموقع مثل harmash.com

  4. port نضع مكانها بورت البرنامج أو البروتوكول المستخدم من قبل العميل, فمثلاً الـ http يستخدم البورت 80

  5. path نضع مكانها إسم المجلد الذي نريد الدخول إليه على السيرفر.

  6. filename نضع مكانها إسم الملف الذي نريد تصفحه أو تحميله إلخ..


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

أمثلة
Socket الـ Socket عبارة عن مجموعة الكلاسات التي يمكن إستخدامها لإنشاء برامج تجعل المستخدمين قادرين على التواصل فيما بينهم بشكل متزامن عبر شبكة النت. و هي تضمن المعلومات الأساسية التي نحتاجها لإجراء أي عملية إتصال: Socket = IP Address + Port Number + Protocol

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

  2. عنوان الشخص الذي سنرسل له البيانات.

  3. رقم بورت البرنامج الذي سنستخدمه لإرسال البيانات.


خلاصة

يمكن الوصول لأي جهاز على الشبكة من خلال الـ IP Address الخاص فيه.
و كل تطبيق يتعامل مع الشبكات سواء لإرسال أو إستقبال بيانات يحتاج إلى رقم بورت خاص فيه ليميزه عن باقي البرامج التي تستخدم الشبكة.

الكلاسات التي نحتاجها للتعامل مع الشبكات في جافا

الكلاس مع تعريفه
public class URL هذا الكلاس مصمم بشكل عام لتجهيز روابط الملفات التي سنتعامل معها عن بعد عبر شبكة الإنترنت.
تابع القراءة »
public class URLConnection هذا الكلاس عبارة عن Abstract Class, و هو يستخدم للقراءة و الكتابة في الملف الذي يشير له كائن الـ URL, بالإضافة إلى أنه يمكننا من معرفة و تحديد كافة المعلومات المتعلقة بإجراء الإتصال مع الملف.
فمثلاً يتيح لنا معرفة آخر مرة تم فيها تحديث الملف, تاريخ صلاحية الملف, إسم الكلاس المناسب لإرسال المعلومات منه و استقبالها فيه إلخ..
تابع القراءة »
public class InetAddress هذا الكلاس مصمم لتحليل عنوان الجهاز أو الموقع الذي نحاول الإتصال به عن بعد عبر شبكة النت.
تابع القراءة »
public class Socket + public class ServerSocket الـ Socket عبارة عن مجموعة من الكلاسات التي يمكن إستخدامها لإنشاء برامج تجعل المستخدمين قادرين على التواصل فيما بينهم بشكل متزامن عبر شبكة النت, لذلك تعتبر أهم كلاسات موجودة في الحزمة java.net و هي تنقسم لقسمين أساسيين:

  • كلاسات مخصصة لبناء برامج تستخدم البروتوكول UDP, مثل الكلاسات DatagramSocket و DatagramPacket.

  • كلاسات مخصصة لبناء برامج تستخدم البروتوكول TCP, مثل الكلاسات Socket و ServerSocket.

هنا قمنا بشرح الكلاسات Socket و ServerSocket.
تابع القراءة »

__________&&&______;&&&___________;&&&&________; __________&&&______;&&&___________;&&&&________;

 الكلاس URL في جافا

الكلاس URL في جافا

الكلمة URL إختصار لـ Uniform Resource Locator و هي تعني كل المعلومات المذكورة في الرابط و التي تشير إلى مصدر محدد للبيانات.

الكلاس URL مصمم بشكل عام لتجهيز روابط الملفات التي سنتعامل معها عن بعد عبر شبكة الإنترنت.


بناؤه

                  public final class URL
                  extends Object
                  implements Serializable 
                

المعلومات الأساسية في أي رابط هي: protocol://host:port/path/filename

  • protocol: نضع مكانها إسم البروتوكول المستخدم في عملية الإتصال مثل http أو https.

  • host: نضع مكانها إسم الموقع مثل harmash.com.

  • port: نضع مكانها بورت البرنامج ( أو البروتوكول ) المستخدم من قبل العميل, فمثلاً https يستخدم البورت 443.

  • path: نضع مكانها إسم المجلد الذي نريد الدخول إليه على السيرفر مثل مجلد home.

  • filename: نضع مكانها إسم الملف الذي نريد تصفحه أو تحميله إلخ.. مثل الملف index.php.


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

كونستركتورات الكلاس URL

بشكل عام عندما تنشئ كائن نوعه URL فأنت تنشئ كائن يمثل رابط.

الجدول التالي يحتوي على بعض الكونستركتورات الموجودين في الكلاس URL.

الكونستركتور مع تعريفه
public URL(String url)
throws MalformedURLException
ينشئ كائن نوعه URL من خلال النص الذي نمرره له.
النص الذي نقوم بإدخاله يمثل كافة المعلومات التي تشكل رابط.
في حال وجود أي خطأ في المعلومات المدخلة فيه يتم رمي الإستثناء MalformedURLException.
public URL(String protocol, String host, int port, String file)
throws MalformedURLException
ينشئ كائن نوعه URL مع تحديد البروتوكول + إسم الموقع + رقم البورت + إسم الملف الذي سيتم الوصول إليه من خلاله.
في حال وجود أي خطأ في المعلومات المدخلة فيه يتم رمي الإستثناء MalformedURLException.
public URL(String protocol, String host, String file)
throws MalformedURLException
ينشئ كائن نوعه URL مع تحديد البروتوكول + إسم الموقع + إسم الملف الذي سيتم الوصول إليه من خلاله.
عندما لا تقوم بتحديد رقم البورت بنفسك, يقوم باستخدام رقم البورت الإفتراضي للبروتوكول المذكور.
في حال وجود أي خطأ في المعلومات المدخلة فيه يتم رمي الإستثناء MalformedURLException.

دوال الكلاس URL

الجدول التالي يحتوي على دوال الكلاس URL.

الدالة مع تعريفها
public String getHost() ترجع نص يمثل البروتوكول + إسم الموقع الموضوعين في كائن الـ URL.
public String getAuthority() ترجع نص يمثل البروتوكول + إسم الموقع + رقم البورت (في حال كان مذكور في الرابط) الموضوعين في كائن الـ URL.
public String getProtocol() ترجع إسم البروتوكول الذي يستخدمه كائن الـ URL للإتصال بالشبكة.
public int getPort() ترجع رقم البورت الخاص بالبروتوكول الذي يستخدمه كائن الـ URL للإتصال بالشبكة.
ترجع 1- في حال عدم تحديد رقم البورت.
public int getDefaultPort() ترجع رقم البورت الإفتراضي للبروتوكول الذي يستخدمه كائن الـ URL للإتصال بالشبكة.
ترجع 1- في حال عدم وجود رقم بورت إفتراصي.
public String getPath() ترجع نص يمثل مسار الملف المراد الوصول إليه عن طريق كائن الـ URL.
ترجع نص فارغ في حال كان مسار الملف غير محدد.
public String getFile() ترجع نص يمثل مسار الملف المراد الوصول إليه عن طريق كائن الـ URL + الـ Query (في حال كان يوجد Query في الرابط).
في حال عدم وجود Query في الرابط, تعطي نفس نتيجة الدالة getPath().
ترجع نص فارغ في حال كان المسار غير محدد في الرابط.
public String getQuery() ترجع جزئية الـ Query الموضوعة في كائن الـ URL.
ترجع null في حال عدم وجود Query في كائن الـ URL.
public String getRef() ترجع جزئية الـ Anchor في كائن الـ URL.
Anchor تعني عنصر محدد موجود في صفحة الويب, و يقال له مرجع الصفحة.
لتحديد الـ Anchor في كائن الـ URL, يجب وضعه بعد إسم الملف ( الذي شير إلى صفحة محددة في الويب ) و نضع الرمز # قبله.

مثال
هذا الرابط يفتح الصفحة الأولى في المجلد الذي يحتوي على دروس جافا و يضعك مباشرةً في الفقرة الثانية.
https://harmash.com/java/java-overview.php#article_2
public String getUserInfo() ترجع معلومات المستخدم الموضوعة في كائن الـ URL في حال كانت ظاهرة فيه.
ترجع null في حال كان لا يوجد أي معلومة خاصة بالمستخدم في كائن الـ URL.

أمثلة
  • http://info@hamash.com
    هذا رابط يحتوي على إيميل شخص من موقع harmash.com, إذاً الدالة هنا ترجع info.

  • http://info:1234@hamash.com
    هذا رابط يحتوي على إيميل و كلمة مرور شخص من موقع harmash.com, إذاً الدالة هنا ترجع info:123.


ملاحظة: هذه مجرد أمثلة, كملة المرور يجب عدم إظهارها أبداً في الرابط حتى لا يتم سرقة الحساب.

public String toExternalForm() ترجع محتوى كائن URL كنص واحد نوعه String.
public String toString() ترجع محتوى كائن URL كنص واحد نوعه String.
public boolean equals(Object obj) تقارن كائن الـ URL الذي قام باستدعائها مع الكائن الذي نمرره لها كـ Argument.
إذاً تقارن الرابط الذي قام باستدعائها مع الرابط الذي نمرره لها كـ Argument.
ترجع true في حال كانا متطابقين.
public boolean sameFile(URL otherURL) تقارن كائن الـ URL الذي قام باستدعائها مع كائن الـ URL الذي نمرره لها كـ Argument.
إذاً تقارن الرابط الذي قام باستدعائها مع الرابط الذي نمرره لها كـ Argument.
ترجع true في حال كانا متطابقين.
public InputStream openStream()
throws IOException
تنشئ إتصال مباشر بين البرنامج و الملف الموجود في الموقع الذي يشير له كائن الـ URL.
في حال نجح الإتصال, ترجع كائن نوعه InputStream يتيح لك قراءة محتوى هذا الملف فقط.
في حال فشل الإتصال يتم رمي إستثناء.
public URLConnection openConnection()
throws IOException
تنشئ إتصال مباشر بين البرنامج و الملف الموجود في الموقع الذي يشير له كائن الـ URL.
في حال نجح الإتصال, ترجع كائن نوعه URLConnection يتيح لك قراءة محتوى هذا الملف أو الكتابة فيه.
في حال فشل الإتصال يتم رمي إستثناء.
public URLConnection openConnection(Proxy proxy).
throws IOException
تنشئ إتصال بين البرنامج و الملف الموجود في الموقع الذي يشير له كائن الـ URL عن طريق Proxy Server.
إذاً هنا يوجد طرف ثالث يلعب دور الوسيط بين البرنامج الذي يحاول الوصول للملف و الموقع الذي يملك الملف.
  • في حال نجح الإتصال, ترجع كائن نوعه URLConnection يتيح لك قراءة محتوى هذا الملف أو الكتابة فيه.

  • في حال كان البروتوكول المستخدم لا يعمل مع Proxy Server, يتم تجاهل Proxy Server و يتم وصل طرفي الإتصال مباشرةً مع بعضهما.

  • في حال وضعت الثابت Proxy.NO_PROXY كـ Argument, أيضاً يتم تجاهل Proxy Server و يتم وصل طرفي الإتصال مباشرةً مع بعضهما.

  • في حال حدث خطأ بسبب الملف يتم رمي الإستثناء IOException

  • في حال كان المستخدم لا يملك صلاحية لإستخدام الـ Proxy Server, يتم رمي الإستثناء SecurityException

  • في حال وضعنا null كـ Argument أو لم نحدد الـ Proxy Server بشكل صحيح, يتم رمي الإستثناء IllegalArgumentException

أمثلة شاملة


المثال الأول

في هذا المثال  قمنا بتعريف كائن نوعه URL يشير إلى رابط درس معين من موقعنا, ثم حاولنا عرض كافة المعلومات التي يمكن استخراجها من الرابط.

ملاحظة: تعمدنا عرض جميع المعلومات التي يمكن استخراجها من الرابط سواء كانت موجودة أو غير موجودة, لاحظ أن أي معلومة حاولنا عرضها و كانت غير موجودة في الرابط ستوضع القيمة null أو 1- مكانها كما ذكرنا في الجدول السابق.

Main.java
                    import java.net.URL;    // URL هنا قمنا باستدعاء الكلاس

                    public class Main {

                    public static void main(String[] args) {

                    // الآن سنحاول إجراء إتصال عبر الشبكة للوصول إلى ملف محدد
                    try
                    {
                    // يشير إلى رابط الدرس الأول في دورة جافا و بالتحديد الفقرة الثانية في الدرس url إسمه URL هنا قمنا بتعريف كائن نوعه
                    URL url = new URL("https://harmash.com:443/java/java-overview/index.php#article_2");

                    // هنا قمنا بعرض المعلومات المتوفرة و الغير متوفرة في الرابط
                    System.out.println("URL          : " + url.toString());
                    System.out.println("Protocol     : " + url.getProtocol());
                    System.out.println("Authority    : " + url.getAuthority());
                    System.out.println("Host name    : " + url.getHost());
                    System.out.println("File name    : " + url.getFile());
                    System.out.println("Path         : " + url.getPath());
                    System.out.println("Port         : " + url.getPort());
                    System.out.println("Default Port : " + url.getDefaultPort());
                    System.out.println("Reference    : " + url.getRef());
                    System.out.println("Query        : " + url.getQuery());
                    System.out.println("User Info    : " + url.getUserInfo());
                    }
                    catch( Exception e ) {
                    e.printStackTrace();
                    }

                    }

                    }
                  

سنحصل على النتيجة التالية عند التشغيل.

                    URL          : https://harmash.com:80/java/java-overview/index.php#article_2
                    Protocol     : https
                    Authority    : harmash.com:80
                    Host name    : harmash.com
                    File name    : /java/java-overview/index.php
                    Path         : /java/java-overview/index.php
                    Port         : 80
                    Default Port : 443
                    Reference    : article_2
                    Query        : null
                    User Info    : null
                  


المثال الثاني

في هذا المثال  قمنا بتعريف كائن نوعه URL يشير إلى رابط درس معين من موقعنا.
بعدها قمنا باستدعاء الدالة openStream() و التي ترجع كائن نوعه URLConnection يتيح لنا قراءة محتوى الملف الذي يشير إليه الرابط.
كائن الـ URLConnection قمنا بتخزينه في كائن نوعه InputStream حتى نستطيع قراءة محتوى الملف في البرنامج.

في الأخير قمنا بإنشاء حلقة while لقراءة محتوى الملف و تخزينه في متغير نوعه String إسمه data.

ملاحظة: هنا ستتعلم طريقة قراءة محتوى أي ملف من موقع ما مهما كان نوعه سواء صورة, فيديو ملف نصي.

Main.java
                    import java.net.URL;               // URL هنا قمنا باستدعاء الكلاس
                    import java.io.InputStream;        // InputStream هنا قمنا باستدعاء الكلاس

                    public class Main {

                    public static void main(String[] args) {

                    // قمنا بتجهيز هذا المتغير من أجل تخزين محتوى الملف فيه
                    String data = "";

                    // الآن سنحاول إجراء إتصال عبر الشبكة للوصول إلى ملف محدد و قراءة محتواه
                    try
                    {
                    // يشير إلى رابط الدرس الأول في دورة جافا url إسمه URL هنا قمنا بتعريف كائن نوعه
                    URL url = new URL("https://harmash.com/java/java-overview/index.php");

                    // is في الكائن URL هنا قمنا بتخزين الملف الذي يشير له الكائن
                    InputStream is = url.openStream();

                    // data و تخزنهم في المتغير is هنا قمنا بإنشاء حلقة تمر على جميع الأحرف الموجودة في الكائن
                    int c;
                    while ((c = is.read()) != -1)
                    {
                    data += (char)c;
                    }

                    // هنا قمنا بإغلاق الإتصال مع الملف
                    is.close();

                    // هنا قمنا بعرض محتوى الملف
                    System.out.println(data);
                    }
                    catch( Exception e ) {
                    e.printStackTrace();
                    }

                    }

                    }
                  

عند تشغيل البرنامج سيتم عرض محتوى الصفحة harmash.com/java/java-networking/, أي كود الصفحة التي يشير لها الرابط.

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

<!DOCTYPE html>
<html lang="ar">

<head>
    <meta http-equiv="content-type" content="text/html; charset=utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="description" content="دÙرة شاÙÙØ© ÙÙ Ùغة جاÙا تبدأ Ùع٠Ù٠اÙصÙر حت٠اÙإحتراÙ">
    <meta name="keywords" content="">
   
    <!-- Google Analytics -->
    <script async src="https://www.googletagmanager.com/gtag/js?id=UA-66898688-2"></script>
    <script>
    window.dataLayer = window.dataLayer || [];
...


المثال الثالث

هنا سنعيد نفس المثال الثاني من حيث الفكرة و لكننا إستخدمنا هذه المرة الـ Buffer عند قراءة محتوى الملف لتسريع عملية القراءة و بالتالي لأداء أفضل.

ملاحظة: هنا ستتعلم طريقة قراءة محتوى أي ملف نصي من موقع ما مع مراعاة أي نوع ترميز مستخدم في الملف.

المثال الثالث

Main.java
                    import java.net.URL;                       // URL هنا قمنا باستدعاء الكلاس
                    import java.io.BufferedReader;             // BufferedReader هنا قمنا باستدعاء الكلاس
                    import java.io.InputStream;                // InputStream هنا قمنا باستدعاء الكلاس
                    import java.io.InputStreamReader;          // InputStreamReader هنا قمنا باستدعاء الكلاس

                    public class Main {

                    public static void main(String[] args) {

                    // قمنا بتجهيز هذا المتغير من أجل تخزين محتوى الملف فيه
                    String data = "";

                    // الآن سنحاول إجراء إتصال عبر الشبكة للوصول إلى ملف محدد و قراءة محتواه
                    try
                    {
                    // يشير إلى رابط الدرس الأول في دورة جافا url إسمه URL هنا قمنا بتعريف كائن نوعه
                    URL url = new URL("https://harmash.com/java/java-overview/index.php");

                    // is في الكائن URL هنا قمنا بتخزين الملف الذي يشير له الكائن
                    InputStream is = url.openStream();

                    // Buffer لحل مشكلة الترميز و وضع محتوى الملف في الـ InputStreamReader إلى النوع is هنا قمنا بتحويل نوع الكائن
                    InputStreamReader isr = new InputStreamReader(is, "UTF-8");

                    // Buffer يتيح لنا قراءة محتوى الملف الموجود في الـ br الكائن
                    BufferedReader br = new BufferedReader(isr);

                    // data و تخزنهم في المتغير br هنا قمنا بإنشاء حلقة تمر على جميع الأحرف الموجودة في الكائن
                    int c;
                    while ((c = br.read()) != -1)
                    {
                    data += (char)c;
                    }

                    // هنا قمنا بإغلاق الإتصال مع الملف
                    is.close();
                    isr.close();
                    br.close();

                    // هنا قمنا بعرض محتوى الملف
                    System.out.println(data);
                    }
                    catch( Exception e ) {
                    e.printStackTrace();
                    }

                    }

                    }
                  

عند تشغيل البرنامج سيتم عرض محتوى الصفحة harmash.com/java/java-networking/, أي كود الصفحة التي يشير لها الرابط.

<!DOCTYPE html>
<html lang="ar">

<head>
    <meta http-equiv="content-type" content="text/html; charset=utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="description" content="دورة شاملة في لغة جافا تبدأ معك من الصفر حتى الإحتراف">
    <meta name="keywords" content="">
   
    <!-- Google Analytics -->
    <script async src="https://www.googletagmanager.com/gtag/js?id=UA-66898688-2"></script>
    <script>
    window.dataLayer = window.dataLayer || [];
...
__________&&&______;&&&___________;&&&&________;

 الكلاس URLConnection في جافا

مقدمة

الكلاس URLConnection عبارة عن كلاس مجرّد ( Abstract Class ) و هو يستخدم للقراءة و الكتابة في الملف الذي يشير له كائن الـ URL بالإضافة إلى أنه يمكن من خلاله معرفة و تحديد كافة المعلومات المتعلقة بإجراء الإتصال مع الملف.
فمثلاً يتيح لنا معرفة آخر مرة تم فيها تحديث الملف, تاريخ صلاحية الملف, إسم الكلاس المناسب لإرسال المعلومات منه و استقبالها فيه إلخ..


بناؤه

                  public abstract class URLConnection
                  extends Object
                

حقول الملف ( File Header Fields )

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

جميع هذه المعلومات مع بعضها تسمى حقول الملف.
سنتعرف لاحقاً على دوال مصممة خصيصياً لإضافة حقول جديدة تحدد طريقة تعامل البرنامج مع الملف.


التعامل مع الملفات عن بعد

للوصول إلى الملفات عن بعد سواء لقراءة محتواها أو التعديل عليها, عليك اتباع الخطوات التالية:

  1. إنشاء كائن من الكلاس URL يمثل رابط لملف موجود في موقع معين.

  2. إستدعاء الدالة openConnection() و التي ترجع كائن نوعه URLConnection يسمح لنا بالتعامل مع هذا الملف.

  3. معرفة البروتوكول المستخدم في إجراء عملية الإتصال.

  4. تحويل كائن الـ URLConnection إلى كائن من إحدى الكلاسات التي ترث منه يكون مخصص للتعامل مع البروتوكول المستخدم في عملية الإتصال.



تحويل نوع كائن الـ URLConnection

الكلاس URLConnection عبارة عن كلاس مجرّد تم تصميمه لإنشاء إتصال مع الملف الذي يشير إليه كائن الـ URL مهما كان البروتوكول المستخدم في عملية الإتصال.
في حال أردت أن تتعامل مع هذا الملف, سيكون عليك تحويل نوع كائن الـ URLConnection لنوع يلائم البروتوكول المستخدم لإجراء هذا الإتصال.

إذاً نوع البروتوكول المستخدم لإجراء الإتصال هو الذي يحدد النوع الذي يجب تحويل كائن الـ URLConnection إليه, أمثلة:

  • في حال كان البروتوكول http هو المستخدم في إجراء الإتصال, سيكون عليك تحويل نوع الكائن إلى النوع HttpURLConnection.

  • في حال كان البروتوكول https هو المستخدم في إجراء الإتصال, سيكون عليك تحويل نوع الكائن إلى النوع HttpsURLConnection.

  • في حال كان البروتوكول ftp هو المستخدم في إجراء الإتصال, سيكون عليك تحويل نوع الكائن إلى النوع FtpURLConnection.

  • في حال كان البروتوكول jar هو المستخدم في إجراء الإتصال, سيكون عليك تحويل نوع الكائن إلى النوع JarURLConnection إلخ..

كونستركتورات الكلاس URLConnection

الكلاس URLConnection يملك الكونستركتور التالي فقط.

الكونستركتور مع تعريفه
protected URLConnection(URL url) ينشئ كائن نوعه URLConnection يمثل كافة المعلومات المتعلقة بالملف الذي يشير له كائن الـ URL, أي يمثل صلة الوصل بين البرنامج و الملف الذي يشير له كائن الـ URLكـ Argument.
بما أنه معرف كـ protected فهذا يعني أنه لا يمكن إستخدامه إلا في حال قمنا بإنشاء كلاس يرث منه و يفعل Override للدالة connect() الموجودة فيه.

ملاحظة: لست بحاجة إلى إستخدام هذا الكونستركتور لأنك لن تقوم ببناء كلاس خاص للتعامل مع الشبكات.

دوال الكلاس URLConnection

الجدول التالي يحتوي على دوال الكلاس URLConnection.

الدالة مع تعريفها
public String getContent() ترجع كائن يمثل إسم الكلاس الذي يجب استخدامه للتعامل مع محتوى الملف الذي يشير إليه كائن الـ URLConnection.
في حال حدث خطأ بسبب الملف يتم رمي الإستثناء IOException
و في حال كان البروتوكول المستخدم غير ملائم للتعامل مع الملف, يتم رمي الإستثناء UnknownServiceException.
public String getContentEncoding() ترجع نص يمثل قيمة الحقل content-encoding في حال تم تحديدها في كائن الـ URLConnection.
و ترجع null في حال كانت قيمته غير معروفة.

معلومة: هذا الحقل يحدد الطريقة التي سيتم فيها تجزيء الملف عند إرساله إلى الجهة المطلوبة, و هو عبارة عن إسم الترميز المستخدم من قبل البروتوكول المعنمد عليه للتعامل مع هذا الملف.
public long getContentLengthLong() ترجع نص يمثل قيمة الحقل content-encoding في حال تم تحديدها في كائن الـ URLConnection.
و ترجع 1- في حال كانت غير محددة.

معلومة: هذا الحقل يمثل حجم البيانات الأساسية المتعلقة بهذا الإتصال في حال قمت بتحديده, أي عدد الأحرف المتوقع إستقبالها.
طبعاً لا ضرورة لتحديدها لأنه سيقوم بذلك بشكل تلقائي في حال لم تفعل ذلك.
public String getContentType() ترجع نص يمثل قيمة الحقل Content-Typeو هو عبارة نوع الملف الذي يشير إليه كائن الـ URLConnection.
و ترجع null في حال كان النوع غير معروف.
public int getDate() ترجع قيمة الحقل date, و هو عبارة عن رقم يمثل التاريخ و الوقت الذي قام فيه السيرفر بإرسال الملف الذي يشير إليه كائن الـ URLConnection.
الرقم الذي ترجعه عبارة عن عدد الـ milliseconds الموجودة إعتباراً من التاريخ 1/1/1970 00:00:00 GMT.
ترجع 0 في حال كان الوقت غير معروف.
public int getLastModified() ترجع قيمة الحقل last-modified في حال كانت مذكورة في الملف الذي يشير إليه كائن الـ URLConnection, و هو عبارة عن رقم يمثل تاريخ آخر مرة تم فيها تعديل هذا الملف.
الرقم الذي ترجعه عبارة عن عدد الـ milliseconds الموجودة إعتباراً من التاريخ 1/1/1970 00:00:00 GMT.
ترجع 0 في حال كان الوقت غير معروف.
public long getExpiration() ترجع قيمة الحقل expires في حال كانت مذكورة في الملف الذي يشير إليه كائن الـ URLConnection, و هو عبارة عن رقم يمثل تاريخ صلاحية الملف.
الرقم الذي ترجعه عبارة عن عدد الـ milliseconds الموجودة إعتباراً من التاريخ 1/1/1970 00:00:00 GMT.
ترجع 0 في حال كانت غير مذكورة في الملف.

معلومة: في العادة أي ملف نطلبه من موقع ما يتم إعطائه تاريخ صلاحية, هذا التاريخ يضمن لك أن زوار الموقع سيحصلون دائماً على آخر تحديث فعلته لهذا الملف.
فمثلاً, عندما تقوم بفتح أي صفحة من النت, يقوم المتصفح بحفظ هذه الصفحة على القرص الصلب, و في حال طلبت نفس الصفحة من جديد حتى و لو كان بعد سنة, سيقوم المتصفح أولاً بالبحث في الصفحات المخزنة فيه سابقاً, و في حال وجد أن هذه الصفحة أصلاً موجودة عنده, يعرضها لك بسرعة بدل أن تنتظره ليحملها لك من النت. إذاً هنا المشكلة تكون أنك ستحصل دائماً على النسخة القديمة للصفحة.
الحل لهذه المشكلة كان بإعطاء الملفات تاريخ صلاحية. فمثلاً تجعل الصفحة صالحة لمدة يوم واحد, عندها في إذا قام المستخدم بطلب نفس الصفحة التي طلبها في اليوم السابق, سيجد المتصفح أن الصفحة التي يمكلها إنتهت صلاحيتها و بالتالي سيطلبها له من السيرفر من جديد و عندها سيحصل على آخر تحديث تم إجراءه على الصفحة.
إذاً هذا الحقل مهم جداً و يجب ذكره في جميع الملفات التي ترفع في النت.
public long getIfModifiedSince() ترجع قيمة الحقل ifModifiedSince في حال كانت مذكورة في الملف, و هو عبارة عن رقم يمثل تاريخ آخر مرة علم فيها المستخدم أن الملف قد تم تحديثه.
الرقم الذي ترجعه عبارة عن عدد الـ milliseconds الموجودة إعتباراً من التاريخ 1/1/1970 00:00:00 GMT.
ترجع 0 في حال كان الوقت غير معروف.

معلومة: هنا مثلاً يتم تصميم البرنامج لمقارنة آخر مرة قام فيها هو بتعديل محتوى الملف مع آخر مرة قام فيها أي أحد بتعديل محتوى هذا الملف.
في حال وجد نفسه هو آخر من قام بتحديث الملف, يعلم عندها أن المعلومات المذكورة فيه لم تتغير و بالتالي يمكنه إستعمال النسخة التي يملكها من هذا الملف بدل تحميلها من النت من جديد.
لكن في حال وجد أن هذا الملف قد تم تحديثه من قبل شخص آخر, عندها سيقوم بتحميل النسخة الموجودة في السيرفر من جديد و تجاهل النسخة التي يملكها.
public void setDoInput(boolean input) تحدد قيمة الحقل doinput في كائن الـ URLConnection.
إذا قمت بتمرير القيمة true لها فهذا يعني أنك تنوي استخدام كائن الـ URLConnection لقراءة محتوى الملف.
ترمي الإستثناء IllegalStateException في حال كان الكائن متصلاً بالملف قبل استدعائها.
public boolean getDoInput() ترجع قيمة الحقل doinput في حال قمنا بتحديدها في كائن الـ URLConnection.
public void setDoOutput(boolean output) تحدد قيمة الحقل doinput في كائن الـ URLConnection.
إذا قمت بتمرير القيمة true لها فهذا يعني أنك تنوي استخدام كائن الـ URLConnection للكتابة في الملف.
ترمي الإستثناء IllegalStateException في حال كان الكائن متصلاً بالملف قبل استدعائها.
public boolean getDoOutput() ترجع قيمة الحقل dooutput في حال قمنا بتحديدها في كائن الـ URLConnection.
public void setUseCaches(boolean usecaches) تحدد قيمة الحقل usecaches في كائن الـ URLConnection.
إذا قمت بتمرير القيمة true لها فهذا يعني أنك تريد الإحتفاظ بنسخة من الملف في القرص الصلب.
ترمي الإستثناء IllegalStateException في حال كان الكائن متصلاً بالملف قبل استدعائها.
public boolean getUseCaches() ترجع قيمة الحقل usecaches في حال قمنا بتحديدها في كائن الـ URLConnection.
public InputStream getInputStream() ترجع كائن نوعه InputStream يستخدم للقراءة من الملف.
في حال حدث خطأ بسبب الملف يتم رمي الإستثناء IOException.
و في حال كان البروتوكول المستخدم غير ملائم للتعامل مع الملف, يتم رمي الإستثناء UnknownServiceException.
public OutputStream getOutputStream() ترجع كائن نوعه OutputStream يستخدم للكتابة في الملف.
في حال حدث خطأ بسبب الملف يتم رمي الإستثناء IOException.
و في حال كان البروتوكول المستخدم غير ملائم للتعامل مع الملف, يتم رمي الإستثناء UnknownServiceException.
public String getHeaderField(String name) ترجع قيمة أي حقل نمرر إسمه لها كنص.
public Map<String,List<String>> getHeaderFields() ترجع كائن نوعه Map يحتوي على جميع أسماء و قيم الحقول الموجودة في Header كائن الـ Connection بشكل key / value.

معلومة: هذه الدالة ترجع لك جميع معلومات الإتصال دفعة واحدة كجدول, و بالتالي تسهل عليك جلب جميع المعلومات المتعلقة بعملية الإتصال مع الملف.
public URL getURL() ترجع كائن الـ URL المستخدم من قبل كائن الـ Connection.

أمثلة شاملة


المثال الأول

في هذا المثال  قمنا بتعريف كائن نوعه URL يشير إلى صفحتنا في فيسبوك https://www.facebook.com/harmashcom.
بعدها قمنا باستدعاء الدالة openConnection() و التي ترجع كائن نوعه URLConnection يتيح لنا تجهيز معلومات الإتصال.
بعدها قمنا باستدعاء الدالة getHeaderFields() و التي ترجع كائن نوعه Map يمثل جميع الحقول الموجودة في كائن الـ URLConnection.
بعدها قمنا بإنشاء حلقة For Each تعرض لنا في كل دورة معلومات حقل واحد, أي Entry واحد.

ملاحظة: الإنترفيس Map يملك Inner Interface إسمه Entry نستخدمه للتعامل مع العناصر التي يملكها كائن الـ Map.
بما أن الإنترفيس Entry معرف بداخل الإنترفيس Map يمكننا إستدعاءه هكذا Map.Entry.

Main.java
                    import java.net.URL;                  // URL هنا قمنا باستدعاء الكلاس
                    import java.net.URLConnection;        // URLConnection هنا قمنا باستدعاء الكلاس
                    import java.util.Map;                 // Map هنا قمنا باستدعاء الكلاس
                    import java.util.List;                // List هنا قمنا باستدعاء الكلاس

                    public class Main {

                    public static void main(String[] args) {

                    // الآن سنحاول إجراء إتصال عبر الشبكة للوصول إلى ملف محدد و عرض كافة معلومات الإتصال المتوفرة
                    try
                    {
                    // يشير إلى رابط موقعنا في فيسبوك url إسمه URL هنا قمنا بتعريف كائن نوعه
                    URL url = new URL("https://www.facebook.com/harmashcom");

                    // connection إسمه URLConnection هنا قمنا بتعريف كائن نوعه
                    URLConnection connection = url.openConnection();

                    // map في الكائن getHeaderFields() هنا قمنا بتخزين أسماء و قيم الحقول التي سترجعها الدالة
                    Map<String, List<String>> map = connection.getHeaderFields();

                    // و بعدها سيتم عرضهم entry بجلب إسم حقل و قيمته و وضعهم في الكائن entrySet() هنا في كل دورة تقوم الدالة
                    for (Map.Entry<String, List<String>> entry : map.entrySet())
                    {
                    System.out.println(entry.getKey() +" : "+ entry.getValue());
                    }

                    }
                    catch( Exception e ) {
                    System.out.println(e.getMessage());
                    }

                    }

                    }
                  

سنحصل على النتيجة التالية عند التشغيل.

                    null : [HTTP/1.1 200 OK]
                    Expires : [Sat, 01 Jan 2000 00:00:00 GMT]
                    X-XSS-Protection : [0]
                    Set-Cookie : [fr=0R31HwmcA2qNYUaC..BX7LPo.cm.AAA.0.0.BX7LPo.AWWl-1aI; expires=Wed, 27-Dec-2016 06:25:44 GMT;
                    Max-Age=7776000; path=/; domain=.facebook.com; httponly]
                    Connection : [keep-alive]
                    public-key-pins-report-only : [max-age=500; pin-sha256="WoiWRyIOVNa9ihaBciRSC7XHjliasfasTH32Us5sud4PB18="; pin-sha256="r/mIkG3eEpVdm+u/ko/cwxzOMo1bJ4TyHIlByibiA5E=";
                    pin-sha256="q4PO2G4cbkZhZ82+JgmRUyGMoAeozA+BSXVXQWA8XWQ="; report-uri="http://reports.fb.com/hpkp/"]
                    Cache-Control : [private, no-cache, no-store, must-revalidate]
                    X-Content-Type-Options : [nosniff]
                    Pragma : [no-cache]
                    X-FB-Debug : [k1P7SDLc7cblje32GG3ydHZ8awX/he/64uiyasdf34f4BF4HYuiXpPSGYahNfpx+7F+vnKq3z4IbNvEEXYjgg==]
                    X-Frame-Options : [DENY]
                    Strict-Transport-Security : [max-age=15552000; preload]
                    Vary : [Accept-Encoding]
                    Date : [Thu, 29 Sep 2016 06:25:44 GMT]
                    Transfer-Encoding : [chunked]
                    P3P : [CP="Facebook does not have a P3P policy. Learn why here: http://fb.me/p3p"]
                    Content-Type : [text/html]
                  


المثال الثاني

في هذا المثال  قمنا بتعريف برنامجين, الأول هو برنامج صغير جداً مكتوب بلغة PHP موجود على السيرفر أي في موقع ما, و الثاني عبارة عن برنامج مكتوب بلغة جافا. أنت الآن مسؤول عن كود الجافا فقط, لأنك تدرس لغة جافا و ليس لغة PHP التي تستعمل في بناء المواقع.

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

  • من السطر 24 إلى السطر 41, قمنا بإرسال البيانات التي أدخلها المستخدم إلى الملف الموجود في السيرفر.

  • من السطر 44 إلى السطر 60, قمنا باستقبال كامل البيانات التي أصبحت موجودة في الملف و من ثم عرضناها.

هذا ملف PHP و هو عبارة عن صفحة ويب موجودة على السيرفر, نمرر لها إيميل و كلمة مرور عند استدعائها, فتعرضهم في الصفحة عندما تفتح.
إنتبه: لم نشرح هذا الكود لأنك الآن تدرس لغة جافا و ليس لغة PHP و لست بحاجة إلى فهمه أيضاً.

test.php
                    <?php
                    if(isset($_GET['email']) &↦ isset($_GET['password']))
                    {
                    $email = $_GET['email'];
                    $password = $_GET['password'];
                    echo "your email is '$email' and your password is '$password'";
                    }
                    ?>
                  

Main.java
                    import java.io.BufferedReader;              // BufferedReader هنا قمنا باستدعاء الكلاس
                    import java.io.InputStreamReader;           // InputStreamReader هنا قمنا باستدعاء الكلاس
                    import java.net.HttpURLConnection;          // HttpURLConnection هنا قمنا باستدعاء الكلاس
                    import java.net.URL;                        // URL هنا قمنا باستدعاء الكلاس
                    import java.util.Scanner;                   // Scanner هنا قمنا باستدعاء الكلاس

                    public class Main {

                    public static void main(String[] args) {

                    // سنستخدمه لإستقبال بيانات في البرنامج من لوحة مفاتيح المستخدم input إسمه Scanner هنا قمنا بإنشاء كائن من الكلاس
                    Scanner input = new Scanner(System.in);

                    // لتخزين البيانات التي سيطلب البرنامج من المستخدم إدخالها password و email هنا قمنا بتجهيز المتغيرات
                    String email;
                    String password;

                    // الآن سنحاول إجراء إتصال عبر الشبكة للوصول إلى ملف محدد و إدخال بيانات فيه ثم إسترجاع جميع البيانات التي فيه
                    try
                    {
                    // email هنا سيطلب من المستخدم إدخال بريده الإلكتروني و بعدها سيتم تخزينه في المتغير
                    System.out.print("Enter you email: ");
                    email = input.next();

                    // password هنا سيطلب من المستخدم إدخال كلمة المرور و بعدها سيتم تخزينها في المتغير
                    System.out.print("Enter you password: ");
                    password = input.next();

                    // و يمرر له المعلومات التي أدخلها المتسخدم test.php هنا قمنا بإنشاء رابط يوصلنا إلى الملف
                    String urlLink = "http://localhost/java/test.php?email=" +email+ "&password=" +password;

                    // urlLink يشير إلى الرابط url إسمه URL هنا قمنا بتعريف كائن نوعه
                    URL url = new URL(urlLink);

                    // conn و وضعناه في الكائن HttpURLConnection إلى النوع openConnection() الذي سترجعه الدالة URLConnection هنا قمنا بتحويل كائن الـ
                    HttpURLConnection conn = (HttpURLConnection)url.openConnection();

                    // هنا حددنا الطريقة التي سيتم فيها إرسال البيانات إلى السيرفر
                    conn.setRequestMethod("GET");

                    // و الذي يسمح لنا بقراءة محتوى الملف br من السيرفر في الكائن getInputStream() هنا قمنا بتخزين الملف الذي سترجعه الدالة
                    BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));

                    // لجلب البيانات الموجودة بشكل مؤقت line لحفظ البيانات التي أرجعها السيرفر, و المتغير data هنا قمنا بتجهيز المتغير
                    String data = "";
                    String line;

                    // data غير فارغ سيتم قراءة محتوياته سطرا سطرا و تخزينهم في المتغير br هنا قلنا أنه طالما أن الملف الذي يشير له الكائن
                    while((line = br.readLine()) != null)
                    {
                    data += line;
                    }

                    br.close();

                    // data هنا قمنا بعرض محتوى الملف الذي أرجعه السيرفر و الذي قمنا بتخزينه في المتغير
                    System.out.println("\nServer Response");
                    System.out.println(data);

                    }
                    catch( Exception e ) {
                    System.out.println(e.getMessage());
                    }

                    }

                    }
                  

سنحصل على النتيجة التالية عند التشغيل إذا قمنا بإدخال نفس المعلومات التي أدخلناها عند تشغيل البرنامج.
قمنا بتعليم البيانات التي إنتظرنا البرنامج لإدخالها من لوحة المفاتيح باللون الأزرق.
و قمنا بتعليم البيانات التي حصلنا عليها من السيرفر باللون الأخضر.

Enter you email: contact@harmash.com
Enter you password: 1234

Server Response
your email is 'contact@harmash.com' and your password is '1234'
__________&&&______;&&&___________;&&&&________;

 الكلاس InetAddress في جافا

مقدمة

الكلاس InetAddress مصمم لتحليل عنوان الجهاز أو الموقع الذي نحاول الإتصال به عن بعد عبر شبكة النت.


بناؤه

                  public class InetAddress
                  extends Object
                  implements Serializable
                

مصطلحات تقنية

  • :IP Address تعني عنوان الجهاز أو الموقع على الشبكة. فمثلاً عنوان harmash.com هو 108.179.232.152.

  • :Host Name تعني أي إسم الجهاز أو الموقع على الشبكة. فمثلاً العنوان 108.179.232.152 يشير إلى الموقع harmash.com.

  • :Local Host تعني عنوان الجهاز على الشبكة المحلية. في العادة يكون يشبه هذا العنوان 192.168.1.105.

  • :Loopback Address تعني العنوان الذس يستخدمه الجهاز لفحص كرت الشبكة. و هو 127.0.0.1.

  • :Multicast Address تعني العنوان الذس يستخدمه الجهاز لإرسال البيانات إلى عدة أجهزة موجودة معه على الشبكة المحلية. مثل العنوان 224.0.0.1.

دوال الكلاس InetAddress

الجدول التالي يحتوي على دوال الكلاس InetAddress.


أخطاء محتملة

بعض الأخطاء التي قد تظهر لك عند استخدام دوال الكلاس InetAddress.

  • ترمي الإستثناء UnknownHostException في حال لم يتم معرفة الـ IP Address للـ Host Name الذي قمنا بتمريره.

  • ترمي الإستثناء SecurityException في حال كان البرنامج ممنوع من الإتصال بالشبكة.


الدالة مع تعريفها
public static InetAddress getByName(String host) نعطيها نص عبارة عن Host Name, مثل www.harmash.com فترجعه ككائن نوعه InetAddress.
public static InetAddress getByAddress(byte[] addr) نعطيها مصفوفة نوعها byte تمثل IP Address فترجعه ككائن نوعه InetAddress.
public static InetAddress getByAddress(String host, byte[] addr) نعطيها مصفوفة نوعها byte تمثل IP Address و Host Name فترجعه ككائن نوعه InetAddress.
public static InetAddress[] getAllByName(String host) ترجع مصفوفة نوعها InetAddress تحتوي على جميع العناوين التي يملكها الموقع الذي نمررها له كـ Argument.
ملاحظة: المواقع الضخمة مثل google و facebook, يملكون أكثر من عنوان.
public static InetAddress getLocalHost() ترجع كائن نوعه InetAddress عبارة عن إسم و عنوان الجهاز الذي قام باستدعاءها على الشبكة المحلية.
public static InetAddress getLoopbackAddress() ترجع كائن نوعه InetAddress عبارة عن العنوان الذي يستخدمه الجهاز لفحص كرت الشبكة.
public String getHostAddress() ترجع الـ Host Name الذي يشير له كائن الـ InetAddress كنص.
public byte[] getAddress() ترجع عنوان الموقع الذي يشير له كائن الـ InetAddress الذي قام باستدعائها كمصفوفة نوعها byte.
public String getHostName() ترجع الـ IP Address الذي يشير له كائن الـ InetAddress كنص.
public boolean isAnyLocalAddress() ترجع true في حال كان كائن الـ InetAddress الذي قام باستدعائها عبارة عن Local Address.
public boolean isLoopbackAddress() ترجع true في حال كان كائن الـ InetAddress الذي قام باستدعائها عبارة عن Loopback Address.
public boolean isMulticastAddress() ترجع true في حال كان كائن الـ InetAddress الذي قام باستدعائها عبارة عن Multicast Address.
public String toString() ترجع الـ Host Name الذي يشير له كائن الـ InetAddress.
public boolean equals(Object obj) تقارن كائن الـ InetAddress الذي قام باستدعائها مع الكائن الذي نمرره لها كـ Argument.
ترجع true في حال كانا متطابقين.
public int hashCode() ترجع الـ Hash Code لكائن الـ InetAddress الذي قام باستدعائها.

مثال شامل

في المثال التالي قمنا بإنشاء كائن نوعه InetAddress إسمه IP يشير إلى موقع harmash.com.
بعدها قمنا بتحليل إسم هذا الموقع لمعرفة كافة المعلومات المتعلقة بعنوانه.


Main.java
                    import java.net.InetAddress;    // InetAddress هنا قمنا باستدعاء الكلاس

                    public class Main {

                    public static void main(String[] args) {

                    // الآن سنحاول إجراء إتصال عبر الشبكة للوصول إلى موقع محدد
                    try
                    {
                    // harmash.com يشير إلى موقع ip إسمه InetAddress لتعريف كائن نوعه getByName() هنا قمنا باستدعاء الدالة
                    InetAddress ip = InetAddress.getByName("www.harmash.com");

                    // harmash.com هنا قمنا بعرض إسم و عنوان موقع
                    System.out.println("Host name  : " + ip.getHostName());
                    System.out.println("IP address : " + ip.getHostAddress());

                    // Loopback Address و الـ Local Host هنا قمنا بعرض
                    System.out.println("Local Host : " + InetAddress.getLocalHost());
                    System.out.println("Loopback   : " + InetAddress.getLoopbackAddress());
                    }
                    catch( Exception e ) {
                    System.out.println(e.getMessage());
                    }

                    }

                    }
                  

ستحصل على نتيجة تشبه النتيجة التالية عند التشغيل.

                    Host name  : www.harmash.com
                    IP address : 108.179.232.152
                    Local Host : Mhamad-PC/192.168.88.1
                    Loopback   : localhost/127.0.0.1
                  
__________&&&______;&&&___________;&&&&________;

 الكلاس Socket و الكلاس ServerSocket في جافا

مقدمة

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

للتعامل مع الـ Socket جافا توفر لنا مجموعة من الكلاسات التي يمكننا إستخدامها لإنشاء برامج تجعل المستخدمين قادرين على التواصل فيما بينهم بشكل متزامن عبر شبكة النت كما في الصورة التالية.


في هذا الدرس سنشرح الكلاسات Socket و ServerSocket التي يمكن استخدامها لمشاركة البيانات بين أي أجهزة كمبيوتر متصلة بشبكة النت.


مصطلحات تقنية

  • Server: تعني خادم أو سيرفر في العربية, و هو عبارة عن كمبيوتر له مواصفات عالية, يقدم خدمات للـ Clients.

  • Client: تعني عميل أو مستخدم عادي في العربية, و هو عبارة عن أي كمبيوتر عادي يحاول أن يتواصل مع الـ Server للحصول على خدمة منه.

  • Remote App: تعني إنشاء تطبيق يستخدم للتحكم في جهاز ما عن بعد و كأن الشخص يجلس أمامه.

الكلاس Socket

الكلاس Socket يستخدم لإنشاء إتصال بين برنامج المستخدم و البرنامج الموجود في السيرفر.


بناؤه

                  public class Socket
                  extends Object
                  implements Closeable 
                


كونستركتورات الكلاس Socket

الجدول التالي يحتوي على بعض الكونستركتورات الموجودة في الكلاس Socket.

الكونستركتور مع تعريفه
public Socket(String host, int port) ينشئ كائن نوعه Socket يجعل برنامج المستخدم متصلاً مع السيرفر بشكل متزامن.

باراميترات
  • host هو نص يمثل عنوان السيرفر الذي سنحاول الإتصال به من برنامج المستخدم.

  • port هو رقم يمثل البورت الذي سيتم حجزه خصيصاً للبرنامج في جهاز المستخدم.

public Socket(InetAddress address, int port) ينشئ كائن نوعه Socket يجعل برنامج المستخدم متصلاً مع السيرفر بشكل متزامن.

باراميترات
  • host هو كائن نوعه InetAddress يمثل عنوان السيرفر الذي سنحاول الإتصال به من برنامج المستخدم.

  • port هو رقم يمثل البورت الذي سيتم حجزه خصيصاً للبرنامج في جهاز المستخدم.

public Socket(String host, int port, InetAddress localAddr, int localPort) ينشئ كائن نوعه Socket يجعل برنامج المستخدم متصلاً مع السيرفر بشكل متزامن.
يستخدم في حالة الـ Remote App.

باراميترات
  • host هو نص يمثل عنوان السيرفر الذي سنحاول الإتصال به من برنامج المستخدم.

  • port هو رقم يمثل البورت المحجوز في السيرفر خصيصاً للبرنامج الذي سنحاول الإتصال به من برنامج المستخدم.

  • localAddr هو كائن نوعه InetAddress يمثل عنوان كمبيوتر المستخدم الذي يحاول الإتصال بالسيرفر.

  • localPort هو رقم يمثل البورت الذي سيتم حجزه خصيصاً للبرنامج في جهاز المستخدم.

public Socket(InetAddress address, int port, InetAddress localAddr, int localPort) ينشئ كائن نوعه Socket يجعل برنامج المستخدم متصلاً مع السيرفر بشكل متزامن.
يستخدم في حالة الـ Remote App.

باراميترات
  • address هو كائن نوعه InetAddress يمثل عنوان السيرفر الذي سنحاول الإتصال به من برنامج المستخدم.

  • port هو رقم يمثل البورت المحجوز في السيرفر خصيصاً للبرنامج الذي سنحاول الإتصال به من برنامج المستخدم.

  • localAddr هو كائن نوعه InetAddress يمثل عنوان كمبيوتر المستخدم الذي يحاول الإتصال بالسيرفر.

  • localPort هو رقم يمثل البورت الذي سيتم حجزه خصيصاً للبرنامج في جهاز المستخدم.

public Socket() ينشئ كائن نوعه Socket لكنه لا يجعل برنامج المستخدم متصلاً مع السيرفر.
هنا ستضطر أن تستدعي الدالة connect() بعده حتى تجعل المستخدم يتصل بالسيرفر.

دوال الكلاس Socket

الجدول التالي يحتوي على بعض دوال الكلاس Socket.

الدالة مع تعريفها
public void connect(SocketAddress host, int timeout) تحتاج هذه الدالة فقط في حال أنشأت كائن الـ Socket بواسطة الكونستركتور الذي لا يأخذ أي Argument لتبدأ الإتصال مع السيرفر.
public InetAddress getInetAddress() ترجع كائن نوعه InetAddress يمثل عنوان السيرفر الذي هو على اتصال مع البرنامج من خلال كائن الـ Socket.
ترجع null في حال كائن كائن الـ Socket غير متصل بالسيرفر.
public int getPort() ترجع رقم البورت الذي يستخدمه كائن الـ Socket في الكمبيوتر الآخر للتحكم به عن بعد.
ترجع 0 في حال كان كائن الـ Socket مغلق أو لم يبدأ عملية الإتصال بعد.
public int getLocalPort() ترجع رقم البورت الذي يستخدمه كائن الـ Socket الذي قام باستدعائها للإتصال مع السيرفر.
ترجع 1- في حال كان كائن الـ Socket مغلق أو لم يبدأ عملية الإتصال بعد.
public SocketAddress getRemoteSocketAddress() ترجع كائن نوعه SocketAddress يمثل عنوان الكمبيوتر الذي نتحكم به عن بعد.
ترجع null في حال كائن كائن الـ Socket غير متصل بالسيرفر.
public InputStream getInputStream() ترجع كائن نوعه InputStream يستخدم للقراءة من الـ Socket.
ترمي الإستثناء IOException في حال حدث خطأ عند نقل البيانات.
public OutputStream getOutputStream() ترجع كائن نوعه OutputStream يستخدم للكتابة في الـ Socket.
ترمي الإستثناء IOException في حال حدث خطأ عند نقل البيانات.
public void close() تغلق الإتصال مع السيرفر, و عندها لن يعود باستطاعتك إستخدام نفس كائن الـ Socket للإتصال بالسيرفر من جديد.

في حال حدث خطأ عند التعامل مع الـ Socket يتم رمي الإستثناء IOException
و في حال كائن الـ Socket الذي قام باستدعاءها معلق ترمي الخطأ SocketException.

الكلاس ServerSocket

الكلاس ServerSocket يستخدم لفتح بورت في السيرفر و تلقي أي إتصال من قبل أي مستخدم عادي.


بناؤه

                  public class ServerSocket
                  extends Object
                  implements Closeable
                


كونستركتورات الكلاس ServerSocket

الجدول التالي يحتوي على جميع الكونستركتورات الموجودة في الكلاس ServerSocket.

الكونستركتور مع تعريفه
public ServerSocket() ينشئ كائن نوعه ServerSocket ليس جاهزاً بعد لتلقي أي إتصال.
هنا ستضطر أن تستدعي الدالة accept() بعده حتى تجعل العملاء قادرين على الإتصال بالسيرفر.
public ServerSocket(int port) ينشئ كائن نوعه ServerSocket جاهز لتلقي إتصال من أي عميل على البورت الذي نمرره له كـ Argument.
في حال قمت بتمرير القيمة 0 كـ Argument فهذا يعني أن السيرفر سيختار أي رقم بورت متوفر عنده.
public ServerSocket(int port, int backlog) ينشئ كائن نوعه ServerSocket جاهز لتلقي إتصال مع عدد محدد من العملاء في نفس الوقت و على بورت محدد.

باراميترات
  • port هو رقم البورت الذي سيتم تلقي إتصلات العملاء من خلاله.

  • backlog هو رقم يمثل عدد العملاء الأقصى الذي يمكنهم الإتصال مع السيرفر في نفس الوقت.

public ServerSocket(int port, int backlog, InetAddress bindAddress) ينشئ كائن نوعه ServerSocket جاهز لتلقي إتصال مع عدد محدد من العملاء في نفس الوقت و على بورت محدد و على عنوان واحد.
إذاً يستخدم هذا الكونستركتور في حال كان السيرفر يملك أكثر من عنوان, لكنك تريد الإتصال مع العملاء من عنوان واحد.

باراميترات
  • port هو رقم البورت الذي سيتم تلقي إتصلات العملاء من خلاله.

  • backlog هو رقم يمثل عدد العملاء الأقصى الذي يمكنهم الإتصال مع السيرفر في نفس الوقت.

  • bindAddress هو كائن نوعه InetAddress يمثل عنوان السيرفر المخصص للتواصل مع العملاء.



دوال الكلاس Socket

الجدول التالي يحتوي على بعض دوال الكلاس Socket.

الدالة مع تعريفها
public Socket accept() تحتاج هذه الدالة فقط في حال أنشأت كائن الـ ServerSocket بواسطة الكونستركتور الذي لا يأخذ أي Argument لتجعل السيرفر يقبل الإتصال مع العملاء.

ترمي الإستثناء SocketException في حال حدث خطأ سببه البروتوكول المستخدم في عملية الإتصال.
ترمي الإستثناء SocketTimeoutException في حال قمنا باستدعائها قبل استدعاء الدالة accept().
ترمي الإستثناء IllegalArgumentException في حال وضعنا قيمة الباراميتر size أصغر أو تساوي صفر.
public void bind(SocketAddress endpoint) في حال أنشأت كائن الـ ServerSocket بواسطة الكونستركتور الذي لا يأخذ أي Argument, و كان السيرفر يملك أكثر من عنوان, يمكنك استدعاء هذه الدالة قبل استدعاء accept(), لتحديد العنوان الذي سيتلقى إتصالات العملاء.

مكان الباراميتر endpoint عليك تمرير كائن من إحدى الكلاسات التي ترث من الكلاس SocketAddress.
في حال قمت بتمرير القيمة null مكانه سيتلقى السيرفر إتصالات العملاء على أي عنوان يملكه - في حال كان يملك أكثر من عنوان - و على أي بورت متوفر.

ترمي الإستثناء IOException في حال فشلت عملية الإتصال أو في حال كان الإتصال مفتوح أصلاً.
ترمي الإستثناء IllegalArgumentException في حال كان الكائن الذي قمنا بتمريره لها لا يتناسب مع البروتوكول المستخدم من قبل كائن الـ ServerSocket الذي قام باستدعائها.
public void bind(SocketAddress endpoint, int backlog) في حال أنشأت كائن الـ ServerSocket بواسطة الكونستركتور الذي لا يأخذ أي Argument, و كان السيرفر يملك أكثر من عنوان, يمكنك استدعاء هذه الدالة قبل استدعاء accept(), لتحديد العنوان الذي سيتلقى إتصالات العملاء.

باراميترات
  • endpoint هو كائن من إحدى الكلاسات التي ترث من الكلاس SocketAddress يمثل عنوان السيرفر الذي سيتلقى إتصال العملاء.
    في حال قمت بتمرير القيمة null مكانه سيتلقى السيرفر إتصالات العملاء على أي عنوان يملكه - في حال كان يملك أكثر من عنوان - و على أي بورت متوفر.

  • backlog هو رقم يمثل عدد العملاء الأقصى الذي يمكنهم الإتصال مع السيرفر في نفس الوقت.


ترمي الإستثناء IOException في حال فشلت عملية الإتصال أو في حال كان الإتصال مفتوح أصلاً.
ترمي الإستثناء IllegalArgumentException في حال كان الكائن الذي قمنا بتمريره لها لا يتناسب مع البروتوكول المستخدم من قبل كائن الـ ServerSocket الذي قام باستدعائها.
public boolean isBound() ترجع true في حال كان كائن الـ ServerSocket جاهزاً لتلقي إتصالات العملاء على أي عنوان يملكه.
public void setReceiveBufferSize(int size) في حال قمت بإنشاء كائن الـ ServerSocket باستخدام الكونستركتور الذي لا يأخذ أي Argument, يمكنك إستدعاءها قبل استدعاء الدالة bind() لتحديد حجم البيانات الأقصى الذي يمكن تبادله بين الخادم و العميل.

ترمي الإستثناء SocketException في حال حدث خطأ سببه البروتوكول المستخدم في عملية الإتصال.
ترمي الإستثناء IllegalArgumentException في حال وضعت قيمة الباراميتر size أصغر أو تساوي صفر.
public InetAddress getInetAddress() ترجع كائن نوعه InetAddress يمثل عنوان كائن الـ ServerSocket.
ترجع null في حال كان كائن الـ ServerSocket غير جاهز للإتصال مع العملاء, أو في حال تم إغلاقه.
public SocketAddress getLocalSocketAddress() ترجع كائن نوعه InetAddress يمثل عنوان كائن الـ ServerSocket بالإضافة إلى رقم البورت.
ترجع null في حال كان كائن الـ ServerSocket غير جاهز للإتصال مع العملاء, أو في حال تم إغلاقه.
public int getLocalPort() ترجع رقم البورت الذي يستخدمه كائن الـ ServerSocket لتلقي إتصالات العملاء.
ترجع 1- في حال لم يقم كائن الـ ServerSocket بتحديد البورت الذي سيستخدمه قبل استدعائها.
public int getReceiveBufferSize() ترجع رقم يمثل حجم البيانات الذي يمكن تبادله بين الخادم و العميل خلال عملية الإتصال بالـ KB.
public void close() تغلق الإتصال مع العملاء. عندها لن يعود باستطاعتك إستخدام نفس كائن الـ ServerSocketلتلقي إتصالات من العملاء.

في حال حدث خطأ عند التعامل مع الـ Socket يتم رمي الإستثناء IOException
و في حال كائن الـ Socket الذي قام باستدعاءها معلق ترمي الخطأ SocketException.
public boolean isClosed() ترجع true في حال تم إغلاق كائن الـ ServerSocket بواسطة الدالة close().
غير ذلك ترجع false.
public String toString() ترجع نص يمثل عنوان و رقم بورت كائن الـ ServerSocket.

أخطاء محتملة

بعض الأخطاء التي قد تقع عند إنشاء كائن من الكلاسات Socket و ServerSocket.

  • UnknownHostException في حال كان لم يتم معرفة الـ IP Address للـ Host Name الذي قمنا بتمريره.

  • SecurityException في حال كان البرنامج ممنوع من الإتصال بالشبكة.

  • IOException في حال حدث خطأ عند نقل البيانات.

  • IllegalArgumentException في حال كان رقم البورت الموضوع ليس بين 0 و 65535.

  • NullPointerException في حال كان عنوان الجهاز الذي يحاول البرنامج الإتصال معه يساوي null, أي غير محدد.

مثال شامل

في هذا المثال  قمنا بإنشاء برنامجين ( أي مشروعين منفصلين ), واحد للسيرفر إسمه Server و واحد لأي مستخدم عادي إسمه Client.
فكرة البرنامج بشكل عام هي جعل البرنامجين قادرين على التواصل مع بعضهما البعض.

ملاحظة: عند تجربتهما عليك تشغيل برنامج السيرفر أولاً, ثم تشغيل برنامج المستخدم العادي كما فعلنا في الفيديو الذي وضعناه مكان نتيجة التشغيل.


مثال

هذا البرنامج مصمم للسيرفر, و هو موضوع في مجلد إسمه server.

Server.java
                    // هنا قمنا باستدعاء الكلاسات التي سنستخدمها لإنشاء الإتصال
                    import java.io.BufferedReader;
                    import java.io.DataInputStream;
                    import java.io.DataOutputStream;
                    import java.io.InputStreamReader;
                    import java.net.ServerSocket;
                    import java.net.Socket;

                    public class Server {

                    public static void main(String[] args) {

                    try
                    {
                    // Socket لإستقبال أي إتصال من قبل المستخدم, أي لإستقبال أي ServerSocket هنا قمنا بإنشاء كائن من الكلاس
                    ServerSocket ss = new ServerSocket(3333);

                    // آخر Socket يمكنه تبادل الببانات مع أي كائن Socket و التي ترجع كائن نوعه accept() هنا قمنا باستدعاء الدالة
                    Socket s = ss.accept();

                    // s سنستخدمه لقراءة محتوى الكائن dis الكائن
                    DataInputStream dis = new DataInputStream(s.getInputStream());

                    // s سنستخدمه للكتابة في الكائن dos الكائن
                    DataOutputStream dos = new DataOutputStream(s.getOutputStream());

                    // سنستخدمه لقراءة البيانات التي سيدخلها السيرفر من لوحة المفاتيح br الكائن
                    BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

                    // serverMsg و رسالات السيرفر ستتخزن في المتغير clientMsg رسالات المستخدم ستتخزن في المتغير
                    String serverMsg,clientMsg;

                    // end هنا سيستمر التواصل بين السيرفر و المستخدم طالما أن المستخدم لم يكتب
                    do{
                    clientMsg = dis.readUTF();
                    System.out.println("client says: "+clientMsg);
                    serverMsg = br.readLine();
                    dos.writeUTF(serverMsg);
                    dos.flush();
                    }
                    while(!clientMsg.equals("end"));

                    // عند إنتهاء الإتصال قمنا بإغلاق جميع الكائنات التي استخدمناها لإنشاء الإتصال و التي لم يعد لها حاجة
                    dis.close();
                    s.close();
                    ss.close();
                    }
                    catch(Exception e) {
                    System.out.println(e.getMessage());
                    }

                    }

                    }
                  

هذا البرنامج مصمم لأي مستخدم, و هو موضوع في مجلد إسمه client.

Client.java
                    // هنا قمنا باستدعاء الكلاسات التي سنستخدمها لإنشاء الإتصال
                    import java.io.BufferedReader;
                    import java.io.DataInputStream;
                    import java.io.DataOutputStream;
                    import java.io.InputStreamReader;
                    import java.net.Socket;

                    public class Client {

                    public static void main(String[] args) {

                    try
                    {
                    // 3333 للتواصل مع برنامج آخر موجود على سيرفر و يستخدم البورت Socket هنا قمنا بإنشاء كائن من الكلاس
                    Socket s = new Socket("localhost",3333);

                    // s سنستخدمه لقراءة محتوى الكائن dis الكائن
                    DataInputStream dis = new DataInputStream(s.getInputStream());

                    // s سنستخدمه للكتابة في الكائن dos الكائن
                    DataOutputStream dos = new DataOutputStream(s.getOutputStream());

                    // سنستخدمه لقراءة البيانات التي سيدخلها المستخدم من لوحة المفاتيح br الكائن
                    BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

                    // serverMsg و رسالات السيرفر ستتخزن في المتغير clientMsg رسالات المستخدم ستتخزن في المتغير
                    String serverMsg, clientMsg;

                    // end هنا سيستمر التواصل بين السيرفر و المستخدم طالما أن المستخدم لم يكتب
                    do{
                    clientMsg = br.readLine();
                    dos.writeUTF(clientMsg);
                    dos.flush();
                    serverMsg = dis.readUTF();
                    System.out.println("server says: "+serverMsg);
                    }
                    while(!clientMsg.equals("end"));

                    // عند إنتهاء الإتصال قمنا بإغلاق جميع الكائنات التي استخدمناها لإنشاء الإتصال و التي لم يعد لها حاجة
                    dis.close();
                    dos.close();
                    s.close();
                    }
                    catch(Exception e) {
                    System.out.println(e.getMessage());
                    }

                    }

                    }
                  

ستحصل على نتيجة تشبه النتيجة التالية عند التشغيل.

__________&&&______;&&&___________;&&&&________; __________&&&______;&&&___________;&&&&________;