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

مساعدة في Chatting Program Using Socket

بدأه مجلـد جديـد في 30 نوفمبر 2008 · 8 رد · 853 مشاهدة · في JavaSE
مشاركة: واتساب X فيسبوك تيليجرام
#1 صاحب الموضوع

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

لدي برنامج chatting يعمل على الشبكة باستخدام socket ، الملفات كتالي:

ChatServer.java

ChatServerThread.java

ChatClient.java

ChatClientThread.java

اي اربع classes

المشكلة انه بتوزيع الكود بين هذه الملفات او الاربع classes اصبح صعب الفهم ومعقد

فهل يمكن وضعه داخل ملفين فقط ، اي two classes

ChatClient.java

ChatServer.java

الملفات في المرفقات وايضا مدمجة مع الموضوع:

first class

ChatServer

  1.  
  2. import java.net.*;
  3. import java.io.*;
  4.  
  5. public class ChatServer implements Runnable
  6. {
  7. private ChatServerThread clients[] = new ChatServerThread[2];
  8. private ServerSocket server = null;
  9. private Thread thread = null;
  10. private int clientCount = 0;
  11.  
  12. public ChatServer( int port )
  13. {
  14. try
  15. {
  16. System.out.println("Binding to port " + port + ", please wait ...");
  17. server = new ServerSocket(port);
  18. System.out.println("Server started: " + server);
  19. start();
  20. }
  21. catch(IOException ioe)
  22. {
  23. System.out.println("Can not bind to port " + port + ": " + ioe.getMessage());
  24. }
  25. }
  26.  
  27. public void run()
  28. {
  29. while ( thread != null ) // or while ( true )
  30. {
  31. try
  32. {
  33. System.out.println("Waiting for a client ...");
  34. addThread( server.accept()); // listening
  35. }
  36. catch(IOException ioe)
  37. {
  38. System.out.println("Server accept error: " + ioe);
  39. stop();
  40. }
  41. }
  42. }
  43.  
  44. public void start()
  45. {
  46. if (thread == null)
  47. {
  48. thread = new Thread(this);
  49. thread.start();
  50. }
  51. }
  52.  
  53. public void stop()
  54. {
  55. if ( thread != null )
  56. {
  57. thread.stop();
  58. thread = null;
  59. }
  60. }
  61.  
  62. private int findClient( int ID )
  63. {
  64. for (int i = 0; i < clientCount; i++)
  65. if ( clients[i].getID() == ID )
  66. return i;
  67. return -1;
  68. }
  69.  
  70. public synchronized void handle( int ID, String input )
  71. {
  72. if ( input.equals(".bye") )
  73. {
  74. clients[ findClient(ID) ].send(".bye");
  75. remove( ID );
  76. }
  77. else
  78. for ( int i = 0; i < clientCount; i++)
  79. clients[i].send( ID + ": " + input );
  80. }
  81.  
  82. public synchronized void remove( int ID )
  83. {
  84. int pos = findClient( ID );
  85. if ( pos >= 0 )
  86. {
  87. ChatServerThread toTerminate = clients[pos];
  88. System.out.println("Removing client thread " + ID + " at " + pos);
  89.  
  90. if ( pos < clientCount-1 )
  91. for (int i = pos+1; i < clientCount; i++)
  92. clients[i-1] = clients[i];
  93.  
  94. clientCount--;
  95. try
  96. {
  97. toTerminate.close();
  98. }
  99. catch(IOException ioe)
  100. {
  101. System.out.println("Error closing thread: " + ioe);
  102. }
  103.  
  104. toTerminate.stop();
  105. }
  106. }
  107.  
  108. private void addThread( Socket socket )
  109. {
  110. if ( clientCount < clients.length )
  111. {
  112. System.out.println("Client accepted: " + socket );
  113. clients[clientCount] = new ChatServerThread( this, socket );
  114. try
  115. {
  116. clients[clientCount].open();
  117. clients[clientCount].start();
  118. clientCount++;
  119. }
  120. catch(IOException ioe)
  121. {
  122. System.out.println("Error opening thread: " + ioe);
  123. }
  124. }
  125. else
  126. {
  127. System.out.println("Client refused: maximum " + clients.length + " reached.");
  128. try
  129. {
  130. System.out.println("Closing client socket ...");
  131. socket.close();
  132. }
  133. catch( Exception e )
  134. {
  135. System.out.println("Error closing client socket: "+ e );
  136. }
  137.  
  138. }
  139. }
  140.  
  141. public static void main(String args[])
  142. {
  143. ChatServer server = null;
  144. if (args.length != 1)
  145. System.out.println("Usage: java ChatServer port");
  146. else
  147. server = new ChatServer( Integer.parseInt(args[0]) );
  148. }
  149. }
  150.  

