ตัวอย่างที่สมบูรณ์ของการถ่ายโอนไฟล์ตามโปรโตคอล Java Socket ซึ่งเสร็จสมบูรณ์ตามการสื่อสาร TCP
นอกเหนือจากการถ่ายโอนไฟล์ไบนารีที่ใช้ TCP แล้วทักษะการเขียนโปรแกรมบางอย่างของ Java Swing โปรแกรมสาธิต
ฟังก์ชั่นหลักมีการใช้งานดังนี้:
ก่อนอื่นมาดูความสัมพันธ์ระหว่างคลาสโดมทั้งหมด:
ต่อไปนี้เป็นคำอธิบายโดยละเอียดของฟังก์ชั่นและการใช้งานรหัสของแต่ละคลาสตามรูปด้านบน:
ด้านเซิร์ฟเวอร์:
ฟังก์ชั่นของคลาส FileTransferserver เป็นอันดับแรกในการสร้างซ็อกเก็ตเซิร์ฟเวอร์บนพอร์ต 9999 และ
เริ่มฟังการเชื่อมต่อ รหัสที่เกี่ยวข้องมีดังนี้:
Private Void starterver (พอร์ต int) {ลอง {serversocket = new Serversocket (พอร์ต); System.out.println ("เซิร์ฟเวอร์เริ่มต้นที่พอร์ต:" + พอร์ต); ในขณะที่ (จริง) {ซ็อกเก็ตไคลเอนต์ = serversocket.accept (); // บล็อก & รอสำหรับซ็อกเก็ตรายได้ System.out.println ("เชื่อมต่อกับ" + client.getRemotesocketAddress ()); งาน filereceivetask = ใหม่ filereceivetask (ไคลเอนต์); bar.setValue (0); // รีเซ็ตตอนนี้ task.addpropertychangelistener (ใหม่ PropertyChangelistener () {โมฆะสาธารณะ PropertyChange (PropertyChangeEvent evt) {ถ้า ("ความคืบหน้า" .Equals (evt.getPropertyName ()) {bar.setValue task.execute (); }} catch (ioexception e) {e.printstacktrace (); -เกี่ยวกับ PropertyChangelistener, Java มีคลาสเครื่องมือที่ทรงพลังมากเพื่อตรวจสอบการเปลี่ยนแปลงข้อมูลในรูปแบบถั่วใด ๆ โปรแกรมใช้ไฟล์
การเปลี่ยนแปลงค่าคุณสมบัติของคุณสมบัติความคืบหน้าของ Swingworker จากนั้นอัปเดต JProgressBar
วัตถุอินสแตนซ์ตระหนักถึงการรีเฟรชของ UI ซอร์สโค้ดที่สมบูรณ์ของคลาส FileTransferserver มีดังนี้:
แพ็คเกจ 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; Public Class FileTransferserver ขยาย JFrame ใช้ ActionListener { / ** * * / สตริงคงสุดท้ายสุดท้ายเริ่มต้น start_svr = "start"; สตริงคงที่สาธารณะสุดท้าย shut_down_svr = "ปิดตัวลง"; สตริงคงที่สาธารณะสุดท้าย end_flag = "eof"; ส่วนตัวคงที่สุดท้าย Long SerialVersionUid = 1L; Serversocket ส่วนตัว Serversocket; JBUTTON ส่วนตัว startBTN; แถบ JProgressBar ส่วนตัว; public filetransferserver () {super ("ไฟล์เซิร์ฟเวอร์"); initcomponent (); setuplistener (); } โมฆะส่วนตัว setupListener () {startBtn.AddActionListener (นี่); } โมฆะส่วนตัว initComponent () {startBtn = ใหม่ jButton (start_svr); JPanel ProgressPanel = new JPanel (); ProgressPanel.SetLayout (ใหม่ BoxLayout (ProgressPanel, BoxLayout.y_axis)); bar = new JProgressBar (); bar.setMinimum (0); bar.setMaximum (100); ProgressPanel.add (BAR); getContentPane (). setLayout (ใหม่ BorderLayout ()); JPanel btnPanel = new JPanel (Flowlayout ใหม่ (flowlayout.right)); btnpanel.add (startbtn); getContentPane (). เพิ่ม (btnpanel, borderlayout.south); getContentPane (). เพิ่ม (ProgressPanel, BorderLayout.Center); } private void starterver (พอร์ต int) {ลอง {serversocket = ใหม่ serversocket (พอร์ต); System.out.println ("เซิร์ฟเวอร์เริ่มต้นที่พอร์ต:" + พอร์ต); ในขณะที่ (จริง) {ซ็อกเก็ตไคลเอนต์ = serversocket.accept (); // บล็อก & รอสำหรับซ็อกเก็ตรายได้ System.out.println ("เชื่อมต่อกับ" + client.getRemotesocketAddress ()); งาน filereceivetask = ใหม่ filereceivetask (ไคลเอนต์); bar.setValue (0); // รีเซ็ตตอนนี้ task.addpropertychangelistener (ใหม่ PropertyChangelistener () {โมฆะสาธารณะ PropertyChange (PropertyChangeEvent evt) {ถ้า ("ความคืบหน้า" .Equals (evt.getPropertyName ()) {bar.setValue task.execute (); }} catch (ioexception e) {e.printstacktrace (); }} โมฆะสาธารณะ showsuccess () {bar.setValue (100); joptionpane.showmessagedialog (นี่ "ไฟล์ได้รับสำเร็จ!"); } @Override โมฆะสาธารณะ ActionPerformed (ActionEvent E) {ถ้า (start_svr.equals (e.getActionCommand ())) {เธรด startThread = เธรดใหม่ (ใหม่ runnable () {public void run () {starterver (9999);}}); startthread.start (); startbtn.setenabled (เท็จ); } อื่นถ้า (shut_down_svr.equals (e.getActionCommand ())) {} else {// ไม่ทำอะไรเลย ... }} โมฆะคงที่สาธารณะ (สตริง [] args) {fileTransferserver Server = FileTransFerserver ใหม่ (); Server.setDefaultCloseoperation (jframe.exit_on_close); Server.Setsize (400, 400); Server.setResizable (เท็จ); Server.setVisible (จริง); - Filereceivetask เป็นคลาสการยอมรับไฟล์ทางฝั่งเซิร์ฟเวอร์:
ก่อนอื่นรับชื่อไฟล์และขนาดไฟล์จากสตรีม TCP ที่กำหนดไว้แล้วเริ่มรับเนื้อหาไฟล์ไบต์
และเขียนไปยังสตรีมวัตถุไฟล์ที่สร้างขึ้นและในที่สุดก็ตรวจสอบว่าขนาดไฟล์เท่ากับสตรีมไบต์ที่เขียน
สุดท้ายส่งข้อความไปยังผู้ส่งไฟล์เพื่อบอกบุคคลอื่นว่าการถ่ายโอนไฟล์เสร็จสมบูรณ์และสามารถปิดสตรีม TCP ได้
ซอร์สโค้ดที่สมบูรณ์ของคลาสนี้มีดังนี้:
แพ็คเกจ 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 <จำนวนเต็ม, วัตถุ> {ซ็อกเก็ตส่วนตัว _msocket; public filereceivetask (ซ็อกเก็ตไคลเอนต์) {this._msocket = ไคลเอนต์; } @Override การป้องกันจำนวนเต็ม doinbackground () พ่นข้อยกเว้น {// รับไฟล์ข้อมูล meta datainputstream อินพุต = ใหม่ datainputStream (_msocket.getInputStream ()); string filename = input.readutf (); int filelength = (int) input.readlong (); // จำนวนไฟล์ไฟล์ไบต์ทั้งหมด = ไฟล์ใหม่ ("c: // ผู้ใช้ // fish // downloads" + file.separator + ชื่อไฟล์); bufferedOutputStream output = ใหม่ bufferedOutputStream (ใหม่ fileOutputStream (ไฟล์)); System.out.println ("ชื่อไฟล์ที่ได้รับ =" + ชื่อไฟล์); System.out.println ("ขนาดไฟล์ที่ได้รับ =" + filelength/1024 + "kb"); // เริ่มรับเนื้อหาของไฟล์และเขียน byte [] content = byte ใหม่ [2048]; int offset = 0; int numreadbytes = 0; ในขณะที่ (ออฟเซ็ต <filelength && (numreadbytes = input.read (เนื้อหา))> 0) {output.write (เนื้อหา, 0, numreadbytes); float precent = 100.0f * ((ลอย) ออฟเซ็ต)/((ลอย) ความยาว filelength); SetProgress ((int) ที่ถูกต้อง); Offset += numreadbytes; } system.out.println ("numreadbytes =" + numreadbytes); if (Offset <filelength) {numreadbytes = input.read (เนื้อหา); System.out.println ("numreadbytes =" + numreadbytes); System.out.println ("ข้อผิดพลาดเนื้อหาไฟล์ที่ฝั่งเซิร์ฟเวอร์"); } else {system.out.println ("งานที่ได้รับไฟล์ได้ดำเนินการอย่างถูกต้อง"); } setProgress (100); // บอกลูกค้าให้ปิดซ็อกเก็ตตอนนี้เราได้รับไฟล์เรียบร้อยแล้ว !! bufferedWriter bufferedWriter = new BufferedWriter (ใหม่ OutputStreamWriter (_MSOCKET.GETOUTPUTSTREAM ())); bufferedWriter.write ("เสร็จสิ้น/r/n"); bufferedWriter.flush (); // ปิดไฟล์และซ็อกเก็ตเอาต์พุต close (); _msocket.close (); กลับ 100; - ลูกค้า:
FileTransferClient เป็นคลาส UI ของไคลเอนต์ที่ใช้การเชื่อมต่อกับเซิร์ฟเวอร์แล้วเลือก
ไฟล์ที่จะถ่ายโอน (รูปภาพ, PDF, เอกสารคำ ฯลฯ ) ถ้าไม่
ป้อนข้อมูลเซิร์ฟเวอร์และพรอมต์จะปรากฏขึ้น พอร์ตได้รับการระบุเป็น: 9999
ปุ่ม [ส่งไฟล์] จะเปิดกล่องการเลือกไฟล์ หลังจากผู้ใช้เลือกไฟล์ที่จะถ่ายโอนแล้วให้สร้างไฟล์
เธรด filetransfertask และเริ่มดำเนินการโอนไฟล์ รหัส UI ของลูกค้ามีดังนี้:
แพ็คเกจ 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 {/ ** * */ ส่วนตัวคงที่สุดท้าย Long SerialVersionUID = 1L; สตริงคงสุดท้ายสาธารณะ send_cmd = "ส่งไฟล์"; สาธารณะขั้นสุดท้ายสุดท้ายคงที่ขั้นต่ำ = 0; สาธารณะสุดท้ายคงสุดท้ายสูงสุด = 100; // สตริงคงสุดท้ายสาธารณะ connect_cmd = "เชื่อมต่อ"; JButton ส่วนตัว SendFilebtn; ส่วนตัว Jtextfield Serverfield; Private Jtextfield Portfield; แถบ JProgressBar ส่วนตัว; public filetransferclient () {super ("ไคลเอนต์การถ่ายโอนไฟล์"); initcomponents (); } private void initcomponents () {getContentPane (). setLayout (ใหม่ BorderLayout ()); JPanel ProgressPanel = new JPanel (); ProgressPanel.SetLayout (ใหม่ BoxLayout (ProgressPanel, BoxLayout.y_axis); bar = ใหม่ JProgressBar (); progressPanel.add (bar); bar.setMinimum (ขั้นต่ำ); bar.setMaximum (สูงสุด); Gridlayout (2,2,5,5)); ServersettingPanel.Add (ใหม่ Jlabel ("พอร์ตเซิร์ฟเวอร์:"); btnpanel.add (sendfilebtn); @Override โมฆะสาธารณะ ActionPerformed (ActionEvent E) {String Command = E.getActionCommand (); สถานะ = chooser.ShowOpendialog (null); task.addpropertychangelistener (ใหม่ PropertyChangelistener () {โมฆะสาธารณะ PropertyChange (PropertyChangeEvent EVT) {ถ้า ("ความคืบหน้า" .Equals (evt.getPropertyName ()) {bar.setValue (จำนวนเต็ม) Execution}} else {// ไม่ทำอะไรเลย}} โมฆะสาธารณะแสดงให้เห็นว่า () {bar.setValue (100); integer.parseint (portfield.getText (). trim ()); พอร์ตความยาว () == 0) {return true;} ลอง {integer.parseint (พอร์ต); client.setDefaultCloseoperation (jFrame.EXIT_ON_CLOSE); ฟังก์ชั่นหลักที่ใช้โดย filetransfertask คือ:
ซอร์สโค้ดที่สมบูรณ์ของคลาสนี้มีดังนี้:
แพ็คเกจ 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 <จำนวนเต็ม, Object> {ไฟล์ส่วนตัวเลือกไฟล์; ซ็อกเก็ตส่วนตัว msocket; ที่อยู่ซ็อกเก็ตส่วนตัวส่วนตัว ผู้ปกครองภาคเอกชน Public FileTransferTask (ไฟล์ไฟล์, ที่อยู่ SocketAddress, FileTransferClient เจ้าของ /*, JProgressBar ความคืบหน้า* /) {this.address = ที่อยู่; this.selectedFile = ไฟล์; msocket = ซ็อกเก็ตใหม่ (); this.parent = เจ้าของ; } @Override การป้องกันจำนวนเต็ม doinbackground () โยนข้อยกเว้น {// รับขนาดของไฟล์ยาวยาว = selectedFile.length (); if (ความยาว> integer.max_value) {โยน iOexception ใหม่ ("ไม่สามารถอ่านไฟล์ได้อย่างสมบูรณ์" + selectedFile.getName () + "ยาวเกินไป (" + length + "ไบต์สูงสุดรองรับ" + integer.max_value + ")"); } msocket.connect (ที่อยู่); // สร้างอาร์เรย์ไบต์เพื่อเก็บข้อมูลไฟล์ msocket.setsolinger (จริง 60); dataOrtputStream dout = new dataOutputStream (msocket.getOutputStream ()); // ตอนนี้เราเริ่มส่งข้อมูลเมตาไฟล์ dout.writeutf (selectedFile.getName ()); dout.writelong (ความยาว); dout.flush (); // ความคิดเห็นสิ้นสุด filedatapackage pdata = ใหม่ filedatapackage (); datainputStream คือ = ใหม่ datainputStream (ใหม่ FileInputStream (SelectedFile)); ไบต์ [] ไบต์ = ไบต์ใหม่ [2048]; // อ่านใน bytes int offset = 0; int numread = 0; int fsize = (int) ความยาว; ในขณะที่ (ออฟเซ็ต <fsize && (numread = is.read (ไบต์, 0, bytes.length))> = 0) {pdata.setData (ไบต์, numread); dout.write (pdata.getpackagedata (), 0, pdata.getpackagedata (). ความยาว); dout.flush (); ออฟเซ็ต += numread; Float Precent = 100.0f * ((ลอย) ออฟเซ็ต)/((ลอย) fsize); SetProgress ((int) ที่ถูกต้อง); } system.out.println ("รวมส่ง bytes =" + ชดเชย); // ตรวจสอบให้แน่ใจว่าไบต์ทั้งหมดได้รับการอ่านใน if (ออฟเซ็ต <fsize) {โยน iOexception ใหม่ ("ไม่สามารถถ่ายโอนไฟล์ได้อย่างสมบูรณ์" + selectedFile.getName ()); } msocket.shutdownoutput (); // รับการถ่ายโอนไฟล์สำเร็จข้อความจากการเชื่อมต่อ bufferedInputStream streamReader = ใหม่ bufferedInputStream (msocket.getInputStream ()); bufferedReader bufferedReader = ใหม่ bufferedReader (ใหม่ inputStreamReader (streamReader)); สตริง DONEMSG = bufferedReader.ReadLine (); if ("เสร็จสิ้น" .equals (doneemsg)) {parent.showsuccess (); } // ปิดสตรีมอินพุต SetProgress (100); // dout.close (); msocket.close (); is.close (); System.out.println ("ปิดทันที ... "); กลับ 100; -คลาสแพ็คเก็ตมีดังนี้ไม่ได้อธิบาย!
แพ็คเกจ com.gloomyfish.socket.tutorial.filetransfer; / ** * นี่เป็นโปรโตคอลการถ่ายโอนไฟล์ที่ง่ายมากผ่านซ็อกเก็ต TCP */ คลาสสาธารณะ FileDatapackage {ข้อมูลความยาว INT ส่วนตัว; // ความยาวของข้อมูลในแพ็คเก็ตสองไบต์ไบต์ส่วนตัว [] databuff; // ข้อมูลสูงสุดในแพ็คเก็ต Meici จะต้องไม่เกิน 2048 ไบต์ไบต์สุดท้ายคงที่ไบต์สุดท้าย [] eof = ไบต์ใหม่ [] {'e', 'o', 'f'}; Public Filedatapackage () {datalength = 0; databuff = ไบต์ใหม่ [2048]; } ไบต์สาธารณะ [] getPackagedata () {byte [] pData = ไบต์ใหม่ [datalength]; // สิ้นสุดความคิดเห็น System.ArrayCopy (Databuff, 0, PData, 0, Datalength); กลับ pdata; } โมฆะสาธารณะ setData (byte [] ข้อมูล, int bsize) {datalength = bsize; สำหรับ (int i = 0; i <databuff.length; i ++) {ถ้า (i <bsize) {databuff [i] = data [i]; } else {databuff [i] = ''; }}}}จำนวนไบต์สูงสุดที่ส่งต่อเวลาคือ 2048 ไบต์ เอฟเฟกต์การวิ่งครั้งสุดท้ายของโปรแกรมมีดังนี้ (Win7 + JDK6U30):
ข้างต้นเป็นเรื่องเกี่ยวกับบทความนี้ฉันหวังว่ามันจะเป็นประโยชน์กับการเรียนรู้ของทุกคน