程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> Java Socket構建阻塞的TCP通信

Java Socket構建阻塞的TCP通信

編輯:關於JAVA

1.服務器端

1.創建ServerSocket對象,可在構造子中指定監聽的端口;

private int port = 8000;
private ServerSocket serverSocket;
……
serverSocket = new ServerSocket(port);

2.服務器端調用ServerSocket對象的accept()方法,該方法一直監聽端口,等待客戶的連接請求,如 果接收到一個連接請求,accept()方法就會返回一個Socket對象,這個Socket對象與客戶端的Socket對象 將形成一條通信線路;

Socket socket = null;
socket = serverSocket.accept(); // 等待客戶連接

3.Socket類提供了getInputStream()方法和getOutputStream()方法。

InputStream socketIn = socket.getInputStream();

OutputStream socketOut = socket.getOutputStream();

源代碼EchoServer.java

public class EchoServer {
   private int port = 8000;
   private ServerSocket serverSocket;
   public EchoServer() throws IOException {
    serverSocket = new ServerSocket(port);
    System.out.println("Server Start");
   }
   public String echo(String msg) {
    return "echo:" + msg;
   }
   private PrintWriter getWriter(Socket socket) throws IOException {
    OutputStream socketOut = socket.getOutputStream();
    return new PrintWriter(socketOut, true);
   }
   private BufferedReader getReader(Socket socket) throws IOException {
    InputStream socketIn = socket.getInputStream();
    return new BufferedReader(new InputStreamReader(socketIn));
   }
   public void service() {
    while (true) {
      Socket socket = null;
      try {
        socket = serverSocket.accept(); // 等待客戶連接
        System.out.println("New connection accepted "
           + socket.getInetAddress() + ":" + socket.getPort());
        BufferedReader br = getReader(socket);
        PrintWriter pw = getWriter(socket);
        String msg = null;
        while ((msg = br.readLine()) != null) {
          System.out.println(msg);
          pw.println(echo(msg));
          if (msg.equals("bye")) // 如果客戶發送的消息為“bye”,就結束通信
           break;
        }
      } catch (IOException e) {
        e.printStackTrace();
      } finally {
        try {
          if (socket != null)
           socket.close(); // 斷開連接
        } catch (IOException e) {
          e.printStackTrace();
        }
      }
    }
   }
   public static void main(String args[]) throws IOException {
    new EchoServer().service();
   }
}

2.客戶端

1.創建一個Socket對象,指定服務器端的地址和端口;

private String host = "localhost";
private int port = 8000;
private Socket socket;
……
socket = new Socket(host, port);

這裡作為客戶端,它的端口是由操作系統隨機產生的。

2.Socket類提供了getInputStream()方法和getOutputStream()方法。

InputStream socketIn = socket.getInputStream();

OutputStream socketOut = socket.getOutputStream();

源代碼EchoClient.java

public class EchoClient {
   private String host = "localhost";
   private int port = 8000;
   private Socket socket;
   public EchoClient() throws IOException {
    socket = new Socket(host, port);
   }
   public static void main(String args[]) throws IOException {
    new EchoClient().talk();
   }
   private PrintWriter getWriter(Socket socket) throws IOException {
    OutputStream socketOut = socket.getOutputStream();
    return new PrintWriter(socketOut, true);
   }
   private BufferedReader getReader(Socket socket) throws IOException {
    InputStream socketIn = socket.getInputStream();
    return new BufferedReader(new InputStreamReader(socketIn));
   }
   public void talk() throws IOException {
    try {
      BufferedReader br = getReader(socket);
      PrintWriter pw = getWriter(socket);
      BufferedReader localReader = new BufferedReader(
          new InputStreamReader(System.in));
      String msg = null;
      while ((msg = localReader.readLine()) != null) {
        pw.println(msg);
        System.out.println(br.readLine());
        if (msg.equals("bye"))
          break;
      }
    } catch (IOException e) {
      e.printStackTrace();
    } finally {
      try {
        socket.close();
      } catch (IOException e) {
        e.printStackTrace();
      }
    }
   }
}

3.關閉Socket

1.關閉Socket的代碼;

try {
    ……
   } catch (IOException e) {
    e.printStackTrace();
   } finally {
    try {
      socket.close();
    } catch (IOException e) {
      e.printStackTrace();
    }
   }

Socket類提供3個狀態測試方法。

-isClosed():如果Socket已經連接到遠程主機,並且還沒有關閉,則返回true;

-isConnected():如果Socket曾經連接到遠程主機,則返回true;

