1. 程式人生 > >JAVA_ 網路程式設計,寫一個可以上傳檔案的伺服器和客戶端

JAVA_ 網路程式設計,寫一個可以上傳檔案的伺服器和客戶端

服務端

class Server 
{  
     public static void main(String[] args) throws Exception 
     {  
      //建立服務端Socket  
      ServerSocket ss = new ServerSocket(10005);  
      //接收客戶端Socket  
      Socket fileLoaderSocket = ss.accept();  

      //列印連線資訊  
      String ip = fileLoaderSocket.getInetAddress().getHostAddress();  
      System.out
.println(ip + "...conncected"); //接收檔案,並儲存 InputStream in = fileLoaderSocket.getInputStream(); //例項化物件fileSave OutputStream fileSave = new FileOutputStream("E:\\3.mp3"); //建立陣列buf byte[] buf = new byte[1024]; int len = 0; //判斷是否讀到檔案末尾 while((len=in
.read(buf)) != -1) { fileSave.write(buf, 0, len); //重新整理 fileSave.flush(); } //返回檔案複製情況資訊 BufferedWriter out = new BufferedWriter(new OutputStreamWriter(fileLoaderSocket.getOutputStream())); out.write("檔案上傳成功"); //重新整理 out
.flush(); //資源關閉 ss.close(); fileLoaderSocket.close(); fileSave.close(); } }

客戶端:

class Client
{  
      public static void main(String[] args) throws Exception 
      {  
      //建立Socket服務  
      Socket fileLoaderSocket = new Socket("168.168.168.94", 10005);  
      //從客戶端本地讀取檔案,並寫入socket的輸出流中  
      OutputStream out = fileLoaderSocket.getOutputStream();  
      //例項化物件fileReader
      InputStream fileRead = new FileInputStream("G:\\2.mp3");  
      //建立陣列
      byte[] buf = new byte[1024];  
      int len = 0; 
      //判斷是否讀到檔案末尾
      while((len=fileRead.read(buf)) != -1)
          {  
           out.write(buf, 0, len);  
          }  
      //告訴服務端,檔案已傳輸完畢  
      fileLoaderSocket.shutdownOutput();  
      //獲取從服務端反饋的資訊  
      BufferedReader in = new BufferedReader(new InputStreamReader(fileLoaderSocket.getInputStream()));  
      String serverBack = in.readLine();  
      System.out.println(serverBack);    
      //資源關閉  
      fileLoaderSocket.close();  
      fileRead.close();  
    }  
}  

下面的程式是從別處直接照搬過來的,供學習參考:

Java Socket程式設計

對於Java Socket程式設計而言,有兩個概念,一個是ServerSocket,一個是Socket。服務端和客戶端之間通過Socket建立連線,之後它們就可以進行通訊了。首先ServerSocket將在服務端監聽某個埠,當發現客戶端有Socket來試圖連線它時,它會accept該Socket的連線請求,同時在服務端建立一個對應的Socket與之進行通訊。這樣就有兩個Socket了,客戶端和服務端各一個。
對於Socket之間的通訊其實很簡單,服務端往Socket的輸出流裡面寫東西,客戶端就可以通過Socket的輸入流讀取對應的內容。Socket與Socket之間是雙向連通的,所以客戶端也可以往對應的Socket輸出流裡面寫東西,然後服務端對應的Socket的輸入流就可以讀出對應的內容。下面來看一些服務端與客戶端通訊的例子:

1.客戶端寫服務端讀

服務端程式碼
Java程式碼
public class Server {  

   public static void main(String args[]) throws IOException {  
      //為了簡單起見,所有的異常資訊都往外拋  
      int port = 8899;  
      //定義一個ServerSocket監聽在埠8899上  
      ServerSocket server = new ServerSocket(port);  
      //server嘗試接收其他Socket的連線請求,server的accept方法是阻塞式的  
      Socket socket = server.accept();  
      //跟客戶端建立好連線之後,我們就可以獲取socket的InputStream,並從中讀取客戶端發過來的資訊了。  
      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();  
   }  

}  

服務端從Socket的InputStream中讀取資料的操作也是阻塞式的,如果從輸入流中沒有讀取到資料程式會一直在那裡不動,直到客戶端往Socket的輸出流中寫入了資料,或關閉了Socket的輸出流。當然,對於客戶端的Socket也是同樣如此。在操作完以後,整個程式結束前記得關閉對應的資源,即關閉對應的IO流和Socket。

客戶端程式碼

Java程式碼
public class Client {  

   public static void main(String args[]) throws Exception {  
      //為了簡單起見,所有的異常都直接往外拋  
      String host = "127.0.0.1";  //要連線的服務端IP地址  
      int port = 8899;   //要連線的服務端對應的監聽埠  
      //與服務端建立連線  
      Socket client = new Socket(host, port);  
      //建立連線後就可以往服務端寫資料了  
      Writer writer = new OutputStreamWriter(client.getOutputStream());  
      writer.write("Hello Server.");  
      writer.flush();//寫完後要記得flush  
      writer.close();  
      client.close();  
   }  

}  

對於客戶端往Socket的輸出流裡面寫資料傳遞給服務端要注意一點,如果寫操作之後程式不是對應著輸出流的關閉,而是進行其他阻塞式的操作(比如從輸入流裡面讀資料),記住要flush一下,只有這樣服務端才能收到客戶端傳送的資料,否則可能會引起兩邊無限的互相等待。在稍後講到客戶端和服務端同時讀和寫的時候會說到這個問題。

2.客戶端和服務端同時讀和寫

前面已經說了Socket之間是雙向通訊的,它既可以接收資料,同時也可以傳送資料。

服務端程式碼

Java程式碼 
public class Server {  

   public static void main(String args[]) throws IOException {  
      //為了簡單起見,所有的異常資訊都往外拋  
      int port = 8899;  
      //定義一個ServerSocket監聽在埠8899上  
      ServerSocket server = new ServerSocket(port);  
      //server嘗試接收其他Socket的連線請求,server的accept方法是阻塞式的  
      Socket socket = server.accept();  
      //跟客戶端建立好連線之後,我們就可以獲取socket的InputStream,並從中讀取客戶端發過來的資訊了。  
      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();  
   }  

}  

在上述程式碼中首先我們從輸入流中讀取客戶端傳送過來的資料,接下來我們再往輸出流裡面寫入資料給客戶端,接下來關閉對應的資原始檔。而實際上上述程式碼可能並不會按照我們預先設想的方式執行,因為從輸入流中讀取資料是一個阻塞式操作,在上述的while迴圈中當讀到資料的時候就會執行迴圈體,否則就會阻塞,這樣後面的寫操作就永遠都執行不了了。除非客戶端對應的Socket關閉了阻塞才會停止,while迴圈也會跳出。針對這種可能永遠無法執行下去的情況的解決方法是while迴圈需要在裡面有條件的跳出來,縱觀上述程式碼,在不斷變化的也只有取到的長度len和讀到的資料了,len已經是不能用的了,唯一能用的就是讀到的資料了。針對這種情況,通常我們都會約定一個結束標記,當客戶端傳送過來的資料包含某個結束標記時就說明當前的資料已經發送完畢了,這個時候我們就可以進行迴圈的跳出了。那麼改進後的程式碼會是這個樣子:

Java程式碼

public class Server {  

   public static void main(String args[]) throws IOException {  
      //為了簡單起見,所有的異常資訊都往外拋  
      int port = 8899;  
      //定義一個ServerSocket監聽在埠8899上  
      ServerSocket server = new ServerSocket(port);  
      //server嘗試接收其他Socket的連線請求,server的accept方法是阻塞式的  
      Socket socket = server.accept();  
      //跟客戶端建立好連線之後,我們就可以獲取socket的InputStream,並從中讀取客戶端發過來的資訊了。  
      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時就結束接收  
            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();  
   }  

}  

在上述程式碼中,當服務端讀取到客戶端傳送的結束標記,即“eof”時就會結束資料的接收,終止迴圈,這樣後續的程式碼又可以繼續進行了。

客戶端程式碼

Java程式碼
public class Client {  

   public static void main(String args[]) throws Exception {  
      //為了簡單起見,所有的異常都直接往外拋  
     String host = "127.0.0.1";  //要連線的服務端IP地址  
     int port = 8899;   //要連線的服務端對應的監聽埠  
     //與服務端建立連線  
     Socket client = new Socket(host, port);  
      //建立連線後就可以往服務端寫資料了  
     Writer writer = new OutputStreamWriter(client.getOutputStream());  
      writer.write("Hello Server.");  
      writer.flush();  
      //寫完以後進行讀操作  
     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();  
   }  

}  

在上述程式碼中我們先是給服務端傳送了一段資料,之後讀取服務端返回來的資料,跟之前的服務端一樣在讀的過程中有可能導致程式一直掛在那裡,永遠跳不出while迴圈。這段程式碼配合服務端的第一段程式碼就正好讓我們分析服務端永遠在那裡接收資料,永遠跳不出while迴圈,也就沒有之後的服務端返回資料給客戶端,客戶端也就不可能接收到服務端返回的資料。解決方法如服務端第二段程式碼所示,在客戶端傳送資料完畢後,往輸出流裡面寫入結束標記告訴服務端資料已經發送完畢了,同樣服務端返回資料完畢後也發一個標記告訴客戶端。那麼修改後的客戶端程式碼就應該是這個樣子:

Java程式碼

public class Client {  

   public static void main(String args[]) throws Exception {  
      //為了簡單起見,所有的異常都直接往外拋  
     String host = "127.0.0.1";  //要連線的服務端IP地址  
     int port = 8899;   //要連線的服務端對應的監聽埠  
     //與服務端建立連線  
     Socket client = new Socket(host, port);  
      //建立連線後就可以往服務端寫資料了  
     Writer writer = new OutputStreamWriter(client.getOutputStream());  
      writer.write("Hello Server.");  
      writer.write("eof");  
      writer.flush();  
      //寫完以後進行讀操作  
     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();  
   }  

}  

我們日常使用的比較多的都是這種客戶端傳送資料給服務端,服務端接收資料後再返回相應的結果給客戶端這種形式。只是客戶端和服務端之間不再是這種一對一的關係,而是下面要講到的多個客戶端對應同一個服務端的情況。

3.多個客戶端連線同一個服務端

像前面講的兩個例子都是服務端接收一個客戶端的請求之後就結束了,不能再接收其他客戶端的請求了,這往往是不能滿足我們的要求的。通常我們會這樣做:

Java程式碼

public class Server {  

   public static void main(String args[]) throws IOException {  
      //為了簡單起見,所有的異常資訊都往外拋  
     int port = 8899;  
      //定義一個ServerSocket監聽在埠8899上  
     ServerSocket server = new ServerSocket(port);  
      while (true) {  
         //server嘗試接收其他Socket的連線請求,server的accept方法是阻塞式的  
       Socket socket = server.accept();  
         //跟客戶端建立好連線之後,我們就可以獲取socket的InputStream,並從中讀取客戶端發過來的資訊了。  
       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時就結束接收  
                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呼叫其accept方法試圖接收來自客戶端的連線請求。當沒有接收到請求的時候,程式會在這裡阻塞直到接收到來自客戶端的連線請求,之後會跟當前建立好連線的客戶端進行通訊,完了後會接著執行迴圈體再次嘗試接收新的連線請求。這樣我們的ServerSocket就能接收來自所有客戶端的連線請求了,並且與它們進行通訊了。這就實現了一個簡單的一個服務端與多個客戶端進行通訊的模式。
上述例子中雖然實現了一個服務端跟多個客戶端進行通訊,但是還存在一個問題。在上述例子中,我們的服務端處理客戶端的連線請求是同步進行的,每次接收到來自客戶端的連線請求後,都要先跟當前的客戶端通訊完之後才能再處理下一個連線請求。這在併發比較多的情況下會嚴重影響程式的效能,為此,我們可以把它改為如下這種非同步處理與客戶端通訊的方式:

Java程式碼

public class Server {  

   public static void main(String args[]) throws IOException {  
      //為了簡單起見,所有的異常資訊都往外拋  
     int port = 8899;  
      //定義一個ServerSocket監聽在埠8899上  
     ServerSocket server = new ServerSocket(port);  
      while (true) {  
         //server嘗試接收其他Socket的連線請求,server的accept方法是阻塞式的  
         Socket socket = server.accept();  
         //每接收到一個Socket就建立一個新的執行緒來處理它  
         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進行通訊 
       * @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時就結束接收  
             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接收到一個新的Socket連線請求後都會新起一個執行緒來跟當前Socket進行通訊,這樣就達到了非同步處理與客戶端Socket進行通訊的情況。
在從Socket的InputStream中接收資料時,像上面那樣一點點的讀就太複雜了,有時候我們就會換成使用BufferedReader來一次讀一行,如:

Java程式碼

public class Server {  

   public static void main(String args[]) throws IOException {  
      //為了簡單起見,所有的異常資訊都往外拋  
     int port = 8899;  
      //定義一個ServerSocket監聽在埠8899上  
     ServerSocket server = new ServerSocket(port);  
      while (true) {  
         //server嘗試接收其他Socket的連線請求,server的accept方法是阻塞式的  
         Socket socket = server.accept();  
         //每接收到一個Socket就建立一個新的執行緒來處理它  
         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進行通訊 
      * @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時就結束接收  
             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();  
      }  
   }  
}  

這個時候需要注意的是,BufferedReader的readLine方法是一次讀一行的,這個方法是阻塞的,直到它讀到了一行資料為止程式才會繼續往下執行,那麼readLine什麼時候才會讀到一行呢?直到程式遇到了換行符或者是對應流的結束符readLine方法才會認為讀到了一行,才會結束其阻塞,讓程式繼續往下執行。所以我們在使用BufferedReader的readLine讀取資料的時候一定要記得在對應的輸出流裡面一定要寫入換行符(流結束之後會自動標記為結束,readLine可以識別),寫入換行符之後一定記得如果輸出流不是馬上關閉的情況下記得flush一下,這樣資料才會真正的從緩衝區裡面寫入。對應上面的程式碼我們的客戶端程式應該這樣寫:

Java程式碼

public class Client {  

   public static void main(String args[]) throws Exception {  
      //為了簡單起見,所有的異常都直接往外拋  
     String host = "127.0.0.1";  //要連線的服務端IP地址  
     int port = 8899;   //要連線的服務端對應的監聽埠  
     //與服務端建立連線  
     Socket client = new Socket(host, port);  
      //建立連線後就可以往服務端寫資料了  
     Writer writer = new OutputStreamWriter(client.getOutputStream());  
      writer.write("Hello Server.");  
      writer.write("eof\n");  
      writer.flush();  
      //寫完以後進行讀操作  
     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.設定超時時間

假設有這樣一種需求,我們的客戶端需要通過Socket從服務端獲取到XX資訊,然後給使用者展示在頁面上。我們知道Socket在讀資料的時候是阻塞式的,如果沒有讀到資料程式會一直阻塞在那裡。在同步請求的時候我們肯定是不能允許這樣的情況發生的,這就需要我們在請求達到一定的時間後控制阻塞的中斷,讓程式得以繼續執行。Socket為我們提供了一個setSoTimeout()方法來設定接收資料的超時時間,單位是毫秒。當設定的超時時間大於0,並且超過了這一時間Socket還沒有接收到返回的資料的話,Socket就會丟擲一個SocketTimeoutException。
假設我們需要控制我們的客戶端在開始讀取資料10秒後還沒有讀到資料就中斷阻塞的話我們可以這樣做:

Java程式碼

public class Client {  

   public static void main(String args[]) throws Exception {  
      //為了簡單起見,所有的異常都直接往外拋  
     String host = "127.0.0.1";  //要連線的服務端IP地址  
     int port = 8899;   //要連線的服務端對應的監聽埠  
     //與服務端建立連線  
     Socket client = new Socket(host, port);  
      //建立連線後就可以往服務端寫資料了  
     Writer writer = new OutputStreamWriter(client.getOutputStream());  
      writer.write("Hello Server.");  
      writer.write("eof\n");  
      writer.flush();  
      //寫完以後進行讀操作  
     BufferedReader br = new BufferedReader(new InputStreamReader(client.getInputStream()));  
      //設定超時間為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("資料讀取超時。");  
      }  
      System.out.println("from server: " + sb);  
      writer.close();  
      br.close();  
      client.close();  
   }  
}  

5.接收資料亂碼

對於這種服務端或客戶端接收中文亂碼的情況通常是因為資料傳送時使用的編碼跟接收時候使用的編碼不一致。比如有下面這樣一段服務端程式碼:

Java程式碼

public class Server {  

   public static void main(String args[]) throws IOException {  
      //為了簡單起見,所有的異常資訊都往外拋  
      int port = 8899;  
      //定義一個ServerSocket監聽在埠8899上  
      ServerSocket server = new ServerSocket(port);  
      while (true) {  
         //server嘗試接收其他Socket的連線請求,server的accept方法是阻塞式的  
         Socket socket = server.accept();  
         //每接收到一個Socket就建立一個新的執行緒來處理它  
         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進行通訊 
      * @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時就結束接收  
             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();  
      }  
   }  
}  

這裡用來測試我就弄的混亂了一點。在上面服務端程式碼中我們在定義輸入流的時候明確定義了使用GBK編碼來讀取資料,而在定義輸出流的時候明確指定了將使用UTF-8編碼來發送資料。如果客戶端上送資料的時候不以GBK編碼來發送的話服務端接收的資料就很有可能會亂碼;同樣如果客戶端接收資料的時候不以服務端傳送資料的編碼,即UTF-8編碼來接收資料的話也極有可能會出現資料亂碼的情況。所以,對於上述服務端程式碼,為使我們的程式能夠讀取對方傳送過來的資料,而不出現亂碼情況,我們的客戶端應該是這樣的:

Java程式碼

public class Client {  

   public static void main(String args[]) throws Exception {  
      //為了簡單起見,所有的異常都直接往外拋  
     String host = "127.0.0.1";  //要連線的服務端IP地址  
     int port = 8899;   //要連線的服務端對應的監聽埠  
     //與服務端建立連線  
     Socket client = new Socket(host, port);  
      //建立連線後就可以往服務端寫資料了  
     Writer writer = new OutputStreamWriter(client.getOutputStream(), "GBK");  
      writer.write("你好,服務端。");  
      writer.write("eof\n");  
      writer.flush();  
      //寫完以後進行讀操作  
     BufferedReader br = new BufferedReader(new InputStreamReader(client.getInputStream(), "UTF-8"));  
      //設定超時間為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("資料讀取超時。");  
      }  
      System.out.println("服務端: " + sb);  
      writer.close();  
      br.close();  
      client.close();  
   }  
}  

相關推薦

JAVA_ 網路程式設計一個可以檔案伺服器客戶

服務端 class Server { public static void main(String[] args) throws Exception { //建立服務端Socket ServerS

python練習題一個方法 進去列表預期的value 求出所有變量得取值可能性(例如list為[1,2,3,4,5,6,12,19]value為20結果是19+1==20只有一種可能性)要求時間復雜度為O(n)

num bubuko com pri def 代碼 data- 取值 .com 題目:(來自光榮之路老師)a+b==valuea+b+c=valuea+b+c+d==valuea+b+c+d+...=valuea和b....取值範圍都在0-value寫一個方法 傳進去列

拖拽檔案的web客戶實現

1. html 程式碼 準備一個jquery.js <!DOCTYPE html> <html> <head> <meta ch

一個 Java 的 Socket 伺服器客戶通訊的例子

        一個 HelloWord 級別的 Java Socket 通訊的例子。通訊過程:         先啟動 Server 端,進入一個死迴圈以便一直監聽某埠是否有連線請求。然後執行 Client 端,客戶端發出連線請求,服務端監聽到這次請求後向客戶端發回接受訊

[計網] 用python語言開發一個簡單的web伺服器客戶

伺服器:      當客戶聯絡時建立一個連線套接字 從這個連線接收HTTP請求(*)      解釋該請求所請求的特定檔案      從伺服器的檔案系統獲取該檔案      併發送檔案內容     

csapp書socket的伺服器客戶的程式碼

客戶端的程式碼:  #include "csapp.h" int main(int argc, char **argv) { int clientfd, port; char *host, buf[MAXLINE]; rio_t rio; if (arg

記錄一個解決了一個晚上加一個白天的問題關於springMVC檔案的功能

在做檔案上傳功能,用到了springMVC的這個類 import org.springframework.web.multipart.MultipartFile; 但是不管前臺怎麼傳檔案的值都過不去,查了下需要在wen.xml 建立bean <bean

不帶外掛 自己js實現批量檔案及進度顯示

今天接受專案中要完成檔案批量上傳檔案而且還要顯示上傳進度,一開始覺得這個應該不是很麻煩,當我在做的時候遇到了很多問題,很頭疼啊。 不過看了別人寫的程式碼,自己也測試過,發現網上好多都存在一些問題,並不是自己想要的。然後自己查閱各種資料,經過自己總結,最終完成了這個功能。

併發處理:鎖一個死鎖的例項執行緒監控

鎖 鎖是一個非常有用的工具,運用的場景非常多,因為他使用起來非常的簡單,而且易於理解。但是,鎖的問題就是很可能會出現一個非常壞的事情,就是一旦造成死鎖,就會導致執行緒得不到釋放,一旦死鎖的執行緒出現的太多,就會造成系統的不可用。 一、死鎖的例子 學習掌握一個概念,最好的方法就

C#為例分塊檔案

前臺: <html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> <title>&

記在k8s的pod使用apache的commons-net:ftp功能時ftp一直檔案失敗

    在k8s的pod上使用apache的commons-net:ftp功能時,一直顯示:          即上傳檔案失敗,但是在本地環境進行上傳時卻又顯示上傳成功,讓人十分不解。在網上搜

webuploader如何使用webuploader檔案demo使用webuploader檔案

webuploader是百度開發的一個js上傳檔案的元件, 你可以免費使用它, 實現上傳檔案,圖片,壓縮包等。 由於webuploader官方文件都是講述前端,js怎麼使用, 很少提及到伺服器端的程式

windows中虛擬機器windows之間互通性並實現檔案

一 測試連結是否ping通 筆記文件見百度網盤:大資料資料/windows與上安裝虛擬機器....doc; 因為安裝虛擬機器的時候,windows和vmare選擇的通訊方式為NAT方式,現在測試是否能ping通 虛擬機器的ip:192.168.59.128 Windo

【問題解決】利用Eclipse在hadoop檔案到hdfs沒有內容

本文適用於一些在網上找了半天答案都沒解決問題的人群,因為我也是在按網上說道弄了一天,最後才解決的。如果你是剛遇到問題,還沒有深入,建議你檢視這篇文章 http://f.dataguru.cn/hadoop-208802-1-1.html 將問題一步一步排除後仍沒有解決的話,可以試試我

(原) Bootstrap 視覺化HTML編輯器summernote 圖片伺服器磁碟

前臺 html <div id="editor" class="col-sm-8"></div> js //載入編輯器 $(document).ready(function () { //型別下拉框值 var sType = ""

在Vue中封裝一個檔案元件

封裝一個上傳檔案的元件,如下: 使用<input type='file'> 來實現檔案上傳,具體操作參照以往JS版的實現 這裡主要說作為一個元件,選中檔案之後,在輸入框中顯示檔名稱,點選Submit將將檔案傳給父元件,再由父元件提價到後臺

c# 模擬表單提交post form 檔案、大資料內容

表單提交協議規定: 要先將 HTTP 要求的 Content-Type 設為 multipart/form-data,而且要設定一個 boundary 引數, 這個引數是由應用程式自行產生,它會用來識別每一份資料的邊界 (boundary), 用以產生多重資訊部份 (me

使用vsftpd搭建ftp使用者無法檔案

553 Could not create file. 搭建完成之後,可以正常的進行使用者登入和上傳檔案等操作,卻不可以上傳檔案,一直提示553的錯誤。網上很多人說是防火牆導致的,然而在嘗試了他們的解決方法之後,依然存在這個問題。 給對應使用者目

網路程式設計(二)——伺服器客戶資訊的獲取

  目錄 1、字串IP地址和二進位制IP地址結構的轉換 2.套接字檔案描述符的判定 3、IP地址與域名之間的相互轉換 4、協議名稱處理函式 1、字串IP地址和二進位制IP地址結構的轉換 #include <sys/socket.h> #inclu