java網絡編程

UDP:

a)        將數據及源和目的封裝成數據包中,不需要建立連接

b)        每個數據報的大小限制在64K內

c)        因無連接,是不可靠協議

d)        不需要建立連接,速度快

TCP:

a)        建立連接,形成傳輸數據的通道

b)        在連接中進行大數據傳輸

c)        通過三次握手完成連接,是可靠協議


應用:

1,TCP在網絡通信上有極強的生命力,例如遠程連接(Telnet)和文件傳輸(FTP)都需要不定長度的數據被可靠地傳輸。但是可靠的傳輸是要付出代價的,對數據內容正確性的檢驗必然佔用計算機的處理時間和網絡的帶寬,因此TCP傳輸的效率不如UDP

2,UDP操作簡單,而且僅需要較少的監護,因此通常用於局域網高可靠性的分散系統中client/server應用程序。例如視頻會議系統,並不要求音頻視頻數據絕對的正確,只要保證連貫性就可以了,這種情況下顯然使用UDP會更合理一些。

基於Socket的java網絡編程

a)        就是爲網絡服務提供的一種機制

b)        通信的兩端都有Socket

c)        網絡通信其實就是socket間的通信

d)        數據在2個Socket間通過IO傳輸

 

1,什麼是Socket

網絡上的兩個程序通過一個雙向的通訊連接實現數據的交換,這個雙向鏈路的一端稱爲一個Socket。Socket通常用來實現客戶方和服務方的連接。Socket是TCP/IP協議的一個十分流行的編程界面,一個Socket由一個IP地址和一個端口號唯一確定。

但是,Socket所支持的協議種類也不光TCP/IP一種,因此兩者之間是沒有必然聯繫的。在Java環境下,Socket編程主要是指基於TCP/IP協議的網絡編程。

2,Socket通訊的過程

Server端Listen(監聽)某個端口是否有連接請求,Client端向Server 端發出Connect(連接)請求,Server端向Client端發回Accept(接受)消息。一個連接就建立起來了。Server端和Client 端都可以通過Send,Write等方法與對方通信。

對於一個功能齊全的Socket,都要包含以下基本結構,其工作過程包含以下四個基本的步驟:

  (1) 創建Socket;

  (2) 打開連接到Socket的輸入/出流;

  (3) 按照一定的協議對Socket進行讀/寫操作;

  (4) 關閉Socket.(在實際應用中,並未使用到顯示的close,雖然很多文章都推薦如此,不過在我的程序中,可能因爲程序本身比較簡單,要求不高,所以並未造成什麼影響。)

3,創建Socket

創建Socket

java在包java.net中提供了兩個類Socket和ServerSocket,分別用來表示雙向連接的客戶端和服務端。這是兩個封裝得非常好的類,使用很方便。其構造方法如下:

  Socket(InetAddress address, int port);

  Socket(InetAddress address, int port, boolean stream);

  Socket(String host, int prot);

  Socket(String host, int prot, boolean stream);

  Socket(SocketImpl impl)

  Socket(String host, int port, InetAddress localAddr,int localPort)

  Socket(InetAddress address, int port, InetAddresslocalAddr, int localPort)

  ServerSocket(int port);

  ServerSocket(int port, int backlog);

  ServerSocket(int port, int backlog, InetAddressbindAddr)

  其中address、host和port分別是雙向連接中另一方的IP地址、主機名和端口號,stream指明socket是流socket還是數據報socket,localPort表示本地主機的端口號,localAddr和 bindAddr是本地機器的地址(ServerSocket的主機地址),impl是socket的父類,既可以用來創建serverSocket又可 以用來創建Socket。count則表示服務端所能支持的最大連接數。

  Socket client = new Socket("127.0.01.", 80);

  ServerSocket server = new ServerSocket(80);

  注意,在選擇端口時,必須小心。每一個端口提供一種特定的服務,只有給出正確的端口,才 能獲得相應的服務。0~1023的端口號爲系統所保留,例如http服務的端口號爲80,telnet服務的端口號爲21,ftp服務的端口號爲23, 所以我們在選擇端口號時,最好選擇一個大於1023的數以防止發生衝突。端口範圍:0-65535,其中0~1024系統使用或保留端口

  在創建socket時如果發生錯誤,將產生IOException,在程序中必須對之作出處理。所以在創建Socket或ServerSocket是必須捕獲或拋出例外。

4,支持多客戶的client/server程序

前面的Client/Server程序只能實現Server和一個客戶的對話。在實際應用 中,往往是在服務器上運行一個永久的程序,它可以接收來自其他多個客戶端的請求,提供相應的服務。爲了實現在服務器方給多個客戶提供服務的功能,需要對上 面的程序進行改造,利用多線程實現多客戶機制。服務器總是在指定的端口上監聽是否有客戶請求,一旦監聽到客戶請求,服務器就會啓動一個專門的服務線程來響 應該客戶的請求,而服務器本身在啓動完線程之後馬上又進入監聽狀態,等待下一個客戶的到來。