-isBound():如果Socket已經與一個本地端口綁定,則返回true。

判斷一個Socket對象當前是否處於連接狀態,

Boolean isConnected = socket.isConnected() && !socket.isClosed();

2.處理關閉

(1)當進程A與進程B交換的是字符流,並且是一行一行地讀寫數據時,可以事先約定一個特殊的標志 。

BufferedReader br = getReader(socket);
PrintWriter pw = getWriter(socket);
String msg = null;
while ((msg = br.readLine()) != null) {
   System.out.println(msg);
   pw.println(echo(msg));
   if (msg.equals("bye")) // 如果客戶發送的消息為“bye”,就結束通信
    break;
}

(2)進程A先發送一個消息,告訴進程B所發送的正文長度,然後發送正文。進程B只要讀取完該長度 的數據就可以停止讀數據。

(3)進程A發送完所有數據後,關閉Socket。當進程B讀入進程A發送的所有數據後,再次執行輸入流 的read()方法時,該方法返回-1.

InputStream socketIn = socket.getInputStream();
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
byte[] buff = new byte[1024];
int len = -1;
while ((len = socketIn.read(buff)) != -1) {
   buffer.write(buff, 0, len);
}
System.out.println(new String(buffer.toByteArray()));

(4)當調用Socket的close()方法關閉Socket時,它的輸入流和輸出流都被關閉。如果僅僅希望關閉 輸入或輸出流其中之一,可調用半關閉方法:shutdownInput()和shutdownOutput()。先後調用Socket的 shutdownInput()和shutdownOutput()方法,僅僅關閉輸入流和輸出流,並不等價於調用close()方法。在 通信結束後仍然需要調用close()方法,因為該方法才會釋放Socket占用的資源。

4.多線程服務器

EchoServer只能順序的處理Client端的請求,這裡使用ExecutorService指定一個線程池用於處理連接 請求。

private ExecutorService executorService; // 線程池
private final int POOL_SIZE = 4; // 單個CPU時線程池中工作線程的數目
…….
executorService = Executors.newFixedThreadPool(Runtime.getRuntime()
        .availableProcessors()* POOL_SIZE);
……
try {
    socket = serverSocket.accept();
    executorService.execute(new Handler(socket));
   } catch (IOException e) {
    e.printStackTrace();
   }

Hander類封裝了原來處理連接請求的邏輯,只要當前線程池中有空閒的線程,就可以用於處理請求。

源代碼MultiEchoServer.java

public class MultiEchoServer {
   private int port = 8000;
   private ServerSocket serverSocket;
   private ExecutorService executorService; // 線程池
   private final int POOL_SIZE = 4; // 單個CPU時線程池中工作線程的數目
   public MultiEchoServer() throws IOException {
    serverSocket = new ServerSocket(port);
    executorService = Executors.newFixedThreadPool(Runtime.getRuntime()
        .availableProcessors()
        * POOL_SIZE);
    System.out.println("Server Start");
   }
   public void service() {
    while (true) {
      Socket socket = null;
      try {
        socket = serverSocket.accept();
        executorService.execute(new Handler(socket));
      } catch (IOException e) {
        e.printStackTrace();
      }
    }
   }
   public static void main(String args[]) throws IOException {
    new MultiEchoServer().service();
   }
}
class Handler implements Runnable {
   private Socket socket;
   public Handler(Socket socket) {
    this.socket = socket;
   }
   private PrintWriter getWriter(Socket socket) throws IOException {
    OutputStream socketOut = socket.getOutputStream();
    return new PrintWriter(socketOut, true);
   }
   private BufferedReader getReader(Socket socket) throws IOException {
    InputStream socketIn = socket.getInputStream();
    return new BufferedReader(new InputStreamReader(socketIn));
   }
   public String echo(String msg) {
    return "echo:" + msg;
   }
   public void run() {
    try {
      System.out.println("New connection accepted "
          + socket.getInetAddress() + ":" + socket.getPort());
      BufferedReader br = getReader(socket);
      PrintWriter pw = getWriter(socket);
      String msg = null;
      while ((msg = br.readLine()) != null) {
        System.out.println(msg);
        pw.println(echo(msg));
        if (msg.equals("bye"))
          break;
      }
    } catch (IOException e) {
      e.printStackTrace();
    } finally {
      try {
        if (socket != null)
          socket.close();
      } catch (IOException e) {
        e.printStackTrace();
      }
    }
   }
}

參考 孫衛琴,《Java網絡編程精解》

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved