JavaSocket构建阻塞的TCP通信

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网络编程精解》

在乎的是看风景的心情,旅行不会因为美丽的风景终止。

JavaSocket构建阻塞的TCP通信

相关文章:

你感兴趣的文章:

标签云: