<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    休息食客

    隨心而動(dòng)

      BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
      16 隨筆 :: 7 文章 :: 2 評論 :: 0 Trackbacks
    聲明:本文轉(zhuǎn)自http://haohaoxuexi.iteye.com/blog/1979

    Java Socket編程

           對于Java Socket編程而言,有兩個(gè)概念,一個(gè)是ServerSocket,一個(gè)是Socket。服務(wù)端和客戶端之間通過Socket建立連接,之后它們就可以進(jìn)行通信了。首先ServerSocket將在服務(wù)端監(jiān)聽某個(gè)端口,當(dāng)發(fā)現(xiàn)客戶端有Socket來試圖連接它時(shí),它會(huì)acceptSocket的連接請求,同時(shí)在服務(wù)端建立一個(gè)對應(yīng)的Socket與之進(jìn)行通信。這樣就有兩個(gè)Socket了,客戶端和服務(wù)端各一個(gè)。

           對于Socket之間的通信其實(shí)很簡單,服務(wù)端往Socket的輸出流里面寫東西,客戶端就可以通過Socket的輸入流讀取對應(yīng)的內(nèi)容。SocketSocket之間是雙向連通的,所以客戶端也可以往對應(yīng)的Socket輸出流里面寫東西,然后服務(wù)端對應(yīng)的Socket的輸入流就可以讀出對應(yīng)的內(nèi)容。下面來看一些服務(wù)端與客戶端通信的例子:

          1、客戶端寫服務(wù)端讀

           服務(wù)端代碼

    1. public class Server { 
    2.   
    3.    public static void main(String args[]) throws IOException { 
    4.       //為了簡單起見,所有的異常信息都往外拋 
    5.       int port = 8899; 
    6.       //定義一個(gè)ServerSocket監(jiān)聽在端口8899上 
    7.       ServerSocket server = new ServerSocket(port); 
    8.       //server嘗試接收其他Socket的連接請求,server的accept方法是阻塞式的 
    9.       Socket socket = server.accept(); 
    10.       //跟客戶端建立好連接之后,我們就可以獲取socket的InputStream,并從中讀取客戶端發(fā)過來的信息了。 
    11.       Reader reader = new InputStreamReader(socket.getInputStream()); 
    12.       char chars[] = new char[64]; 
    13.       int len; 
    14.       StringBuilder sb = new StringBuilder(); 
    15.       while ((len=reader.read(chars)) != -1) { 
    16.          sb.append(new String(chars, 0, len)); 
    17.       } 
    18.       System.out.println("from client: " + sb); 
    19.       reader.close(); 
    20.       socket.close(); 
    21.       server.close(); 
    22.    } 
    23.     
    public class Server {
     
       public static void main(String args[]) throws IOException {
          //為了簡單起見,所有的異常信息都往外拋
          int port = 8899;
          //定義一個(gè)ServerSocket監(jiān)聽在端口8899上
          ServerSocket server = new ServerSocket(port);
          //server嘗試接收其他Socket的連接請求,server的accept方法是阻塞式的
          Socket socket = server.accept();
          //跟客戶端建立好連接之后,我們就可以獲取socket的InputStream,并從中讀取客戶端發(fā)過來的信息了。
          Reader reader = new InputStreamReader(socket.getInputStream());
          char chars[] = new char[64];
          int len;
          StringBuilder sb = new StringBuilder();
          while ((len=reader.read(chars)) != -1) {
             sb.append(new String(chars, 0, len));
          }
          System.out.println("from client: " + sb);
          reader.close();
          socket.close();
          server.close();
       }
       
    }
    

           

    服務(wù)端從SocketInputStream中讀取數(shù)據(jù)的操作也是阻塞式的,如果從輸入流中沒有讀取到數(shù)據(jù)程序會(huì)一直在那里不動(dòng),直到客戶端往Socket的輸出流中寫入了數(shù)據(jù),或關(guān)閉了Socket的輸出流。當(dāng)然,對于客戶端的Socket也是同樣如此。在操作完以后,整個(gè)程序結(jié)束前記得關(guān)閉對應(yīng)的資源,即關(guān)閉對應(yīng)的IO流和Socket。

           客戶端代碼

    1. public class Client { 
    2.   
    3.    public static void main(String args[]) throws Exception { 
    4.       //為了簡單起見,所有的異常都直接往外拋 
    5.       String host = "127.0.0.1";  //要連接的服務(wù)端IP地址 
    6.       int port = 8899;   //要連接的服務(wù)端對應(yīng)的監(jiān)聽端口 
    7.       //與服務(wù)端建立連接 
    8.       Socket client = new Socket(host, port); 
    9.       //建立連接后就可以往服務(wù)端寫數(shù)據(jù)了 
    10.       Writer writer = new OutputStreamWriter(client.getOutputStream()); 
    11.       writer.write("Hello Server."); 
    12.       writer.flush();//寫完后要記得flush 
    13.       writer.close(); 
    14.       client.close(); 
    15.    } 
    16.     
    public class Client {
     
       public static void main(String args[]) throws Exception {
          //為了簡單起見,所有的異常都直接往外拋
          String host = "127.0.0.1";  //要連接的服務(wù)端IP地址
          int port = 8899;   //要連接的服務(wù)端對應(yīng)的監(jiān)聽端口
          //與服務(wù)端建立連接
          Socket client = new Socket(host, port);
          //建立連接后就可以往服務(wù)端寫數(shù)據(jù)了
          Writer writer = new OutputStreamWriter(client.getOutputStream());
          writer.write("Hello Server.");
          writer.flush();//寫完后要記得flush
          writer.close();
          client.close();
       }
       
    }

          

    對于客戶端往Socket的輸出流里面寫數(shù)據(jù)傳遞給服務(wù)端要注意一點(diǎn),如果寫操作之后程序不是對應(yīng)著輸出流的關(guān)閉,而是進(jìn)行其他阻塞式的操作(比如從輸入流里面讀數(shù)據(jù)),記住要flush一下,只有這樣服務(wù)端才能收到客戶端發(fā)送的數(shù)據(jù),否則可能會(huì)引起兩邊無限的互相等待。在稍后講到客戶端和服務(wù)端同時(shí)讀和寫的時(shí)候會(huì)說到這個(gè)問題。

          2、客戶端和服務(wù)端同時(shí)讀和寫

           前面已經(jīng)說了Socket之間是雙向通信的,它既可以接收數(shù)據(jù),同時(shí)也可以發(fā)送數(shù)據(jù)。

           服務(wù)端代碼

    1. public class Server { 
    2.   
    3.    public static void main(String args[]) throws IOException { 
    4.       //為了簡單起見,所有的異常信息都往外拋 
    5.       int port = 8899; 
    6.       //定義一個(gè)ServerSocket監(jiān)聽在端口8899上 
    7.       ServerSocket server = new ServerSocket(port); 
    8.       //server嘗試接收其他Socket的連接請求,server的accept方法是阻塞式的 
    9.       Socket socket = server.accept(); 
    10.       //跟客戶端建立好連接之后,我們就可以獲取socket的InputStream,并從中讀取客戶端發(fā)過來的信息了。 
    11.       Reader reader = new InputStreamReader(socket.getInputStream()); 
    12.       char chars[] = new char[64]; 
    13.       int len; 
    14.       StringBuilder sb = new StringBuilder(); 
    15.       while ((len=reader.read(chars)) != -1) { 
    16.          sb.append(new String(chars, 0, len)); 
    17.       } 
    18.       System.out.println("from client: " + sb); 
    19.       //讀完后寫一句 
    20.       Writer writer = new OutputStreamWriter(socket.getOutputStream()); 
    21.       writer.write("Hello Client."); 
    22.       writer.flush(); 
    23.       writer.close(); 
    24.       reader.close(); 
    25.       socket.close(); 
    26.       server.close(); 
    27.    } 
    28.     
    public class Server {
     
       public static void main(String args[]) throws IOException {
          //為了簡單起見,所有的異常信息都往外拋
          int port = 8899;
          //定義一個(gè)ServerSocket監(jiān)聽在端口8899上
          ServerSocket server = new ServerSocket(port);
          //server嘗試接收其他Socket的連接請求,server的accept方法是阻塞式的
          Socket socket = server.accept();
          //跟客戶端建立好連接之后,我們就可以獲取socket的InputStream,并從中讀取客戶端發(fā)過來的信息了。
          Reader reader = new InputStreamReader(socket.getInputStream());
          char chars[] = new char[64];
          int len;
          StringBuilder sb = new StringBuilder();
          while ((len=reader.read(chars)) != -1) {
             sb.append(new String(chars, 0, len));
          }
          System.out.println("from client: " + sb);
          //讀完后寫一句
          Writer writer = new OutputStreamWriter(socket.getOutputStream());
          writer.write("Hello Client.");
          writer.flush();
          writer.close();
          reader.close();
          socket.close();
          server.close();
       }
       
    }
    

           

    在上述代碼中首先我們從輸入流中讀取客戶端發(fā)送過來的數(shù)據(jù),接下來我們再往輸出流里面寫入數(shù)據(jù)給客戶端,接下來關(guān)閉對應(yīng)的資源文件。而實(shí)際上上述代碼可能并不會(huì)按照我們預(yù)先設(shè)想的方式運(yùn)行,因?yàn)閺妮斎肓髦凶x取數(shù)據(jù)是一個(gè)阻塞式操作,在上述的while循環(huán)中當(dāng)讀到數(shù)據(jù)的時(shí)候就會(huì)執(zhí)行循環(huán)體,否則就會(huì)阻塞,這樣后面的寫操作就永遠(yuǎn)都執(zhí)行不了了。除非客戶端對應(yīng)的Socket關(guān)閉了阻塞才會(huì)停止,while循環(huán)也會(huì)跳出。針對這種可能永遠(yuǎn)無法執(zhí)行下去的情況的解決方法是while循環(huán)需要在里面有條件的跳出來,縱觀上述代碼,在不斷變化的也只有取到的長度len和讀到的數(shù)據(jù)了,len已經(jīng)是不能用的了,唯一能用的就是讀到的數(shù)據(jù)了。針對這種情況,通常我們都會(huì)約定一個(gè)結(jié)束標(biāo)記,當(dāng)客戶端發(fā)送過來的數(shù)據(jù)包含某個(gè)結(jié)束標(biāo)記時(shí)就說明當(dāng)前的數(shù)據(jù)已經(jīng)發(fā)送完畢了,這個(gè)時(shí)候我們就可以進(jìn)行循環(huán)的跳出了。那么改進(jìn)后的代碼會(huì)是這個(gè)樣子:

    1. public class Server { 
    2.   
    3.    public static void main(String args[]) throws IOException { 
    4.       //為了簡單起見,所有的異常信息都往外拋 
    5.       int port = 8899; 
    6.       //定義一個(gè)ServerSocket監(jiān)聽在端口8899上 
    7.       ServerSocket server = new ServerSocket(port); 
    8.       //server嘗試接收其他Socket的連接請求,server的accept方法是阻塞式的 
    9.       Socket socket = server.accept(); 
    10.       //跟客戶端建立好連接之后,我們就可以獲取socket的InputStream,并從中讀取客戶端發(fā)過來的信息了。 
    11.       Reader reader = new InputStreamReader(socket.getInputStream()); 
    12.       char chars[] = new char[64]; 
    13.       int len; 
    14.       StringBuilder sb = new StringBuilder(); 
    15.       String temp; 
    16.       int index; 
    17.       while ((len=reader.read(chars)) != -1) { 
    18.          temp = new String(chars, 0, len); 
    19.          if ((index = temp.indexOf("eof")) != -1) {//遇到eof時(shí)就結(jié)束接收 
    20.             sb.append(temp.substring(0, index)); 
    21.             break; 
    22.          } 
    23.          sb.append(temp); 
    24.       } 
    25.       System.out.println("from client: " + sb); 
    26.       //讀完后寫一句 
    27.       Writer writer = new OutputStreamWriter(socket.getOutputStream()); 
    28.       writer.write("Hello Client."); 
    29.       writer.flush(); 
    30.       writer.close(); 
    31.       reader.close(); 
    32.       socket.close(); 
    33.       server.close(); 
    34.    } 
    35.     
    public class Server {
     
       public static void main(String args[]) throws IOException {
          //為了簡單起見,所有的異常信息都往外拋
          int port = 8899;
          //定義一個(gè)ServerSocket監(jiān)聽在端口8899上
          ServerSocket server = new ServerSocket(port);
          //server嘗試接收其他Socket的連接請求,server的accept方法是阻塞式的
          Socket socket = server.accept();
          //跟客戶端建立好連接之后,我們就可以獲取socket的InputStream,并從中讀取客戶端發(fā)過來的信息了。
          Reader reader = new InputStreamReader(socket.getInputStream());
          char chars[] = new char[64];
          int len;
          StringBuilder sb = new StringBuilder();
          String temp;
          int index;
          while ((len=reader.read(chars)) != -1) {
             temp = new String(chars, 0, len);
             if ((index = temp.indexOf("eof")) != -1) {//遇到eof時(shí)就結(jié)束接收
                sb.append(temp.substring(0, index));
                break;
             }
             sb.append(temp);
          }
          System.out.println("from client: " + sb);
          //讀完后寫一句
          Writer writer = new OutputStreamWriter(socket.getOutputStream());
          writer.write("Hello Client.");
          writer.flush();
          writer.close();
          reader.close();
          socket.close();
          server.close();
       }
       
    }
    
    

          

    在上述代碼中,當(dāng)服務(wù)端讀取到客戶端發(fā)送的結(jié)束標(biāo)記,即“eof”時(shí)就會(huì)結(jié)束數(shù)據(jù)的接收,終止循環(huán),這樣后續(xù)的代碼又可以繼續(xù)進(jìn)行了。

           客戶端代碼

    1. public class Client { 
    2.   
    3.    public static void main(String args[]) throws Exception { 
    4.       //為了簡單起見,所有的異常都直接往外拋 
    5.      String host = "127.0.0.1";  //要連接的服務(wù)端IP地址 
    6.      int port = 8899;   //要連接的服務(wù)端對應(yīng)的監(jiān)聽端口 
    7.      //與服務(wù)端建立連接 
    8.      Socket client = new Socket(host, port); 
    9.       //建立連接后就可以往服務(wù)端寫數(shù)據(jù)了 
    10.      Writer writer = new OutputStreamWriter(client.getOutputStream()); 
    11.       writer.write("Hello Server."); 
    12.       writer.flush(); 
    13.       //寫完以后進(jìn)行讀操作 
    14.      Reader reader = new InputStreamReader(client.getInputStream()); 
    15.       char chars[] = new char[64]; 
    16.       int len; 
    17.       StringBuffer sb = new StringBuffer(); 
    18.       while ((len=reader.read(chars)) != -1) { 
    19.          sb.append(new String(chars, 0, len)); 
    20.       } 
    21.       System.out.println("from server: " + sb); 
    22.       writer.close(); 
    23.       reader.close(); 
    24.       client.close(); 
    25.    } 
    26.     
    public class Client {
     
       public static void main(String args[]) throws Exception {
          //為了簡單起見,所有的異常都直接往外拋
         String host = "127.0.0.1";  //要連接的服務(wù)端IP地址
         int port = 8899;   //要連接的服務(wù)端對應(yīng)的監(jiān)聽端口
         //與服務(wù)端建立連接
         Socket client = new Socket(host, port);
          //建立連接后就可以往服務(wù)端寫數(shù)據(jù)了
         Writer writer = new OutputStreamWriter(client.getOutputStream());
          writer.write("Hello Server.");
          writer.flush();
          //寫完以后進(jìn)行讀操作
         Reader reader = new InputStreamReader(client.getInputStream());
          char chars[] = new char[64];
          int len;
          StringBuffer sb = new StringBuffer();
          while ((len=reader.read(chars)) != -1) {
             sb.append(new String(chars, 0, len));
          }
          System.out.println("from server: " + sb);
          writer.close();
          reader.close();
          client.close();
       }
       
    }
    
    

          

    在上述代碼中我們先是給服務(wù)端發(fā)送了一段數(shù)據(jù),之后讀取服務(wù)端返回來的數(shù)據(jù),跟之前的服務(wù)端一樣在讀的過程中有可能導(dǎo)致程序一直掛在那里,永遠(yuǎn)跳不出while循環(huán)。這段代碼配合服務(wù)端的第一段代碼就正好讓我們分析服務(wù)端永遠(yuǎn)在那里接收數(shù)據(jù),永遠(yuǎn)跳不出while循環(huán),也就沒有之后的服務(wù)端返回?cái)?shù)據(jù)給客戶端,客戶端也就不可能接收到服務(wù)端返回的數(shù)據(jù)。解決方法如服務(wù)端第二段代碼所示,在客戶端發(fā)送數(shù)據(jù)完畢后,往輸出流里面寫入結(jié)束標(biāo)記告訴服務(wù)端數(shù)據(jù)已經(jīng)發(fā)送完畢了,同樣服務(wù)端返回?cái)?shù)據(jù)完畢后也發(fā)一個(gè)標(biāo)記告訴客戶端。那么修改后的客戶端代碼就應(yīng)該是這個(gè)樣子:
    1. public class Client { 
    2.   
    3.    public static void main(String args[]) throws Exception { 
    4.       //為了簡單起見,所有的異常都直接往外拋 
    5.      String host = "127.0.0.1";  //要連接的服務(wù)端IP地址 
    6.      int port = 8899;   //要連接的服務(wù)端對應(yīng)的監(jiān)聽端口 
    7.      //與服務(wù)端建立連接 
    8.      Socket client = new Socket(host, port); 
    9.       //建立連接后就可以往服務(wù)端寫數(shù)據(jù)了 
    10.      Writer writer = new OutputStreamWriter(client.getOutputStream()); 
    11.       writer.write("Hello Server."); 
    12.       writer.write("eof"); 
    13.       writer.flush(); 
    14.       //寫完以后進(jìn)行讀操作 
    15.      Reader reader = new InputStreamReader(client.getInputStream()); 
    16.       char chars[] = new char[64]; 
    17.       int len; 
    18.       StringBuffer sb = new StringBuffer(); 
    19.       String temp; 
    20.       int index; 
    21.       while ((len=reader.read(chars)) != -1) { 
    22.          temp = new String(chars, 0, len); 
    23.          if ((index = temp.indexOf("eof")) != -1) { 
    24.             sb.append(temp.substring(0, index)); 
    25.             break; 
    26.          } 
    27.          sb.append(new String(chars, 0, len)); 
    28.       } 
    29.       System.out.println("from server: " + sb); 
    30.       writer.close(); 
    31.       reader.close(); 
    32.       client.close(); 
    33.    } 
    34.     
    35.   
    public class Client {
     
       public static void main(String args[]) throws Exception {
          //為了簡單起見,所有的異常都直接往外拋
         String host = "127.0.0.1";  //要連接的服務(wù)端IP地址
         int port = 8899;   //要連接的服務(wù)端對應(yīng)的監(jiān)聽端口
         //與服務(wù)端建立連接
         Socket client = new Socket(host, port);
          //建立連接后就可以往服務(wù)端寫數(shù)據(jù)了
         Writer writer = new OutputStreamWriter(client.getOutputStream());
          writer.write("Hello Server.");
          writer.write("eof");
          writer.flush();
          //寫完以后進(jìn)行讀操作
         Reader reader = new InputStreamReader(client.getInputStream());
          char chars[] = new char[64];
          int len;
          StringBuffer sb = new StringBuffer();
          String temp;
          int index;
          while ((len=reader.read(chars)) != -1) {
             temp = new String(chars, 0, len);
             if ((index = temp.indexOf("eof")) != -1) {
                sb.append(temp.substring(0, index));
                break;
             }
             sb.append(new String(chars, 0, len));
          }
          System.out.println("from server: " + sb);
          writer.close();
          reader.close();
          client.close();
       }
       
    }
     

          

    我們?nèi)粘J褂玫谋容^多的都是這種客戶端發(fā)送數(shù)據(jù)給服務(wù)端,服務(wù)端接收數(shù)據(jù)后再返回相應(yīng)的結(jié)果給客戶端這種形式。只是客戶端和服務(wù)端之間不再是這種一對一的關(guān)系,而是下面要講到的多個(gè)客戶端對應(yīng)同一個(gè)服務(wù)端的情況。

          3、多個(gè)客戶端連接同一個(gè)服務(wù)端

           像前面講的兩個(gè)例子都是服務(wù)端接收一個(gè)客戶端的請求之后就結(jié)束了,不能再接收其他客戶端的請求了,這往往是不能滿足我們的要求的。通常我們會(huì)這樣做:

    1. public class Server { 
    2.   
    3.    public static void main(String args[]) throws IOException { 
    4.       //為了簡單起見,所有的異常信息都往外拋 
    5.      int port = 8899; 
    6.       //定義一個(gè)ServerSocket監(jiān)聽在端口8899上 
    7.      ServerSocket server = new ServerSocket(port); 
    8.       while (true) { 
    9.          //server嘗試接收其他Socket的連接請求,server的accept方法是阻塞式的 
    10.        Socket socket = server.accept(); 
    11.          //跟客戶端建立好連接之后,我們就可以獲取socket的InputStream,并從中讀取客戶端發(fā)過來的信息了。 
    12.        Reader reader = new InputStreamReader(socket.getInputStream()); 
    13.          char chars[] = new char[64]; 
    14.          int len; 
    15.          StringBuilder sb = new StringBuilder(); 
    16.          String temp; 
    17.          int index; 
    18.          while ((len=reader.read(chars)) != -1) { 
    19.             temp = new String(chars, 0, len); 
    20.             if ((index = temp.indexOf("eof")) != -1) {//遇到eof時(shí)就結(jié)束接收 
    21.                 sb.append(temp.substring(0, index)); 
    22.                 break; 
    23.             } 
    24.             sb.append(temp); 
    25.          } 
    26.          System.out.println("from client: " + sb); 
    27.          //讀完后寫一句 
    28.        Writer writer = new OutputStreamWriter(socket.getOutputStream()); 
    29.          writer.write("Hello Client."); 
    30.          writer.flush(); 
    31.          writer.close(); 
    32.          reader.close(); 
    33.          socket.close(); 
    34.       } 
    35.    } 
    36.     
    public class Server {
     
       public static void main(String args[]) throws IOException {
          //為了簡單起見,所有的異常信息都往外拋
         int port = 8899;
          //定義一個(gè)ServerSocket監(jiān)聽在端口8899上
         ServerSocket server = new ServerSocket(port);
          while (true) {
             //server嘗試接收其他Socket的連接請求,server的accept方法是阻塞式的
           Socket socket = server.accept();
             //跟客戶端建立好連接之后,我們就可以獲取socket的InputStream,并從中讀取客戶端發(fā)過來的信息了。
           Reader reader = new InputStreamReader(socket.getInputStream());
             char chars[] = new char[64];
             int len;
             StringBuilder sb = new StringBuilder();
             String temp;
             int index;
             while ((len=reader.read(chars)) != -1) {
                temp = new String(chars, 0, len);
                if ((index = temp.indexOf("eof")) != -1) {//遇到eof時(shí)就結(jié)束接收
                    sb.append(temp.substring(0, index));
                    break;
                }
                sb.append(temp);
             }
             System.out.println("from client: " + sb);
             //讀完后寫一句
           Writer writer = new OutputStreamWriter(socket.getOutputStream());
             writer.write("Hello Client.");
             writer.flush();
             writer.close();
             reader.close();
             socket.close();
          }
       }
       
    }
    
    

          

    在上面代碼中我們用了一個(gè)死循環(huán),在循環(huán)體里面ServerSocket調(diào)用其accept方法試圖接收來自客戶端的連接請求。當(dāng)沒有接收到請求的時(shí)候,程序會(huì)在這里阻塞直到接收到來自客戶端的連接請求,之后會(huì)跟當(dāng)前建立好連接的客戶端進(jìn)行通信,完了后會(huì)接著執(zhí)行循環(huán)體再次嘗試接收新的連接請求。這樣我們的ServerSocket就能接收來自所有客戶端的連接請求了,并且與它們進(jìn)行通信了。這就實(shí)現(xiàn)了一個(gè)簡單的一個(gè)服務(wù)端與多個(gè)客戶端進(jìn)行通信的模式。

           上述例子中雖然實(shí)現(xiàn)了一個(gè)服務(wù)端跟多個(gè)客戶端進(jìn)行通信,但是還存在一個(gè)問題。在上述例子中,我們的服務(wù)端處理客戶端的連接請求是同步進(jìn)行的,每次接收到來自客戶端的連接請求后,都要先跟當(dāng)前的客戶端通信完之后才能再處理下一個(gè)連接請求。這在并發(fā)比較多的情況下會(huì)嚴(yán)重影響程序的性能,為此,我們可以把它改為如下這種異步處理與客戶端通信的方式:

    1. public class Server { 
    2.     
    3.    public static void main(String args[]) throws IOException { 
    4.       //為了簡單起見,所有的異常信息都往外拋 
    5.      int port = 8899; 
    6.       //定義一個(gè)ServerSocket監(jiān)聽在端口8899上 
    7.      ServerSocket server = new ServerSocket(port); 
    8.       while (true) { 
    9.          //server嘗試接收其他Socket的連接請求,server的accept方法是阻塞式的 
    10.          Socket socket = server.accept(); 
    11.          //每接收到一個(gè)Socket就建立一個(gè)新的線程來處理它 
    12.          new Thread(new Task(socket)).start(); 
    13.       } 
    14.    } 
    15.     
    16.    /**
    17.     * 用來處理Socket請求的
    18.    */ 
    19.    static class Task implements Runnable { 
    20.   
    21.       private Socket socket; 
    22.        
    23.       public Task(Socket socket) { 
    24.          this.socket = socket; 
    25.       } 
    26.        
    27.       public void run() { 
    28.  
    29.          try { 
    30.  
    31.             handleSocket(); 
    32.          } catch (Exception e) { 
    33.             e.printStackTrace(); 
    34.          } 
    35.       } 
    36.        
    37.       /**
    38.        * 跟客戶端Socket進(jìn)行通信
    39.        * @throws Exception
    40.        */ 
    41.       private void handleSocket() throws Exception { 
    42.          Reader reader = new InputStreamReader(socket.getInputStream()); 
    43.          char chars[] = new char[64]; 
    44.          int len; 
    45.          StringBuilder sb = new StringBuilder(); 
    46.          String temp; 
    47.          int index; 
    48.          while ((len=reader.read(chars)) != -1) { 
    49.             temp = new String(chars, 0, len); 
    50.             if ((index = temp.indexOf("eof")) != -1) {//遇到eof時(shí)就結(jié)束接收 
    51.              sb.append(temp.substring(0, index)); 
    52.                 break; 
    53.             } 
    54.             sb.append(temp); 
    55.          } 
    56.          System.out.println("from client: " + sb); 
    57.          //讀完后寫一句 
    58.        Writer writer = new OutputStreamWriter(socket.getOutputStream()); 
    59.          writer.write("Hello Client."); 
    60.          writer.flush(); 
    61.          writer.close(); 
    62.          reader.close(); 
    63.          socket.close(); 
    64.       } 
    65.        
    66.    } 
    67.     
    public class Server {
       
       public static void main(String args[]) throws IOException {
          //為了簡單起見,所有的異常信息都往外拋
         int port = 8899;
          //定義一個(gè)ServerSocket監(jiān)聽在端口8899上
         ServerSocket server = new ServerSocket(port);
          while (true) {
             //server嘗試接收其他Socket的連接請求,server的accept方法是阻塞式的
             Socket socket = server.accept();
             //每接收到一個(gè)Socket就建立一個(gè)新的線程來處理它
             new Thread(new Task(socket)).start();
          }
       }
       
       /**
        * 用來處理Socket請求的
       */
       static class Task implements Runnable {
     
          private Socket socket;
          
          public Task(Socket socket) {
             this.socket = socket;
          }
          
          public void run() {
    
             try {
    
                handleSocket();
             } catch (Exception e) {
                e.printStackTrace();
             }
          }
          
          /**
           * 跟客戶端Socket進(jìn)行通信
           * @throws Exception
           */
          private void handleSocket() throws Exception {
             Reader reader = new InputStreamReader(socket.getInputStream());
             char chars[] = new char[64];
             int len;
             StringBuilder sb = new StringBuilder();
             String temp;
             int index;
             while ((len=reader.read(chars)) != -1) {
                temp = new String(chars, 0, len);
                if ((index = temp.indexOf("eof")) != -1) {//遇到eof時(shí)就結(jié)束接收
                 sb.append(temp.substring(0, index));
                    break;
                }
                sb.append(temp);
             }
             System.out.println("from client: " + sb);
             //讀完后寫一句
           Writer writer = new OutputStreamWriter(socket.getOutputStream());
             writer.write("Hello Client.");
             writer.flush();
             writer.close();
             reader.close();
             socket.close();
          }
          
       }
       
    }
    

          

    在上面代碼中,每次ServerSocket接收到一個(gè)新的Socket連接請求后都會(huì)新起一個(gè)線程來跟當(dāng)前Socket進(jìn)行通信,這樣就達(dá)到了異步處理與客戶端Socket進(jìn)行通信的情況。

           在從SocketInputStream中接收數(shù)據(jù)時(shí),像上面那樣一點(diǎn)點(diǎn)的讀就太復(fù)雜了,有時(shí)候我們就會(huì)換成使用BufferedReader來一次讀一行,如:

    1. public class Server { 
    2.   
    3.    public static void main(String args[]) throws IOException { 
    4.       //為了簡單起見,所有的異常信息都往外拋 
    5.      int port = 8899; 
    6.       //定義一個(gè)ServerSocket監(jiān)聽在端口8899上 
    7.      ServerSocket server = new ServerSocket(port); 
    8.       while (true) { 
    9.          //server嘗試接收其他Socket的連接請求,server的accept方法是阻塞式的 
    10.          Socket socket = server.accept(); 
    11.          //每接收到一個(gè)Socket就建立一個(gè)新的線程來處理它 
    12.          new Thread(new Task(socket)).start(); 
    13.       } 
    14.    } 
    15.     
    16.    /**
    17.     * 用來處理Socket請求的
    18.    */ 
    19.    static class Task implements Runnable { 
    20.   
    21.       private Socket socket; 
    22.        
    23.       public Task(Socket socket) { 
    24.          this.socket = socket; 
    25.       } 
    26.        
    27.       public void run() { 
    28.          try { 
    29.             handleSocket(); 
    30.          } catch (Exception e) { 
    31.             e.printStackTrace(); 
    32.          } 
    33.       } 
    34.        
    35.       /**
    36.        * 跟客戶端Socket進(jìn)行通信
    37.       * @throws Exception
    38.        */ 
    39.       private void handleSocket() throws Exception { 
    40.          BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream())); 
    41.          StringBuilder sb = new StringBuilder(); 
    42.          String temp; 
    43.          int index; 
    44.          while ((temp=br.readLine()) != null) { 
    45.             System.out.println(temp); 
    46.             if ((index = temp.indexOf("eof")) != -1) {//遇到eof時(shí)就結(jié)束接收 
    47.              sb.append(temp.substring(0, index)); 
    48.                 break; 
    49.             } 
    50.             sb.append(temp); 
    51.          } 
    52.          System.out.println("from client: " + sb); 
    53.          //讀完后寫一句 
    54.        Writer writer = new OutputStreamWriter(socket.getOutputStream()); 
    55.          writer.write("Hello Client."); 
    56.          writer.write("eof\n"); 
    57.          writer.flush(); 
    58.          writer.close(); 
    59.          br.close(); 
    60.          socket.close(); 
    61.       } 
    62.    } 
    public class Server {
     
       public static void main(String args[]) throws IOException {
          //為了簡單起見,所有的異常信息都往外拋
         int port = 8899;
          //定義一個(gè)ServerSocket監(jiān)聽在端口8899上
         ServerSocket server = new ServerSocket(port);
          while (true) {
             //server嘗試接收其他Socket的連接請求,server的accept方法是阻塞式的
             Socket socket = server.accept();
             //每接收到一個(gè)Socket就建立一個(gè)新的線程來處理它
             new Thread(new Task(socket)).start();
          }
       }
       
       /**
        * 用來處理Socket請求的
       */
       static class Task implements Runnable {
     
          private Socket socket;
          
          public Task(Socket socket) {
             this.socket = socket;
          }
          
          public void run() {
             try {
                handleSocket();
             } catch (Exception e) {
                e.printStackTrace();
             }
          }
          
          /**
           * 跟客戶端Socket進(jìn)行通信
          * @throws Exception
           */
          private void handleSocket() throws Exception {
             BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
             StringBuilder sb = new StringBuilder();
             String temp;
             int index;
             while ((temp=br.readLine()) != null) {
                System.out.println(temp);
                if ((index = temp.indexOf("eof")) != -1) {//遇到eof時(shí)就結(jié)束接收
                 sb.append(temp.substring(0, index));
                    break;
                }
                sb.append(temp);
             }
             System.out.println("from client: " + sb);
             //讀完后寫一句
           Writer writer = new OutputStreamWriter(socket.getOutputStream());
             writer.write("Hello Client.");
             writer.write("eof\n");
             writer.flush();
             writer.close();
             br.close();
             socket.close();
          }
       }
    }
    
    

          

    這個(gè)時(shí)候需要注意的是,BufferedReaderreadLine方法是一次讀一行的,這個(gè)方法是阻塞的,直到它讀到了一行數(shù)據(jù)為止程序才會(huì)繼續(xù)往下執(zhí)行,那么readLine什么時(shí)候才會(huì)讀到一行呢?直到程序遇到了換行符或者是對應(yīng)流的結(jié)束符readLine方法才會(huì)認(rèn)為讀到了一行,才會(huì)結(jié)束其阻塞,讓程序繼續(xù)往下執(zhí)行。所以我們在使用BufferedReaderreadLine讀取數(shù)據(jù)的時(shí)候一定要記得在對應(yīng)的輸出流里面一定要寫入換行符(流結(jié)束之后會(huì)自動(dòng)標(biāo)記為結(jié)束,readLine可以識(shí)別),寫入換行符之后一定記得如果輸出流不是馬上關(guān)閉的情況下記得flush一下,這樣數(shù)據(jù)才會(huì)真正的從緩沖區(qū)里面寫入。對應(yīng)上面的代碼我們的客戶端程序應(yīng)該這樣寫:
    1. public class Client { 
    2.  
    3.    public static void main(String args[]) throws Exception { 
    4.       //為了簡單起見,所有的異常都直接往外拋 
    5.      String host = "127.0.0.1";  //要連接的服務(wù)端IP地址 
    6.      int port = 8899;   //要連接的服務(wù)端對應(yīng)的監(jiān)聽端口 
    7.      //與服務(wù)端建立連接 
    8.      Socket client = new Socket(host, port); 
    9.       //建立連接后就可以往服務(wù)端寫數(shù)據(jù)了 
    10.      Writer writer = new OutputStreamWriter(client.getOutputStream()); 
    11.       writer.write("Hello Server."); 
    12.       writer.write("eof\n"); 
    13.       writer.flush(); 
    14.       //寫完以后進(jìn)行讀操作 
    15.      BufferedReader br = new BufferedReader(new InputStreamReader(client.getInputStream())); 
    16.       StringBuffer sb = new StringBuffer(); 
    17.       String temp; 
    18.       int index; 
    19.       while ((temp=br.readLine()) != null) { 
    20.          if ((index = temp.indexOf("eof")) != -1) { 
    21.             sb.append(temp.substring(0, index)); 
    22.             break; 
    23.          } 
    24.          sb.append(temp); 
    25.       } 
    26.       System.out.println("from server: " + sb); 
    27.       writer.close(); 
    28.       br.close(); 
    29.       client.close(); 
    30.    } 
    public class Client {
    
       public static void main(String args[]) throws Exception {
          //為了簡單起見,所有的異常都直接往外拋
         String host = "127.0.0.1";  //要連接的服務(wù)端IP地址
         int port = 8899;   //要連接的服務(wù)端對應(yīng)的監(jiān)聽端口
         //與服務(wù)端建立連接
         Socket client = new Socket(host, port);
          //建立連接后就可以往服務(wù)端寫數(shù)據(jù)了
         Writer writer = new OutputStreamWriter(client.getOutputStream());
          writer.write("Hello Server.");
          writer.write("eof\n");
          writer.flush();
          //寫完以后進(jìn)行讀操作
         BufferedReader br = new BufferedReader(new InputStreamReader(client.getInputStream()));
          StringBuffer sb = new StringBuffer();
          String temp;
          int index;
          while ((temp=br.readLine()) != null) {
             if ((index = temp.indexOf("eof")) != -1) {
                sb.append(temp.substring(0, index));
                break;
             }
             sb.append(temp);
          }
          System.out.println("from server: " + sb);
          writer.close();
          br.close();
          client.close();
       }
    }
    
    

     

          4、設(shè)置超時(shí)時(shí)間

           假設(shè)有這樣一種需求,我們的客戶端需要通過Socket從服務(wù)端獲取到XX信息,然后給用戶展示在頁面上。我們知道Socket在讀數(shù)據(jù)的時(shí)候是阻塞式的,如果沒有讀到數(shù)據(jù)程序會(huì)一直阻塞在那里。在同步請求的時(shí)候我們肯定是不能允許這樣的情況發(fā)生的,這就需要我們在請求達(dá)到一定的時(shí)間后控制阻塞的中斷,讓程序得以繼續(xù)運(yùn)行。Socket為我們提供了一個(gè)setSoTimeout()方法來設(shè)置接收數(shù)據(jù)的超時(shí)時(shí)間,單位是毫秒。當(dāng)設(shè)置的超時(shí)時(shí)間大于0,并且超過了這一時(shí)間Socket還沒有接收到返回的數(shù)據(jù)的話,Socket就會(huì)拋出一個(gè)SocketTimeoutException。

           假設(shè)我們需要控制我們的客戶端在開始讀取數(shù)據(jù)10秒后還沒有讀到數(shù)據(jù)就中斷阻塞的話我們可以這樣做:

    1. public class Client { 
    2.   
    3.    public static void main(String args[]) throws Exception { 
    4.       //為了簡單起見,所有的異常都直接往外拋 
    5.      String host = "127.0.0.1";  //要連接的服務(wù)端IP地址 
    6.      int port = 8899;   //要連接的服務(wù)端對應(yīng)的監(jiān)聽端口 
    7.      //與服務(wù)端建立連接 
    8.      Socket client = new Socket(host, port); 
    9.       //建立連接后就可以往服務(wù)端寫數(shù)據(jù)了 
    10.      Writer writer = new OutputStreamWriter(client.getOutputStream()); 
    11.       writer.write("Hello Server."); 
    12.       writer.write("eof\n"); 
    13.       writer.flush(); 
    14.       //寫完以后進(jìn)行讀操作 
    15.      BufferedReader br = new BufferedReader(new InputStreamReader(client.getInputStream())); 
    16.       //設(shè)置超時(shí)間為10秒 
    17.      client.setSoTimeout(10*1000); 
    18.       StringBuffer sb = new StringBuffer(); 
    19.       String temp; 
    20.       int index; 
    21.       try { 
    22.          while ((temp=br.readLine()) != null) { 
    23.             if ((index = temp.indexOf("eof")) != -1) { 
    24.                 sb.append(temp.substring(0, index)); 
    25.                 break; 
    26.             } 
    27.             sb.append(temp); 
    28.          } 
    29.       } catch (SocketTimeoutException e) { 
    30.          System.out.println("數(shù)據(jù)讀取超時(shí)。"); 
    31.       } 
    32.       System.out.println("from server: " + sb); 
    33.       writer.close(); 
    34.       br.close(); 
    35.       client.close(); 
    36.    } 
    37.  
    38.   
    public class Client {
     
       public static void main(String args[]) throws Exception {
          //為了簡單起見,所有的異常都直接往外拋
         String host = "127.0.0.1";  //要連接的服務(wù)端IP地址
         int port = 8899;   //要連接的服務(wù)端對應(yīng)的監(jiān)聽端口
         //與服務(wù)端建立連接
         Socket client = new Socket(host, port);
          //建立連接后就可以往服務(wù)端寫數(shù)據(jù)了
         Writer writer = new OutputStreamWriter(client.getOutputStream());
          writer.write("Hello Server.");
          writer.write("eof\n");
          writer.flush();
          //寫完以后進(jìn)行讀操作
         BufferedReader br = new BufferedReader(new InputStreamReader(client.getInputStream()));
          //設(shè)置超時(shí)間為10秒
         client.setSoTimeout(10*1000);
          StringBuffer sb = new StringBuffer();
          String temp;
          int index;
          try {
             while ((temp=br.readLine()) != null) {
                if ((index = temp.indexOf("eof")) != -1) {
                    sb.append(temp.substring(0, index));
                    break;
                }
                sb.append(temp);
             }
          } catch (SocketTimeoutException e) {
             System.out.println("數(shù)據(jù)讀取超時(shí)。");
          }
          System.out.println("from server: " + sb);
          writer.close();
          br.close();
          client.close();
       }
    }
    
     
    
    

           5、接收數(shù)據(jù)亂碼

           對于這種服務(wù)端或客戶端接收中文亂碼的情況通常是因?yàn)閿?shù)據(jù)發(fā)送時(shí)使用的編碼跟接收時(shí)候使用的編碼不一致。比如有下面這樣一段服務(wù)端代碼:

    1. public class Server { 
    2.   
    3.    public static void main(String args[]) throws IOException { 
    4.       //為了簡單起見,所有的異常信息都往外拋 
    5.       int port = 8899; 
    6.       //定義一個(gè)ServerSocket監(jiān)聽在端口8899上 
    7.       ServerSocket server = new ServerSocket(port); 
    8.       while (true) { 
    9.          //server嘗試接收其他Socket的連接請求,server的accept方法是阻塞式的 
    10.          Socket socket = server.accept(); 
    11.          //每接收到一個(gè)Socket就建立一個(gè)新的線程來處理它 
    12.          new Thread(new Task(socket)).start(); 
    13.       } 
    14.    } 
    15.     
    16.    /**
    17.     * 用來處理Socket請求的
    18.     */ 
    19.    static class Task implements Runnable { 
    20.   
    21.       private Socket socket; 
    22.        
    23.       public Task(Socket socket) { 
    24.          this.socket = socket; 
    25.       } 
    26.        
    27.       public void run() { 
    28.          try { 
    29.             handleSocket(); 
    30.          } catch (Exception e) { 
    31.             e.printStackTrace(); 
    32.          } 
    33.       } 
    34.        
    35.       /**
    36.        * 跟客戶端Socket進(jìn)行通信
    37.       * @throws Exception
    38.        */ 
    39.       private void handleSocket() throws Exception { 
    40.          BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream(), "GBK")); 
    41.          StringBuilder sb = new StringBuilder(); 
    42.          String temp; 
    43.          int index; 
    44.          while ((temp=br.readLine()) != null) { 
    45.             System.out.println(temp); 
    46.             if ((index = temp.indexOf("eof")) != -1) {//遇到eof時(shí)就結(jié)束接收 
    47.              sb.append(temp.substring(0, index)); 
    48.                 break; 
    49.             } 
    50.             sb.append(temp); 
    51.          } 
    52.          System.out.println("客戶端: " + sb); 
    53.          //讀完后寫一句 
    54.        Writer writer = new OutputStreamWriter(socket.getOutputStream(), "UTF-8"); 
    55.          writer.write("你好,客戶端。"); 
    56.          writer.write("eof\n"); 
    57.          writer.flush(); 
    58.          writer.close(); 
    59.          br.close(); 
    60.          socket.close(); 
    61.       } 
    62.    } 
    public class Server {
     
       public static void main(String args[]) throws IOException {
          //為了簡單起見,所有的異常信息都往外拋
          int port = 8899;
          //定義一個(gè)ServerSocket監(jiān)聽在端口8899上
          ServerSocket server = new ServerSocket(port);
          while (true) {
             //server嘗試接收其他Socket的連接請求,server的accept方法是阻塞式的
             Socket socket = server.accept();
             //每接收到一個(gè)Socket就建立一個(gè)新的線程來處理它
             new Thread(new Task(socket)).start();
          }
       }
       
       /**
        * 用來處理Socket請求的
        */
       static class Task implements Runnable {
     
          private Socket socket;
          
          public Task(Socket socket) {
             this.socket = socket;
          }
          
          public void run() {
             try {
                handleSocket();
             } catch (Exception e) {
                e.printStackTrace();
             }
          }
          
          /**
           * 跟客戶端Socket進(jìn)行通信
          * @throws Exception
           */
          private void handleSocket() throws Exception {
             BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream(), "GBK"));
             StringBuilder sb = new StringBuilder();
             String temp;
             int index;
             while ((temp=br.readLine()) != null) {
                System.out.println(temp);
                if ((index = temp.indexOf("eof")) != -1) {//遇到eof時(shí)就結(jié)束接收
                 sb.append(temp.substring(0, index));
                    break;
                }
                sb.append(temp);
             }
             System.out.println("客戶端: " + sb);
             //讀完后寫一句
           Writer writer = new OutputStreamWriter(socket.getOutputStream(), "UTF-8");
             writer.write("你好,客戶端。");
             writer.write("eof\n");
             writer.flush();
             writer.close();
             br.close();
             socket.close();
          }
       }
    }
    
    

          

    這里用來測試我就弄的混亂了一點(diǎn)。在上面服務(wù)端代碼中我們在定義輸入流的時(shí)候明確定義了使用GBK編碼來讀取數(shù)據(jù),而在定義輸出流的時(shí)候明確指定了將使用UTF-8編碼來發(fā)送數(shù)據(jù)。如果客戶端上送數(shù)據(jù)的時(shí)候不以GBK編碼來發(fā)送的話服務(wù)端接收的數(shù)據(jù)就很有可能會(huì)亂碼;同樣如果客戶端接收數(shù)據(jù)的時(shí)候不以服務(wù)端發(fā)送數(shù)據(jù)的編碼,即UTF-8編碼來接收數(shù)據(jù)的話也極有可能會(huì)出現(xiàn)數(shù)據(jù)亂碼的情況。所以,對于上述服務(wù)端代碼,為使我們的程序能夠讀取對方發(fā)送過來的數(shù)據(jù),而不出現(xiàn)亂碼情況,我們的客戶端應(yīng)該是這樣的:
    1. public class Client { 
    2.   
    3.    public static void main(String args[]) throws Exception { 
    4.       //為了簡單起見,所有的異常都直接往外拋 
    5.      String host = "127.0.0.1";  //要連接的服務(wù)端IP地址 
    6.      int port = 8899;   //要連接的服務(wù)端對應(yīng)的監(jiān)聽端口 
    7.      //與服務(wù)端建立連接 
    8.      Socket client = new Socket(host, port); 
    9.       //建立連接后就可以往服務(wù)端寫數(shù)據(jù)了 
    10.      Writer writer = new OutputStreamWriter(client.getOutputStream(), "GBK"); 
    11.       writer.write("你好,服務(wù)端。"); 
    12.       writer.write("eof\n"); 
    13.       writer.flush(); 
    14.       //寫完以后進(jìn)行讀操作 
    15.      BufferedReader br = new BufferedReader(new InputStreamReader(client.getInputStream(), "UTF-8")); 
    16.       //設(shè)置超時(shí)間為10秒 
    17.      client.setSoTimeout(10*1000); 
    18.       StringBuffer sb = new StringBuffer(); 
    19.       String temp; 
    20.       int index; 
    21.       try { 
    22.          while ((temp=br.readLine()) != null) { 
    23.             if ((index = temp.indexOf("eof")) != -1) { 
    24.                 sb.append(temp.substring(0, index)); 
    25.                 break; 
    26.             } 
    27.             sb.append(temp); 
    28.          } 
    29.       } catch (SocketTimeoutException e) { 
    30.          System.out.println("數(shù)據(jù)讀取超時(shí)。"); 
    31.       } 
    32.       System.out.println("服務(wù)端: " + sb); 
    33.       writer.close(); 
    34.       br.close(); 
    35.       client.close(); 
    36.    } 
    837

    posted on 2014-07-28 11:36 休息食客 閱讀(69) 評論(0)  編輯  收藏

    只有注冊用戶登錄后才能發(fā)表評論。


    網(wǎng)站導(dǎo)航:
    博客園   IT新聞   Chat2DB   C++博客   博問  
     
    主站蜘蛛池模板: 84pao强力永久免费高清| 久久亚洲色WWW成人欧美| 亚洲AV永久无码精品水牛影视| 亚洲精品A在线观看| 免费女人18毛片a级毛片视频| 免费观看毛片视频| 精品免费国产一区二区三区 | 亚洲va成无码人在线观看| 亚洲熟妇无码久久精品| 亚洲色偷偷偷网站色偷一区| 亚洲经典在线观看| 亚洲91精品麻豆国产系列在线| avtt天堂网手机版亚洲| 亚洲中文字幕无码mv| 亚洲AV日韩AV无码污污网站| 美女黄色免费网站| 国产免费高清69式视频在线观看| 中文字幕在线免费播放| 精品四虎免费观看国产高清午夜| 午夜视频免费在线观看| 国产h肉在线视频免费观看| 免费一本色道久久一区| 国产女高清在线看免费观看| 亚洲第一区在线观看| 亚洲精品午夜国产VA久久成人| 亚洲国产成人久久综合碰碰动漫3d| 久久丫精品国产亚洲av| 中国亚洲呦女专区| 免费精品国产自产拍在线观看| 一级成人a免费视频| 一级成人a毛片免费播放| 成人免费一级毛片在线播放视频| 宅男666在线永久免费观看| 亚洲一区二区三区在线播放| 亚洲AV日韩AV天堂一区二区三区| 亚洲精品第一国产综合精品| 亚洲AV无码资源在线观看| 久久久久久国产a免费观看不卡| 97视频免费观看2区| 暖暖免费高清日本中文| 亚洲乱码精品久久久久..|