欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java Socket編程簡介_動力節(jié)點Java學院整理

 更新時間:2017年05月27日 11:27:38   投稿:mrr  
這篇文章主要介紹了Java Socket編程簡介的相關(guān)知識,非常不錯,具有參考借鑒價值,需要的朋友可以參考下

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

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

      1、客戶端寫服務端讀

       服務端代碼 

Java代碼  

 public class Server { 
 public static void main(String args[]) throws IOException { 
 //為了簡單起見,所有的異常信息都往外拋 
 int port = 8899; 
 //定義一個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(); 
 } 
 } 

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

       客戶端代碼

Java代碼  

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

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

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

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

       服務端代碼 

Java代碼    

public class Server { 
 public static void main(String args[]) throws IOException { 
 //為了簡單起見,所有的異常信息都往外拋 
 int port = 8899; 
 //定義一個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)閉對應的資源文件。而實際上上述代碼可能并不會按照我們預先設(shè)想的方式運行,因為從輸入流中讀取數(shù)據(jù)是一個阻塞式操作,在上述的while循環(huán)中當讀到數(shù)據(jù)的時候就會執(zhí)行循環(huán)體,否則就會阻塞,這樣后面的寫操作就永遠都執(zhí)行不了了。除非客戶端對應的Socket關(guān)閉了阻塞才會停止,while循環(huán)也會跳出。針對這種可能永遠無法執(zhí)行下去的情況的解決方法是while循環(huán)需要在里面有條件的跳出來,縱觀上述代碼,在不斷變化的也只有取到的長度len和讀到的數(shù)據(jù)了,len已經(jīng)是不能用的了,唯一能用的就是讀到的數(shù)據(jù)了。針對這種情況,通常我們都會約定一個結(jié)束標記,當客戶端發(fā)送過來的數(shù)據(jù)包含某個結(jié)束標記時就說明當前的數(shù)據(jù)已經(jīng)發(fā)送完畢了,這個時候我們就可以進行循環(huán)的跳出了。那么改進后的代碼會是這個樣子:

Java代碼  

 public class Server { 
 public static void main(String args[]) throws IOException { 
 //為了簡單起見,所有的異常信息都往外拋 
 int port = 8899; 
 //定義一個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時就結(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(); 
 } 
 } 

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

       客戶端代碼

Java代碼       

public class Client { 
 
 public static void main(String args[]) throws Exception { 
 //為了簡單起見,所有的異常都直接往外拋 
 String host = "127.0.0.1"; //要連接的服務端IP地址 
 int port = 8899; //要連接的服務端對應的監(jiān)聽端口 
 //與服務端建立連接 
 Socket client = new Socket(host, port); 
 //建立連接后就可以往服務端寫數(shù)據(jù)了 
 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(); 
 } 
 } 

在上述代碼中我們先是給服務端發(fā)送了一段數(shù)據(jù),之后讀取服務端返回來的數(shù)據(jù),跟之前的服務端一樣在讀的過程中有可能導致程序一直掛在那里,永遠跳不出while循環(huán)。這段代碼配合服務端的第一段代碼就正好讓我們分析服務端永遠在那里接收數(shù)據(jù),永遠跳不出while循環(huán),也就沒有之后的服務端返回數(shù)據(jù)給客戶端,客戶端也就不可能接收到服務端返回的數(shù)據(jù)。解決方法如服務端第二段代碼所示,在客戶端發(fā)送數(shù)據(jù)完畢后,往輸出流里面寫入結(jié)束標記告訴服務端數(shù)據(jù)已經(jīng)發(fā)送完畢了,同樣服務端返回數(shù)據(jù)完畢后也發(fā)一個標記告訴客戶端。那么修改后的客戶端代碼就應該是這個樣子:

Java代碼    

public class Client { 
 public static void main(String args[]) throws Exception { 
 //為了簡單起見,所有的異常都直接往外拋 
 String host = "127.0.0.1"; //要連接的服務端IP地址 
 int port = 8899; //要連接的服務端對應的監(jiān)聽端口 
 //與服務端建立連接 
 Socket client = new Socket(host, port); 
 //建立連接后就可以往服務端寫數(shù)據(jù)了 
 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(); 
 } 
 } 

      

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

      3、多個客戶端連接同一個服務端

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

Java代碼       

public class Server { 
 public static void main(String args[]) throws IOException { 
 //為了簡單起見,所有的異常信息都往外拋 
 int port = 8899; 
 //定義一個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時就結(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(); 
 } 
 } 
 } 

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

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

Java代碼       

public class Server { 
 public static void main(String args[]) throws IOException { 
 //為了簡單起見,所有的異常信息都往外拋 
 int port = 8899; 
 //定義一個ServerSocket監(jiān)聽在端口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時就結(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接收到一個新的Socket連接請求后都會新起一個線程來跟當前Socket進行通信,這樣就達到了異步處理與客戶端Socket進行通信的情況。

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

Java代碼       

 public class Server { 
 public static void main(String args[]) throws IOException { 
 //為了簡單起見,所有的異常信息都往外拋 
 int port = 8899; 
 //定義一個ServerSocket監(jiān)聽在端口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時就結(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(); 
 } 
 } 
 } 

這個時候需要注意的是,BufferedReader的readLine方法是一次讀一行的,這個方法是阻塞的,直到它讀到了一行數(shù)據(jù)為止程序才會繼續(xù)往下執(zhí)行,那么readLine什么時候才會讀到一行呢?直到程序遇到了換行符或者是對應流的結(jié)束符readLine方法才會認為讀到了一行,才會結(jié)束其阻塞,讓程序繼續(xù)往下執(zhí)行。所以我們在使用BufferedReader的readLine讀取數(shù)據(jù)的時候一定要記得在對應的輸出流里面一定要寫入換行符(流結(jié)束之后會自動標記為結(jié)束,readLine可以識別),寫入換行符之后一定記得如果輸出流不是馬上關(guān)閉的情況下記得flush一下,這樣數(shù)據(jù)才會真正的從緩沖區(qū)里面寫入。對應上面的代碼我們的客戶端程序應該這樣寫:

Java代碼

 public class Client { 
 public static void main(String args[]) throws Exception { 
 //為了簡單起見,所有的異常都直接往外拋 
 String host = "127.0.0.1"; //要連接的服務端IP地址 
 int port = 8899; //要連接的服務端對應的監(jiān)聽端口 
 //與服務端建立連接 
 Socket client = new Socket(host, port); 
 //建立連接后就可以往服務端寫數(shù)據(jù)了 
 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、設(shè)置超時時間

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

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

Java代碼  

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

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

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

Java代碼 

 public class Server { 
 public static void main(String args[]) throws IOException { 
 //為了簡單起見,所有的異常信息都往外拋 
 int port = 8899; 
 //定義一個ServerSocket監(jiān)聽在端口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時就結(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(); 
 } 
 } 
 } 

這里用來測試我就弄的混亂了一點。在上面服務端代碼中我們在定義輸入流的時候明確定義了使用GBK編碼來讀取數(shù)據(jù),而在定義輸出流的時候明確指定了將使用UTF-8編碼來發(fā)送數(shù)據(jù)。如果客戶端上送數(shù)據(jù)的時候不以GBK編碼來發(fā)送的話服務端接收的數(shù)據(jù)就很有可能會亂碼;同樣如果客戶端接收數(shù)據(jù)的時候不以服務端發(fā)送數(shù)據(jù)的編碼,即UTF-8編碼來接收數(shù)據(jù)的話也極有可能會出現(xiàn)數(shù)據(jù)亂碼的情況。所以,對于上述服務端代碼,為使我們的程序能夠讀取對方發(fā)送過來的數(shù)據(jù),而不出現(xiàn)亂碼情況,我們的客戶端應該是這樣的:

Java代碼

public class Client { 
 public static void main(String args[]) throws Exception { 
 //為了簡單起見,所有的異常都直接往外拋 
 String host = "127.0.0.1"; //要連接的服務端IP地址 
 int port = 8899; //要連接的服務端對應的監(jiān)聽端口 
 //與服務端建立連接 
 Socket client = new Socket(host, port); 
 //建立連接后就可以往服務端寫數(shù)據(jù)了 
 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")); 
 //設(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ù)讀取超時。"); 
 } 
 System.out.println("服務端: " + sb); 
 writer.close(); 
 br.close(); 
 client.close(); 
 } 
 } 

相關(guān)文章

