Java Socket构建阻塞的TCP通信

xiaoxiao2025-07-17  13

1.服务器端 1.创建ServerSocket对象,可在构造子中指定监听的端口;

privateintport = 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 publicclass EchoServer { privateintport = 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(); returnnew PrintWriter(socketOut, true); } private BufferedReader getReader(Socket socket) throws IOException { InputStream socketIn = socket.getInputStream(); returnnew BufferedReader(new InputStreamReader(socketIn)); } publicvoid 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(); } } } } publicstaticvoid main(String args[]) throws IOException { new EchoServer().service(); } }

2.客户端 1.创建一个Socket对象,指定服务器端的地址和端口;

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

这里作为客户端,它的端口是由操作系统随机产生的。

2.Socket类提供了getInputStream()方法和getOutputStream()方法。 InputStream socketIn = socket.getInputStream(); OutputStream socketOut = socket.getOutputStream(); 源代码EchoClient.java publicclass EchoClient { private String host = "localhost"; privateintport = 8000; private Socket socket; public EchoClient() throws IOException { socket = new Socket(host, port); } publicstaticvoid main(String args[]) throws IOException { new EchoClient().talk(); } private PrintWriter getWriter(Socket socket) throws IOException { OutputStream socketOut = socket.getOutputStream(); returnnew PrintWriter(socketOut, true); } private BufferedReader getReader(Socket socket) throws IOException { InputStream socketIn = socket.getInputStream(); returnnew BufferedReader(new InputStreamReader(socketIn)); } publicvoid 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 = newbyte[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; // 线程池 privatefinalintPOOL_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 publicclass MultiEchoServer { privateintport = 8000; private ServerSocket serverSocket; private ExecutorService executorService; // 线程池 privatefinalintPOOL_SIZE = 4; // 单个CPU时线程池中工作线程的数目 public MultiEchoServer() throws IOException { serverSocket = new ServerSocket(port); executorService = Executors.newFixedThreadPool(Runtime.getRuntime() .availableProcessors() * POOL_SIZE); System.out.println("Server Start"); } publicvoid service() { while (true) { Socket socket = null; try { socket = serverSocket.accept(); executorService.execute(new Handler(socket)); } catch (IOException e) { e.printStackTrace(); } } } publicstaticvoid 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(); returnnew PrintWriter(socketOut, true); } private BufferedReader getReader(Socket socket) throws IOException { InputStream socketIn = socket.getInputStream(); returnnew BufferedReader(new InputStreamReader(socketIn)); } public String echo(String msg) { return"echo:" + msg; } publicvoid 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(); } } } }
转载请注明原文地址: https://www.6miu.com/read-5033259.html

最新回复(0)