second class

ChatServerThread

  1.  
  2. import java.net.*;
  3. import java.io.*;
  4.  
  5. public class ChatServerThread extends Thread
  6. {
  7. private ChatServer server = null;
  8. private Socket socket = null;
  9. private int ID = -1;
  10. private DataInputStream streamIn = null;
  11. private DataOutputStream streamOut = null;
  12.  
  13. public ChatServerThread( ChatServer _server, Socket _socket )
  14. {
  15. super();
  16. server = _server;
  17. socket = _socket;
  18. ID = socket.getPort();
  19. }
  20.  
  21. public void send( String msg )
  22. {
  23. try
  24. {
  25. streamOut.writeUTF(msg);
  26. streamOut.flush();
  27. }
  28. catch(IOException ioe)
  29. {
  30. System.out.println(ID + " ERROR sending: " + ioe.getMessage());
  31. server.remove(ID);
  32. stop(); // OR server.stop?
  33. }
  34. }
  35.  
  36. public int getID()
  37. {
  38. return ID;
  39. }
  40.  
  41. public void run()
  42. {
  43. System.out.println("Server Thread " + ID + " running.");
  44. while (true)
  45. {
  46. try
  47. {
  48. server.handle( ID, streamIn.readUTF() );
  49. }
  50. catch(IOException ioe)
  51. {
  52. System.out.println(ID + " ERROR reading: " + ioe.getMessage());
  53. server.remove(ID);
  54. stop();
  55. }
  56. }
  57. }
  58.  
  59. public void open() throws IOException
  60. {
  61. streamIn = new DataInputStream( new BufferedInputStream( socket.getInputStream()) );
  62. streamOut = new DataOutputStream( new BufferedOutputStream( socket.getOutputStream()) );
  63. }
  64.  
  65. public void close() throws IOException
  66. {
  67. if ( socket != null )
  68. socket.close();
  69. if ( streamIn != null )
  70. streamIn.close();
  71. if ( streamOut != null )
  72. streamOut.close();
  73. }
  74. }
  75.  

third class

ChatClient

  1.  
  2. import java.net.*;
  3. import java.io.*;
  4.  
  5. public class ChatClient implements Runnable
  6. {
  7. private Socket socket = null;
  8. private Thread thread = null;
  9. private DataInputStream console = null;
  10. private DataOutputStream streamOut = null;
  11. private ChatClientThread client = null;
  12.  
  13. public ChatClient( String serverName, int serverPort )
  14. {
  15. System.out.println("Establishing connection. Please wait ...");
  16. try
  17. {
  18. socket = new Socket( serverName, serverPort );
  19. System.out.println("Connected: " + socket);
  20. start();
  21. }
  22. catch(UnknownHostException uhe)
  23. {
  24. System.out.println("Host unknown: " + uhe.getMessage());
  25. }
  26. catch(IOException ioe)
  27. {
  28. System.out.println("Unexpected exception: " + ioe.getMessage());
  29. }
  30. }
  31.  
  32. public void run()
  33. {
  34. while ( thread != null )
  35. {
  36. try
  37. {
  38. streamOut.writeUTF( console.readLine() );
  39. streamOut.flush();
  40. }
  41. catch(IOException ioe)
  42. {
  43. System.out.println("Sending error: " + ioe.getMessage());
  44. stop();
  45. }
  46. }
  47. }
  48.  
  49. public void handle( String msg )
  50. {
  51. if ( msg.equals(".bye") )
  52. {
  53. System.out.println("Good bye. Press RETURN to exit ...");
  54. stop();
  55. }
  56. else
  57. System.out.println(msg);
  58. }
  59.  
  60. public void start() throws IOException
  61. {
  62. console = new DataInputStream( System.in );
  63. streamOut = new DataOutputStream( socket.getOutputStream() );
  64. if ( thread == null )
  65. {
  66. client = new ChatClientThread( this, socket );
  67. thread = new Thread(this);
  68. thread.start();
  69. }
  70. }
  71.  
  72. public void stop()
  73. {
  74. if (thread != null)
  75. {
  76. thread.stop();
  77. thread = null;
  78. }
  79. try
  80. {
  81. if ( console != null )
  82. console.close();
  83. if ( streamOut != null )
  84. streamOut.close();
  85. if ( socket != null )
  86. socket.close();
  87. }
  88.  
  89. catch(IOException ioe)
  90. {
  91. System.out.println("Error closing ...");
  92. }
  93. client.close();
  94. client.stop();
  95. }
  96.  
  97. public static void main(String args[])
  98. {
  99. ChatClient client = null;
  100. if ( args.length != 2 )
  101. System.out.println("Usage: java ChatClient host port");
  102. else
  103. client = new ChatClient( args[0], Integer.parseInt(args[1]) );
  104. }
  105. }
  106.  

fourth class

ChatClientThread

  1.  
  2. import java.net.*;
  3. import java.io.*;
  4.  
  5. public class ChatClientThread extends Thread
  6. {
  7. private Socket socket = null;
  8. private ChatClient client = null;
  9. private DataInputStream streamIn = null;
  10.  
  11. public ChatClientThread( ChatClient _client, Socket _socket )
  12. {
  13. client = _client;
  14. socket = _socket;
  15. open();
  16. start();
  17. }
  18.  
  19. public void open()
  20. {
  21. try
  22. {
  23. streamIn = new DataInputStream(socket.getInputStream());
  24. }
  25. catch(IOException ioe)
  26. {
  27. System.out.println("Error getting input stream: " + ioe);
  28. client.stop();
  29. }
  30. }
  31.  
  32. public void close()
  33. {
  34. try
  35. {
  36. if (streamIn != null) streamIn.close();
  37. }
  38. catch(IOException ioe)
  39. {
  40. System.out.println("Error closing input stream: " + ioe);
  41. }
  42. }
  43.  
  44. public void run()
  45. {
  46. while (true)
  47. {
  48. try
  49. {
  50. client.handle( streamIn.readUTF() );
  51. }
  52. catch(Exception e)
  53. {
  54. System.out.println("Listening error: " + e.getMessage());
  55. client.stop();
  56. }
  57. }
  58. }
  59. }
  60.  

#2

يمكنك وضعهم في ملفين فقط ، لكن لن يتغير شيء في الكود ، وبالتالي يزداد حجم الملف الواحد ،،

فالملف ChatServer.java يقوم في البدايه بعمل Thread يقوم فيه بالأنتظار لأي كلاينت يريد الأتصال فيه ، وحين يتم ذلك ، يقوم بعمل كائن جديد من ChatServerThread.java وهو Thread مهتمه قرائه ما تم ارساله الكلاينت ، وثم يتم استدعاء داله handle نتظر هل هذه الرساله .bye فاذا كانت كذلك فأنها ترجع رساله للعميل تفيده بالخروج ، والا فسوف تطبع الرساله مع رقم العميل _يمكن أنشاء عميلين في البرنامج_ .

لاحظ أن الملف الأول ChatServer يحتوي على مصفوفه من كائنتات ChatServerThread وبالتالي يجب أن يتواجد هذا الكلاس ، سواء في ملف منفصل ، أو يمكنك نسخ محتوياته وضعها في أخر الملف ChatServer وغير حمايه الكلاس من public الى private لأنه لا يمكن وجود كلاسين public في نفس الملف ..

وبنفس المنطق مع الملفين الأخرين ،ChatClient.java تقوم في البدايه بانشاء Thread جديد مهمته هنا ارسال رسائل للخادم، وفي نفس اللحظه تنشىء Thread أخر ChatClientThread.java مهتمه قرائه الرسائل التي تأتيه وطباعتها اذا لم تكن .bye ..

بالنسبه للداله stop ، ففي الملف ChatServer و ChatClient تكون مهتمها غلق Thread الأساسي بالكامل ، وفي الملف الأول تكون بمعني أن السيرفر لن يتسقبل أي اتصال بعد ذلك ، وفي الملف الثاني فهي أيضا تغلق الThread الأساسي هنا والذي مهتمه ارسال الرسائل للخادم وأيضا تغلق الsocket الخاص للتعامل مع الخادم ، وتغلق مجرى الأرسال أيضا ..

أما بالنسبه للملفات ChatServerThread و ChatClientThread فالداله stop تقوم هنا بغلق Thread الحالي والذي هو في الملف الأول Thread التعامل مع الكلاينت ، وفي الثاني Thread قرائه الرسائل من الخادم . على العموم استخدام stop مع الThread غير جيد ، خاصه أنها أصبحت داله ملغيهdeprecated في جافا 1.5 .

بالتوفيق ،،

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

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

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

#3

انا اقصد هل يمكن استخدام فقط two classes ؟

البرنامج هذا يقوم بربط كل server thread مع client thread

#4

اذا مصر على كلاسين فقط ، ضع ال ChatServerThread داخل ChatServer ويكون inner class :) . ونفس الأمر مع الclient ،،

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

بالتوفيق :) .

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

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

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

#5

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

هل يمكن عمل نفس البرنامج باستخدام java RMI؟

#6

نعم يمكن ، فبدل أن ترسل عن طريق socket رساله string ، ستقوم باستدعاء داله موجوده في الجهه الأخرى وتمرر لها ذلك string ، وستريح نفسك من انشاء thread رئيسي (يتعامل مع أكثر من كلاينت) لأنه السيرفر في RMI يستطيع التعامل مع أي عدد من العملاء ،

بالتوفيق .

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

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

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

#7

أخي ممكن تقول لي مامعني الشرطه التي قبل هذه المتغيرات؟

public ChatClientThread( ChatClient _client, Socket _socket )

هل ترمز للعنوان مثل السي ++ لما كنا نقول &variable?

بس التمرير داخل الجافا يتعامل تلقائياً مع الـreferance أثناء التمرير!

ممكن توضحوها لي؟


HeartOutputStream myHeart;
OutputStream myHeartOutStream;

myHeartOutStream = MAllaw.getHeart().getOutputStream();
myHeart = new HeartOutputStream(myHeartOutStream);

while(myHeart.isStillBeating())
myHeart.write("I ♥ Java");

#8

يجوز استخدام _ في تسميه المتغيرات ، فيمكن أن تجد _number , ويمكن أن يبدأ المتغير بها ..لا مشكله ..

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

بالتوفيق :) .

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

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

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

#9
اقتباس
جوز استخدام _ في تسميه المتغيرات ، فيمكن أن تجد _number , ويمكن أن يبدأ المتغير بها ..لا مشكله ..

أهااااااااا مجرد رمز عادي مثل $ صح ذكرت :)

شكرا أخي وجدي

اقتباس
بالنسبه للتمرير في جافا فهو دائما عن طريق القيمه ، وعندما تمرر كائن الى داله فأنت تمرر موقعه (reference) في الذاكره وبالتالي يمكن تغيير قيمته فقط ولن يمكنك جعله يشير لموقع أخر في الذاكره

أيوا بالضبط أنا قصدي بالنسبه للأوبجكتس فتتعامل تلقائياً مع الـ referance مثل المصفوفات في الجافا تعتبر object لكن المتغيرات العاديه مثل الـint والـfloat وغيرها فتكون by value

مشكور مره أخرى أخي العزيز وجدي على التوضيح :)


HeartOutputStream myHeart;
OutputStream myHeartOutStream;

myHeartOutStream = MAllaw.getHeart().getOutputStream();
myHeart = new HeartOutputStream(myHeartOutStream);

while(myHeart.isStillBeating())
myHeart.write("I ♥ Java");

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