  • Jmeter參數(shù)化獲取序列數(shù)據(jù)實現(xiàn)過程

    Jmeter參數(shù)化獲取序列數(shù)據(jù)實現(xiàn)過程

    這篇文章主要介紹了Jmeter參數(shù)化獲取序列數(shù)據(jù)實現(xiàn)過程,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-07-07
  • 使用maven的profile構(gòu)建不同環(huán)境配置的方法

    使用maven的profile構(gòu)建不同環(huán)境配置的方法

    這篇文章主要介紹了使用maven的profile構(gòu)建不同環(huán)境配置的方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2021-01-01
  • java根據(jù)本地IP獲取mac地址的方法

    java根據(jù)本地IP獲取mac地址的方法

    這篇文章主要為大家詳細介紹了java根據(jù)本地IP獲取mac地址的方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-06-06
  • 如何在java 8 map中使用stream

    如何在java 8 map中使用stream

    這篇文章主要介紹了如何在java 8 map中使用stream,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-04-04
  • Java多線程Atomic包操作原子變量與原子類詳解

    Java多線程Atomic包操作原子變量與原子類詳解

    這篇文章主要介紹了Java多線程Atomic包操作原子變量與原子類詳解,簡單介紹了Atomic,同時涉及java.util.concurrent中的原子變量,Atomic類的作用等相關(guān)內(nèi)容,具有一定參考價值,需要的朋友可以了解下。
    2017-11-11
  • Java實現(xiàn)給網(wǎng)站上傳圖片蓋章的方法

    Java實現(xiàn)給網(wǎng)站上傳圖片蓋章的方法

    這篇文章主要介紹了Java實現(xiàn)給網(wǎng)站上傳圖片蓋章的方法,涉及java針對圖片的合成操作技巧,類似水印功能,需要的朋友可以參考下
    2015-07-07
  • Spring Boot整合FTPClient線程池的實現(xiàn)示例

    Spring Boot整合FTPClient線程池的實現(xiàn)示例

    這篇文章主要介紹了Spring Boot整合FTPClient線程池的實現(xiàn)示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-12-12
  • Spring框架核心概念小結(jié)

    Spring框架核心概念小結(jié)

    Spring是企業(yè)級Java的開源開發(fā)框架。Spring框架的核心功能可用于開發(fā)任何java應用程序,本文重點給大家介紹Spring框架核心概念總覽,感興趣的朋友跟隨小編一起看看吧
    2022-02-02
  • Java值得使用Lambda的8個場景合集

    Java值得使用Lambda的8個場景合集

    可能對不少人來說,Lambda顯得陌生又復雜,覺得Lambda會導致代碼可讀性下降,但畢竟2023年了,JDK都出了那么多新版本,是時候試試Lambda了
    2023-08-08
  • 如何設(shè)置Spring Boot測試時的日志級別

    如何設(shè)置Spring Boot測試時的日志級別

    Spring Boot是由Pivotal團隊提供的全新框架,其設(shè)計目的是用來簡化新Spring應用的初始搭建以及開發(fā)過程。該框架使用了特定的方式來進行配置,從而使開發(fā)人員不再需要定義樣板化的配置。下面我們來一起學習一下吧
    2019-06-06

最新評論