5,簡單的Client/Server程序

獲得指定url的ip地址及名字

package com.wj.ip;

 

import java.net.InetAddress;

import java.net.UnknownHostException;

/**

 * 得到ip地址

 * @author wJing

 * time:2014/2/9

 */

public class IPDemo1 {

   /**

    *

    * @param args

    * @throws Exception

    */

   public staticvoid main(String[] args) throws Exception {

       InetAddress i= InetAddress.getLocalHost();

       System.out.println(i.toString());

       System.out.println(i.getHostName());

       System.out.println(i.getHostAddress());

      

       InetAddressia = InetAddress.getByName("127.0.0.1");

       System.out.println("address:"+ia.getHostAddress());

       System.out.println("ip:"+ ia.getHostName());

   }

}

簡單的Client(發送文本):

package com.wj.client;

 

import java.io.BufferedReader;

import java.io.DataOutputStream;

import java.io.FileReader;

import java.io.IOException;

import java.io.InputStreamReader;

import java.io.PrintWriter;

import java.net.Socket;

 

/**

 *

 * @author wJing

 * time:2014-2-915:09:54

 * 把客戶端的一個文件傳遞到服務端,模擬

 */

public class TextClient {

 

   public staticvoid main(String[] args) throws Exception, IOException {

       Socket s =new Socket("localhost", 9999);

      

       BufferedReaderbuf = new BufferedReader(new FileReader("d:\\abcde.txt"));

      

       PrintWriterwriter = new PrintWriter(s.getOutputStream(),true);

      

       /*

       /////////////////////////////////////////////////////////////////

       //時間戳,確定文件的結束標記

       DataOutputStreamdos = new DataOutputStream(s.getOutputStream());

       long time =System.currentTimeMillis();

       dos.writeLong(time);

      

       ////////////////////////////////////////////////////////////////

      

       */

      

      

       String line =null;

      

       while((line =buf.readLine()) != null) {

          writer.println(line);

       }

       //關閉客戶端輸出流

      

       s.shutdownOutput();

      

      

       ////////////////////////////////////////////////////////

//     writer.println(time);//文件讀完以後再發一次時間戳

       ///////////////////////////////////////////////////////////

       BufferedReaderin = new BufferedReader(new InputStreamReader(s.getInputStream()));

       String str =in.readLine();

       System.out.println(str);

      

       buf.close();

       s.close();

   }

 

}

簡單的Server(接收文本):

package com.wj.server;

 

import java.io.BufferedReader;

import java.io.DataInputStream;

import java.io.FileWriter;

import java.io.InputStreamReader;

import java.io.PrintWriter;

import java.net.ServerSocket;

import java.net.Socket;

 

public class TextServer {

 

   public staticvoid main(String[] args) throws Exception {

       ServerSocketss = new ServerSocket(9999);

       Socket s =ss.accept();

      

       BufferedReaderbufIn = new BufferedReader(new InputStreamReader(s.getInputStream()));

      

       PrintWriterin = new PrintWriter(new FileWriter("e://copy.txt"),true);

      

       /**

        *

       ///////////////////////////////////////////////////////////

       DataInputStreamdis = new DataInputStream(s.getInputStream());

       long time =dis.readLong();

       ///////////////////////////////////////////////////////////

      

       /**

        * 方式1:發送一個標記給服務器

        * 方式2:使用時間戳當作一個標記

        * 方式3:使用socket的shutdowninput、shutdownoutput

        */

      

      

       String line =null;

       while((line =bufIn.readLine()) != null) {

//        if(line.equals(time)){

//            break;

//        }

          in.println(line);

       }

      

       PrintWriterout = new PrintWriter(s.getOutputStream(), true);

       out.println("上傳成功");

      

       in.close();

       s.close();

       ss.close();

   }

 

}

簡單的Client(發送圖片):

package com.wj.client;

 

import java.io.FileInputStream;

import java.io.IOException;

import java.io.InputStream;

import java.io.OutputStream;

import java.net.Socket;

import java.net.UnknownHostException;

 

/**

 *

 * @author wJing

 * time:2014-2-916:38:57

 * 上次圖片

 */

public class ImageClient {

 

   public staticvoid main(String[] args) throws Exception, IOException {

       Socket s =new Socket("localhost", 1520);

       FileInputStreamfis = new FileInputStream("d:\\1.jpg");

      

       OutputStreamout = s.getOutputStream();

      

       byte[] buf =new byte[1024];

      

       int len = 0;

      

       while((len =fis.read(buf)) != -1) {

          out.write(buf,0, len);

       }

      

       //告訴服務器數據已寫完

       s.shutdownOutput();

      

       InputStreamin = s.getInputStream();

       byte[] bufIn= new byte[1024];

       int num =in.read(bufIn);

      

       System.out.println(newString(bufIn, 0, num));

      

       fis.close();

       s.close();

   }

 

}

簡單的Server(接收圖片)

package com.wj.server;

 

import java.io.File;

import java.io.FileNotFoundException;

import java.io.FileOutputStream;

import java.io.IOException;

import java.io.InputStream;

import java.io.OutputStream;

import java.net.ServerSocket;

import java.net.Socket;

 

class picThread implements Runnable {

   private Socket s;

   publicpicThread(Socket s) {

       this.s = s;

   }

   @Override

   public void run(){

       int count =1;

       String ip =s.getInetAddress().getAddress().toString();

       System.out.println(ip+ ".....connected");

       try {

       InputStreamin = s.getInputStream();

      

       File file =new File(ip+count + ".jpg");

       while(file.exists()){

          file = newFile(ip + "(" + count++ + ").jpg");

       }

 

       FileOutputStreamfos = new FileOutputStream(file);

 

       byte[] buf =new byte[1024];

       int len = 0;

       while((len =in.read(buf)) != -1) {

          fos.write(buf,0, len);

       }

 

       OutputStreamout = s.getOutputStream();

       out.write("上次成功".getBytes());

 

       fos.close();

       s.close();

       }catch(Exception e) {

          throw newRuntimeException(ip + "上傳失敗");

       }

   }

 

}

 

public class ImageServer {

   public staticvoid main(String[] args) throws Exception {

       //  UploadPic();

 

 

       //使用多線程處理多個客戶端的訪問

       ServerSocketss = new ServerSocket(1520);

       while(true) {

          Socket s =ss.accept();

          newThread(new picThread(s)).start();

       }

   }

 

 

   //先線程的圖片上傳,一個客戶端連上以後只有等爲他服務完成以後才能爲下一個人服務

   private staticvoid UploadPic() throws IOException, FileNotFoundException {

       ServerSocketss = new ServerSocket(1520);

       //     while(true) {

       Socket s =ss.accept();

 

       InputStreamin = s.getInputStream();

 

       FileOutputStreamfos = new FileOutputStream("e:\\server.jpg");

 

       byte[] buf =new byte[1024];

       int len = 0;

       while((len =in.read(buf)) != -1) {

          fos.write(buf,0, len);

       }

 

       OutputStreamout = s.getOutputStream();

       out.write("上次成功".getBytes());

 

       fos.close();

       s.close();

       //     }

       ss.close();

   }

}

 

 

 

 

 

一個基於UDP的簡單聊天程序:

package com.wj.udp;

 

import java.io.BufferedReader;

import java.io.IOException;

import java.io.InputStreamReader;

import java.net.DatagramPacket;

import java.net.DatagramSocket;

import java.net.InetAddress;

import java.net.SocketException;

 

/**

 *

 * @author wJing

 *編寫一個聊天程序

 *time:2014-2-9 11:33:20

 */

 

class Send implements Runnable {

   privateDatagramSocket ds;

  

   publicSend(DatagramSocket ds) {

       this.ds = ds;

   }

  

   @Override

   public void run(){

      

       try {

          BufferedReaderin = new BufferedReader(new InputStreamReader(System.in));

          Stringline = null;

          while((line= in.readLine()) != null) {

              if("886".equals(line)){

                 break;

              }

              byte[] buf = line.getBytes();

              DatagramPacketdp = new DatagramPacket(buf, buf.length,InetAddress.getByName("localhost"), 10002);

              ds.send(dp);

          }

       } catch(Exception e) {

          throw newRuntimeException("發送端失敗");

       }

   }

  

}

 

class Receive implements Runnable {

   private DatagramSocketds;

  

   publicReceive(DatagramSocket ds) {

       this.ds = ds;

   }

   @Override

   public void run(){

       try {

          while(true){

              byte[]buf = new byte[1024 * 64];

              DatagramPacketdp = new DatagramPacket(buf, buf.length);

              ds.receive(dp);

             

              Stringip = dp.getAddress().getHostAddress();

              Stringdata = new String(dp.getData(), 0, dp.getLength());

              System.out.println("ip->"+ ip + ":" + data);

          }

       } catch(Exception e) {

          throw newRuntimeException("接收失敗");

       }

   }

  

}

 

public class ChatDemo {

 

   public staticvoid main(String[] args) throws Exception {

       DatagramSocketsendSocket = new DatagramSocket();

       DatagramSocketreceiveSocket = new DatagramSocket(10002);

      

       newThread(new Send(sendSocket)).run();

       newThread(new Receive(receiveSocket)).run();

   }

 

}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章