瑞斯特總結java socket編程

 

總結java socket編程

一,網絡編程中兩個主要的問題

一個是如何準確的定位網絡上一臺或多臺主機,另一個就是找到主機后如何可靠高效的進行數據傳輸。

TCP/IP協議中IP層主要負責網絡主機的定位,數據傳輸的路由,由IP地址可以唯一地確定Internet上的一臺主機。

TCP層則提供面向應用的可靠(tcp)的或非可靠(UDP)的數據傳輸機制,這是網絡編程的主要對象,一般不需要關心IP層是如何處理數據的。

目前較為流行的網絡編程模型是客戶機/服務器(C/S)結構。即通信雙方一方作為服務器等待客戶提出請求并予以響應。客戶則在需要服務時向服務器提 出申請。服務器一般作為守護進程始終運行,監聽網絡端口,一旦有客戶請求,就會啟動一個服務進程來響應該客戶,同時自己繼續監聽服務端口,使后來的客戶也 能及時得到服務。

二,兩類傳輸協議:TCPUDP

TCP是Tranfer Control Protocol的 簡稱,是一種面向連接的保證可靠傳輸的協議。通過TCP協議傳輸,得到的是一個順序的無差錯的數據流。發送方和接收方的成對的兩個socket之間必須建 立連接,以便在TCP協議的基礎上進行通信,當一個socket(通常都是server socket)等待建立連接時,另一個socket可以要求進行連接,一旦這兩個socket連接起來,它們就可以進行雙向數據傳輸,雙方都可以進行發送 或接收操作。

UDP是User Datagram Protocol的簡稱,是一種無連接的協議,每個數據報都是一個獨立的信息,包括完整的源地址或目的地址,它在網絡上以任何可能的路徑傳往目的地,因此能否到達目的地,到達目的地的時間以及內容的正確性都是不能被保證的。

比較:

UDP1,每個數據報中都給出了完整的地址信息,因此無需要建立發送方和接收方的連接。

            2UDP傳輸數據時是有大小限制的,每個被傳輸的數據報必須限定在64KB之內

           3UDP是一個不可靠的協議,發送方所發送的數據報并不一定以相同的次序到達接收方

TCP1,面向連接的協議,在socket之間進行數據傳輸之前必然要建立連接,所以在TCP中需要連接

                時間。

            2TCP傳輸數據大小限制,一旦連接建立起來,雙方的socket就可以按統一的格式傳輸大的  

                    數據。

             3TCP是一個可靠的協議,它確保接收方完全正確地獲取發送方所發送的全部數據。

應用:

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

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

三,基于Socketjava網絡編程

1,什么是Socket

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

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

2Socket通訊的過程

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

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

  (1) 創建Socket

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

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

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

3,創建Socket

創建Socket

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

  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, InetAddress localAddr, int localPort)

  ServerSocket(int port);

  ServerSocket(int port, int backlog);

  ServerSocket(int port, int backlog, InetAddress bindAddr)

  其中addresshostport分別是雙向連接中另一方的IP地址、主機名和端 口號,stream指明socket是流socket還是數據報socketlocalPort表示本地主機的端口號,localAddr和 bindAddr是本地機器的地址(ServerSocket的主機地址),implsocket的父類,既可以用來創建serverSocket又可 以用來創建Socketcount則表示服務端所能支持的最大連接數。例如:學習視頻網 http://www.xxspw.com

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

  ServerSocket server = new ServerSocket(80);

  注意,在選擇端口時,必須小心。每一個端口提供一種特定的服務,只有給出正確的端口,才 能獲得相應的服務。0~1023的端口號為系統所保留,例如http服務的端口號為80,telnet服務的端口號為21,ftp服務的端口號為23, 所以我們在選擇端口號時,最好選擇一個大于1023的數以防止發生沖突。

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

4,簡單的Client/Server程序

