مثال كامل على نقل الملفات استنادًا إلى بروتوكول مقبس Java ، الذي تم الانتهاء منه بناءً على اتصال TCP.
بالإضافة إلى نقل الملفات الثنائية المستندة إلى TCP ، بعض مهارات البرمجة في Java Swing ، برنامج العرض التوضيحي
يتم تنفيذ الوظائف الرئيسية على النحو التالي:
أولاً ، دعونا نلقي نظرة على العلاقة بين فئة القبة بأكملها:
فيما يلي شرح مفصل للوظائف وتطبيقات التعليمات البرمجية لكل فئة وفقًا للشكل أعلاه:
جانب الخادم:
وظيفة فئة FileTransferserver هي أول من إنشاء مقبس خادم على المنفذ 9999 و
ابدأ في الاستماع إلى الاتصال. الرموز ذات الصلة هي كما يلي:
private void starterver (int port) {try {serversocket = new ServersOcket (port) ؛ System.out.println ("بدأ الخادم في المنفذ:" + منفذ) ؛ بينما (صواب) {socket client = serversOcket.accept () ؛ // blocked & في انتظار Socket Socket.out.println ("فقط متصل بـ" + client.getRemotesocketAddress ()) ؛ مهمة FileReceivetask = جديد fileReceivetask (عميل) ؛ bar.setValue (0) ؛ // إعادة تعيينها الآن Task.addPropertyChangelistener (New PropertyChangelistener () {public void propertyChange (propertyChangeEvent evt) {if ("progress" .equals (evt.getPropertyName ()))) Task.execute () ؛ }} catch (ioException e) {E.PrintStackTrace () ؛ }}حول PropertyChangelistener ، توفر Java فئة أدوات قوية للغاية لمراقبة تغييرات البيانات في أي نموذج بين الفول. ينفذ البرنامج
تغيير قيمة خاصية التقدم في Swingworker ، ثم تحديث JProgressBar
كائن مثيل ، يحقق تحديث واجهة المستخدم. رمز المصدر الكامل لفئة FileTransferserver هو كما يلي:
package com.gloomyfish.socket.tutorial.filetransfer ؛ استيراد java.awt.borderlayout ؛ استيراد java.awt.flowlayout ؛ استيراد java.awt.event.actionevent ؛ استيراد java.awt.event.actionListener ؛ استيراد java.beans.propertyChangeEvent ؛ استيراد java.beans.propertychangelistener ؛ استيراد java.io.ioException ؛ استيراد java.net.serversocket ؛ استيراد java.net.socket ؛ استيراد javax.swing.boxlayout ؛ استيراد javax.swing.jbutton ؛ استيراد javax.swing.jframe ؛ استيراد javax.swing.joptionpane ؛ استيراد javax.swing.jpanel ؛ استيراد javax.swing.jprogressbar ؛ يمتد FileTransferserver من الفئة العامة jframe actionlistener { / ** * * / public Final Static String Start_Svr = "start" ؛ السلسلة الثابتة النهائية العامة string_down_svr = "king down" ؛ السلسلة الثابتة النهائية العامة end_flag = "eof" ؛ خاص ثابت نهائي طويل المسبانيويد = 1L ؛ ServerSocket Serversocket ؛ خاص jbutton startbtn ؛ شريط JProgressBar الخاص ؛ Public FileTransferserver () {super ("file server") ؛ initComponent () ؛ setuplistener () ؛ } private void setuplistener () {StartBtn.AddActionListener (this) ؛ } private void initComponent () {StartBtn = New JButton (start_svr) ؛ JPanel ProgressPanel = new JPanel () ؛ ProgressPanel.setLayout (New BoxLayout (ProgressPanel ، boxlayout.y_axis)) ؛ BAR = New JProgressBar () ؛ bar.setMinimum (0) ؛ bar.setMaximum (100) ؛ ProgressPanel.Add (BAR) ؛ getContentPane (). setLayout (New BorderLayout ()) ؛ jpanel btnpanel = new jpanel (New FlowLayout (flowlayout.right)) ؛ btnpanel.add (startbtn) ؛ getContentPane (). add (btnpanel ، borderlayout.south) ؛ getContentPane (). add (ProgressPanel ، BorderLayout.Center) ؛ } private void starterver (int port) {try {serversocket = new ServersOcket (port) ؛ System.out.println ("بدأ الخادم في المنفذ:" + منفذ) ؛ بينما (صواب) {socket client = serversOcket.accept () ؛ // blocked & في انتظار Socket Socket.out.println ("فقط متصل بـ" + client.getRemotesocketAddress ()) ؛ مهمة FileReceivetask = جديد fileReceivetask (عميل) ؛ bar.setValue (0) ؛ // إعادة تعيينها الآن Task.addPropertyChangelistener (New PropertyChangelistener () {public void propertyChange (propertyChangeEvent evt) {if ("progress" .equals (evt.getPropertyName ()))) Task.execute () ؛ }} catch (ioException e) {E.PrintStackTrace () ؛ }} public void displesuccess () {bar.setValue (100) ؛ joptionpane.showmessagedialog (هذا ، "ملف تم استلامه بنجاح!") ؛ } Override public void actionperformed (ActionEvent e) {if (start_svr.equals ( startThread.start () ؛ startbtn.setEnabled (false) ؛ } آخر إذا (sther_down_svr.equals (e.getActionCommand ()))) {} آخر {// لا شيء ...}} الفراغ الثابت العام (سلسلة [] args) {filetransferserver server = new fileTransferserver () ؛ server.setDefaultCloseOperation (jframe.exit_on_close) ؛ server.setsize (400 ، 400) ؛ server.setResizeBer (false) ؛ server.setVisible (صحيح) ؛ }} FileReceivetask هي فئة قبول الملف على جانب الخادم:
أولاً ، احصل على اسم الملف وحجم الملف من دفق TCP المعمول به ، ثم ابدأ في قبول بايت محتوى الملف
واكتب إلى دفق كائن الملف الذي تم إنشاؤه ، وتحقق أخيرًا مما إذا كان حجم الملف يساوي دفق البايت المكتوب
أخيرًا ، أرسل رسالة إلى مرسل الملف لإخبار الطرف الآخر بأن نقل الملف قد اكتمل ويمكن إغلاق دفق TCP.
رمز المصدر الكامل لهذه الفئة هو كما يلي:
package com.gloomyfish.socket.tutorial.filetransfer ؛ استيراد java.io.bufferedOutputStream ؛ استيراد java.io.bufferedOutputStream ؛ استيراد java.io.datainputStream ؛ استيراد java.io.file ؛ استيراد java.io.fileOutputStream ؛ استيراد java.io.outputStreamWriter ؛ استيراد java.net.socket ؛ استيراد Javax.swing.swingworker ؛ يمتد FileReceivetask من الفئة العامة Swingworker <Integer ، Object> {private Socket _msocket ؛ Public FileReceivetask (عميل المقبس) {this._msocket = client ؛ } Override Integer DoInbackground () يلقي استثناء {// الحصول على معلومات meta datainputStream إدخال = جديد datainputStream (_msocket.getInputStream ()) ؛ اسم ملف السلسلة = input.readutf () ؛ int fileLength = (int) input.readlong () ؛ // عدد ملف ملف البايت الكلي = ملف جديد ("c: // user // fish // downloads" + file.separator + filename) ؛ إخراج bufferedoutputstream = جديد bufferedoutputStream (FileOutputStream جديد (ملف)) ؛ System.out.println ("اسم الملف المستلم =" + اسم الملف) ؛ System.out.println ("Size file size =" + fileLength/1024 + "kb") ؛ // ابدأ في تلقي محتوى الملف واكتبها بايت [] المحتوى = بايت جديد [2048] ؛ int الإزاحة = 0 ؛ int numReadBytes = 0 ؛ بينما (الإزاحة <fileLength && (numReadByTes = input.Read (content))> 0) {output.write (content ، 0 ، numReadBytes) ؛ float precent = 100.0f * ((تعويم) إزاحة)/((تعويم) طول fileLengle) ؛ setProgress ((int) precent) ؛ الإزاحة += numReadBytes ؛ } system.out.println ("numReadBytes =" + numReadBytes) ؛ if (Offset <fileLength) {numReadByTes = input.Read (content) ؛ system.out.println ("numReadByTes =" + numReadBytes) ؛ System.out.println ("خطأ محتوى الملف في جانب الخادم") ؛ } آخر {system.out.println ("تم إجراء مهمة تلقي الملف بشكل صحيح") ؛ } setProgress (100) ؛ // أخبر العميل بإغلاق المقبس الآن ، نتلقى بالفعل الملف بنجاح !! BufferedWriter BufferedWriter = new BufferedWriter (New OutputStreamWriter (_msocket.getOutputStream ())) ؛ bufferedWriter.write ("Done/r/n") ؛ bufferedWriter.flush () ؛ // أغلق الملف والمقبس Output.close () ؛ _msocket.close () ؛ إرجاع 100 ؛ }} عميل:
FileTransferClient هي فئة واجهة المستخدم العميل التي تنفذ اتصال الخادم ثم يختار
الملفات المراد نقلها (الصور ، PDFs ، مستندات الكلمات ، إلخ). إذا لم يكن كذلك
أدخل معلومات الخادم وستظهر موجه. تم تحديد المنفذ على النحو التالي: 9999
سيفتح زر [إرسال الملف] مربع تحديد الملف. بعد أن يحدد المستخدم الملف المراد نقله ، قم بإنشاء ملف
مؤشر ترابط FileTransferTask وابدأ في تنفيذ نقل الملفات. رمز واجهة المستخدم العميل كما يلي:
package com.gloomyfish.socket.tutorial.filetransfer ؛ استيراد java.awt.borderlayout ؛ استيراد java.awt.flowlayout ؛ استيراد java.awt.gridlayout ؛ استيراد java.awt.event.actionevent ؛ استيراد java.awt.event.actionListener ؛ استيراد java.beans.propertyChangeEvent ؛ استيراد java.beans.propertychangelistener ؛ استيراد java.io.file ؛ استيراد java.net.inetsocketaddress ؛ استيراد java.net.socketaddress ؛ استيراد javax.swing.borderfactory ؛ استيراد javax.swing.boxlayout ؛ استيراد javax.swing.jbutton ؛ استيراد javax.swing.jfilechooser ؛ استيراد javax.swing.jframe ؛ استيراد javax.swing.jlabel ؛ استيراد javax.swing.joptionpane ؛ استيراد javax.swing.jpanel ؛ استيراد javax.swing.jprogressbar ؛ استيراد javax.swing.jtextfield ؛ /*** عادةً ما أكتب تعليقات باللغة الإنجليزية ، وأحيانًا أكتب تعليقات صينية أيضًا ، لكنني أعتقد أن كتابة التعليقات الإنجليزية* أكثر توحيدًا مع الكود ، ولا شيء آخر. */ الفئة العامة fileTransferClient يمتد JFrame تنفيذ ActionListener {/ ** * */ private Static Final Long SerialVersionuid = 1L ؛ السلسلة الثابتة النهائية العامة send_cmd = "إرسال ملف" ؛ الحد الأدنى النهائي في الحد الأدنى = 0 ؛ الحد الأقصى النهائي الثابت الحد الأقصى = 100 ؛ // public final static string connect_cmd = "connect" ؛ الخاص jbutton sendFileBtn ؛ خاص JTextfield Serverfield ؛ Private Jtextfield Portfield ؛ شريط JProgressBar الخاص ؛ Public FileTransferClient () {Super ("File Transfer Client") ؛ initComponents () ؛ } private void initComponents () {getContentPane (). setLayout (New BorderLayout ()) ؛ JPanel ProgressPanel = new JPanel () ؛ ProgressPanel.setLayout (new boxlayout (progresspanel ، boxlayout.y_axis) ؛ bar = new jprogressbar () ؛ progresspanel.add (bar) ؛ bar.setMinimum (minimum) ؛ bar.setMaximum (maximum) ؛ Gridlayout (2،2،5،5) ؛ Serversingpanel.Add (New JLabel ("منفذ الخادم:") ؛ Btnpanel.Add (SendFileBtn) ؛ Actionperformed (ActionEvent e) {string command = chooser.showopendialog (null) ؛ Task.AddPropertyChangelistener (PropertyChangelistener () {public void property (propertyChangeEvent) {if ( } {// لا شيء}} public void downsuccess () {bar.setvalue (100) ؛ } INTEGER.PARSEINT (PORT) ؛ Client.Setsize (400 ، الوظائف الرئيسية التي تنفذها FileTransferTask هي:
رمز المصدر الكامل لهذه الفئة هو كما يلي:
package com.gloomyfish.socket.tutorial.filetransfer ؛ استيراد java.io.bufferedInputStream ؛ استيراد java.io.bufferedreader ؛ استيراد java.io.datainputStream ؛ استيراد java.io.dataOutputStream ؛ استيراد java.io.file ؛ استيراد java.io.fileInputStream ؛ استيراد java.io.ioException ؛ استيراد java.io.inputstreamreader ؛ استيراد java.net.socket ؛ استيراد java.net.socketaddress ؛ استيراد Javax.swing.swingworker ؛ يمتد FileTransferTask من الفئة العامة Swingworker <Integer ، Object> {private file selectFile ؛ مقبس خاص msocket ؛ عنوان المقبس الخاص ؛ PILTRANSFERCLIENT الخاص ؛ Public FileTransferTask (ملف الملف ، عنوان SocketAddress ، مالك FileTransferClient /*، JprogressBar Progress* /) {this.address = العنوان ؛ this.selectedfile = ملف ؛ msocket = مقبس جديد () ؛ this.parent = المالك ؛ } Override Integer Integer doInbackground () يلقي استثناء {// احصل على حجم الملف الطويل = selectionfile.length () ؛ if (length> integer.max_value) {رمي ioException جديد ("لا يمكن قراءة الملف بالكامل" + selectFile.getName () + "لأنه طويل جدًا (" + طول + "بايت ، مبلغ الحد الأقصى المدعوم" + integer.max_value + ")") ؛ } msocket.connect (العنوان) ؛ // إنشاء صفيف البايت للاحتفاظ ببيانات الملف msocket.setsolinger (True ، 60) ؛ DataOutputStream Dout = جديد DataOutputStream (msocket.getOutputStream ()) ؛ // نبدأ الآن في إرسال معلومات ملف التعريف. dout.writeutf (selectFile.getName ()) ؛ dout.writelong (طول) ؛ dout.flush () ؛ // End Comment FileDatapackage pdata = new FileDatapackage () ؛ DatainputStream هو = جديد datainputStream (جديد fileInputStream (SelectionFile)) ؛ بايت [] بايت = بايت جديد [2048] ؛ // اقرأ في بايت int الإزاحة = 0 ؛ int numRead = 0 ؛ int fsize = (int) طول ؛ بينما (الإزاحة <fsize && (numRead = iS.Read (bytes ، 0 ، bytes.length))> = 0) {pdata.setData (bytes ، numRead) ؛ dout.write (pdata.getPackagedata () ، 0 ، pdata.getPackagedata (). الطول) ؛ dout.flush () ؛ الإزاحة += numRead ؛ float precent = 100.0f * ((float) offset)/((float) fsize) ؛ setProgress ((int) precent) ؛ } system.out.println ("total send bytes =" + offset) ؛ // تأكد من قراءة جميع البايتات في إذا (الإزاحة <fsize) {رمي ioException جديد ("لا يمكن نقل الملف بالكامل" + selectFile.getName ()) ؛ } msocket.shutdownoutput () ؛ // تلقي رسالة نقل الملف بنجاح من الاتصال bufferedInputStream StreamReader = جديد bufferedInputStream (msocket.getInputStream ()) ؛ Bufferreaderer BufferedReader = جديد BufferedReader (New InputStreamReader (StreamReader)) ؛ String Donemsg = BufferedReader.ReadLine () ؛ if ("done" .equals (donemsg)) {parent.showsuccess () ؛ } // أغلق دفق إدخال الملف setProgress (100) ؛ // dout.close () ؛ msocket.close () ؛ is.close () ؛ System.out.println ("أغلقها الآن ...") ؛ إرجاع 100 ؛ }}فئة الحزمة كما يلي ، لم يتم شرحها!
package com.gloomyfish.socket.tutorial.filetransfer ؛ / ** * هذا هو بروتوكول نقل الملفات البسيط للغاية عبر مقبس TCP */ فئة عامة FileDatapackage {private int datalength ؛ // طول البيانات في الحزمة ، قاعدة بيانات بايت بايت [] [] ؛ // أقصى بيانات في الحزمة ، يجب ألا يتجاوز MEICI 2048 Bytes Public Final Static Byte [] eof = new byte [] {'e' ، 'o' ، 'f'} ؛ Public FileDatapackage () {datalength = 0 ؛ Databuff = New Byte [2048] ؛ } public byte [] getPackagedata () {byte [] pdata = new byte [datalength] ؛ // end comment system.arrayCopy (databuff ، 0 ، pdata ، 0 ، datalength) ؛ إرجاع pdata ؛ } public void setData (byte [] data ، int bsize) {datalength = bsize ؛ لـ (int i = 0 ؛ i <databuff.length ؛ i ++) {if (i <bsize) {databuff [i] = data [i] ؛ } آخر {databuff [i] = '' ؛ }}}}الحد الأقصى لعدد البايتات المرسلة لكل وقت هو 2048 بايت. التأثير النهائي للبرنامج هو كما يلي (Win7 + JDK6U30):
ما سبق هو كل شيء عن هذا المقال ، آمل أن يكون مفيدًا لتعلم الجميع.