1. 客戶端程序

  import java.io.*;

  import java.net.*;

  public class TalkClient {

    public static void main(String args[]) {

      try{

        Socket socket=new Socket("127.0.0.1",4700);

        //向本機的4700端口發出客戶請求

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

        //由系統標準輸入設備構造BufferedReader對象

        PrintWriter os=new PrintWriter(socket.getOutputStream());

        //Socket對象得到輸出流,并構造PrintWriter對象

        BufferedReader is=new BufferedReader(new InputStreamReader(socket.getInputStream()));

        //Socket對象得到輸入流,并構造相應的BufferedReader對象

        String readline;

        readline=sin.readLine(); //從系統標準輸入讀入一字符串

        while(!readline.equals("bye")){

        //若從標準輸入讀入的字符串為 "bye"則停止循環

          os.println(readline);

          //將從系統標準輸入讀入的字符串輸出到Server

          os.flush();

          //刷新輸出流,使Server馬上收到該字符串

          System.out.println("Client:"+readline);

          //在系統標準輸出上打印讀入的字符串

          System.out.println("Server:"+is.readLine());

          //Server讀入一字符串,并打印到標準輸出上

          readline=sin.readLine(); //從系統標準輸入讀入一字符串

        } //繼續循環

        os.close(); //關閉Socket輸出流

        is.close(); //關閉Socket輸入流

        socket.close(); //關閉Socket

      }catch(Exception e) {

        System.out.println("Error"+e); //出錯,則打印出錯信息

      }

  }

}

 2. 服務器端程序

  import java.io.*;

  import java.net.*;

  import java.applet.Applet;

  public class TalkServer{

    public static void main(String args[]) {

      try{

        ServerSocket server=null;

        try{

          server=new ServerSocket(4700);

        //創建一個ServerSocket在端口4700監聽客戶請求

        }catch(Exception e) {

          System.out.println("can not listen to:"+e);

        //出錯,打印出錯信息

        }

        Socket socket=null;

        try{

          socket=server.accept();

          //使用accept()阻塞等待客戶請求,有客戶

          //請求到來則產生一個Socket對象,并繼續執行

        }catch(Exception e) {

          System.out.println("Error."+e);

          //出錯,打印出錯信息

        }

        String line;

        BufferedReader is=new BufferedReader(new InputStreamReader(socket.getInputStream()));

         //Socket對象得到輸入流,并構造相應的BufferedReader對象

        PrintWriter os=newPrintWriter(socket.getOutputStream());

         //Socket對象得到輸出流,并構造PrintWriter對象

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

         //由系統標準輸入設備構造BufferedReader對象

        System.out.println("Client:"+is.readLine());

        //在標準輸出上打印從客戶端讀入的字符串

        line=sin.readLine();

        //從標準輸入讀入一字符串

        while(!line.equals("bye")){

        //如果該字符串為 "bye",則停止循環

          os.println(line);

          //向客戶端輸出該字符串

          os.flush();

          //刷新輸出流,使Client馬上收到該字符串

          System.out.println("Server:"+line);

          //在系統標準輸出上打印讀入的字符串

          System.out.println("Client:"+is.readLine());

          //Client讀入一字符串,并打印到標準輸出上

          line=sin.readLine();

          //從系統標準輸入讀入一字符串

         //繼續循環

        os.close(); //關閉Socket輸出流

        is.close(); //關閉Socket輸入流

        socket.close(); //關閉Socket

        server.close(); //關閉ServerSocket

      }catch(Exception e){

        System.out.println("Error:"+e);

        //出錯,打印出錯信息

      }

    }

  }

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

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

ServerSocket serverSocket=null;

    boolean listening=true;

    try{

      serverSocket=new ServerSocket(4700);

      //創建一個ServerSocket在端口4700監聽客戶請求

    }catch(IOException e) {  }

    while(listening){ //永遠循環監聽

      new ServerThread(serverSocket.accept(),clientnum).start();

      //監聽到客戶請求,根據得到的Socket對象和

       客戶計數創建服務線程,并啟動之

      clientnum++; //增加客戶計數

    }

    serverSocket.close(); //關閉ServerSocket

設計ServerThread

 public class ServerThread extends Thread{

   Socket socket=null; //保存與本線程相關的Socket對象

   int clientnum; //保存本進程的客戶計數

   public ServerThread(Socket socket,int num) { //構造函數

    this.socket=socket; //初始化socket變量

    clientnum=num+1; //初始化clientnum變量

   }

   public void run() { //線程主體

    try{//在這里實現數據的接受和發送}

四,Datagram通訊

TCP/IP協議的傳輸層除了TCP協議之外還有一個UDP協議,相比而言UDP的應用不如TCP廣泛,幾個標準的應用層協議HTTPFTPSMTP…使用的都是TCP協議。但是,UDP協議可以應用在需要很強的實時交互性的場合,如網絡游戲,視頻會議等。

1,什么是Datagram

數據報(Datagram)就跟日常生活中的郵件系統一樣,是不能保證可靠的寄到的,而面向鏈接的TCP就好比電話,雙方能肯定對方接受到了信息。

TCP,可靠,傳輸大小無限制,但是需要連接建立時間,差錯控制開銷大。

UDP,不可靠,差錯控制開銷較小,傳輸大小限制在64K以下,不需要建立連接。

2Datagram使用

包java.net中提供了兩個類DatagramSocket和DatagramPacket用來支持數據報通信,DatagramSocket用于在程序之間建立傳送數據報的通信連接, DatagramPacket則用來表示一個數據報。

DatagramSocket的構造方法:

           DatagramSocket();

   DatagramSocketint prot;

   DatagramSocket(int port, InetAddress laddr)

其中,port指明socket所使用的端口號,如果未指明端口號,則把socket連接到 本地主機上一個可用的端口。laddr指明一個可用的本地地址。給出端口號時要保證不發生端口沖突,否則會生成SocketException類例外。注 意:上述的兩個構造方法都聲明拋棄非運行時例外SocketException,程序中必須進行處理,或者捕獲、或者聲明拋棄。

   用數據報方式編寫client/server程序時,無論在客戶方還是服務方,首先都要建立一個DatagramSocket對象,用來接收或發送數據報,然后使用DatagramPacket類對象作為傳輸數據的載體。

DatagramPacket的構造方法 :

   DatagramPacketbyte buf[],int length);

   DatagramPacket(byte buf[], int length, InetAddress addr, int port);

   DatagramPacket(byte[] buf, int offset, int length)

   DatagramPacket(byte[] buf, int offset, int length, InetAddress address, int port)

其中,buf中存放數據報數據,length為數據報中數據的長度,addrport旨明目的地址,offset指明了數據報的位移量。

在接收數據前,應該采用上面的第一種方法生成一個DatagramPacket對象,給出接收數據的緩沖區及其長度。然后調用DatagramSocket 的方法receive()等待數據報的到來,receive()將一直等待,直到收到一個數據報為止。

  DatagramPacket packet=new DatagramPacket(buf, 256);

  Socket.receive (packet);

發送數據前,也要先生成一個新的DatagramPacket對象,這時要使用上面的第二種 構造方法,在給出存放發送數據的緩沖區的同時,還要給出完整的目的地址,包括IP地址和端口號。發送數據是通過DatagramSocket的方法 send()實現的,send()根據數據報的目的地址來尋徑,以傳遞數據報。

  DatagramPacket packet=new DatagramPacket(buf, length, address, port);

  Socket.send(packet)

   在構造數據報時,要給出InetAddress類參數。類InetAddress在包java.net中定義,用來表示一個Internet地址,我們可 以通過它提供的類方法getByName()從一個表示主機名的字符串獲取該主機的IP地址,然后再獲取相應的地址信息。

3,用Datagram進行廣播通訊(MulticastSocket

DatagramSocket只允許數據報發送一個目的地址,java.net包中提供了一個類MulticastSocket,允許數據報以廣播方式發送到該端口的所有客戶。MulticastSocket用在客戶端,監聽服務器廣播來的數據。

1. 客戶方程序:MulticastClient.java

  import java.io.*;

  import java.net.*;

  import java.util.*;

  public class MulticastClient {

    public static void main(String args[]) throws IOException

    {

     MulticastSocket socket=new MulticastSocket(4446);

     //創建4446端口的廣播套接字

     InetAddress address=InetAddress.getByName("230.0.0.1");

     //得到230.0.0.1的地址信息

     socket.joinGroup(address);

     //使用joinGroup()將廣播套接字綁定到地址上

     DatagramPacket packet;

     for(int i=0;i<5;i++) {

       byte[] buf=new byte[256];

       //創建緩沖區

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

       //創建接收數據報

       socket.receive(packet); //接收

       String received=new String(packet.getData());

       //由接收到的數據報得到字節數組,

       //并由此構造一個String對象

       System.out.println("Quote of theMoment:"+received);

       //打印得到的字符串

     } //循環5

     socket.leaveGroup(address);

     //把廣播套接字從地址上解除綁定

     socket.close(); //關閉廣播套接字

   }

 }

 2. 服務器方程序:MulticastServer.java

  public class MulticastServer{

    public static void main(String args[]) throws java.io.IOException

    {

      new MulticastServerThread().start();

      //啟動一個服務器線程

    }

  }

 3. 程序MulticastServerThread.java

  import java.io.*;

  import java.net.*;

  import java.util.*;

  public class MulticastServerThread extends QuoteServerThread

  //QuoteServerThread繼承得到新的服務器線程類MulticastServerThread

  {

    Private long FIVE_SECOND=5000; //定義常量,5秒鐘

    public MulticastServerThread(String name) throws IOException

    {

      super("MulticastServerThread");

      //調用父類,也就是QuoteServerThread的構造函數

    }

    public void run() //重寫父類的線程主體

    {

     while(moreQuotes) {

     //根據標志變量判斷是否繼續循環

      try{

        byte[] buf=new byte[256];

        //創建緩沖區

        String dString=null;

        if(in==null) dString=new Date().toString();

        //如果初始化的時候打開文件失敗了,

        //則使用日期作為要傳送的字符串

        else dString=getNextQuote();

        //否則調用成員函數從文件中讀出字符串

        buf=dString.getByte();

        //String轉換成字節數組,以便傳送send it

        InetAddress group=InetAddress.getByName("230.0.0.1");

        //得到230.0.0.1的地址信息

        DatagramPacket packet=new DatagramPacket(buf,buf.length,group,4446);

        //根據緩沖區,廣播地址,和端口號創建DatagramPacket對象

        socket.send(packet); //發送該Packet

        try{

          sleep((long)(Math.random()*FIVE_SECONDS));

          //隨機等待一段時間,05秒之間

        }catch(InterruptedException e) { } //異常處理

      }catch(IOException e){ //異常處理

        e.printStackTrace( ); //打印錯誤棧

        moreQuotes=false; //置結束循環標志

      }

    }

    socket.close( ); //關閉廣播套接口

   }

 }

發表評論

 




 

哈努曼与假面五骑士
上期六台彩开奖特马是多少 三分彩开奖查询 北京pk10开奖视频直播 云南快了十分开奖结果查询结果 山西快乐十分走势图50期 上海时时为何停售 北京十一选五走势手机版 云南时时彩开奖号 如何看懂快3走势图 一肖一码期期中特资料 甘肃福彩快3开奖走势图 福州十三水玩法 广东十分快乐开奖助手 天津福彩20分开奖结果 pk10高手赌法长期 浙江体彩大乐透走势图1