这次文章中,是在上篇的基础上,在服务端使用了多线程的方式来管理连接,主线程负责接收连接,在接到连接后变创建新的线程,每个线程负责与自己的客户端进行通信。
与单线程阻塞的例子相比来说,服务端可以与多个客户端进行通信了,不过多线程频繁的创建与销毁便会带来很大的资源开销,而系统的网络资源等都是有限的;因此便可以引入线程池,可以在某种程度上重用线程,减少线程的创建和销毁的次数以减少开销。
下例代码中包含了使用和不使用线程池(针对Server端)的两种方式,如果测试的时候,解开注释的代码即可以。
Server端代码:
package com.henushang.socket.chapter2; import java.io.BufferedReader; import java.io.IOException; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import com.henushang.socket.util.SocketUtils; public class EchoServer { private int port = 8000; private ServerSocket serverSocket; private ExecutorService executorService ; // 连接池 private final int POOL_SIZE = 4;// 连接池大小 public EchoServer() throws Exception{ serverSocket = new ServerSocket(port); executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * POOL_SIZE); System.out.println("waitting connet..."); } /** * 接受连接 * * @author henushang */ public void service() { Socket socket = null; while (true) { try { socket = serverSocket.accept(); executorService.execute(new Handler(socket));// 使用连接池 // new Thread(new Handler(socket)).start();// 不使用连接池 } catch (IOException e) { e.printStackTrace(); } } } public static void main(String[] args) throws Exception { new EchoServer().service(); } /** * 线程类,负责维持与一个客户端的通信 * * @author henushang */ class Handler implements Runnable{ private Socket socket = null; public Handler(Socket socket) { this.socket = socket; } @Override public void run() { System.out.println("new connection accepted:" + socket.getInetAddress() + ":" + socket.getPort()); try { BufferedReader reader = SocketUtils.getReader(this.socket); PrintWriter writer = SocketUtils.getWriter(this.socket); String msg = null; while ((msg = reader.readLine()) != null) { System.out.println(msg); // 因为客户端接收消息的时候使用的是readline()方法,如果消息没有以\r\n 结尾的话,客户端则接收不到消息 // writer.write(SocketUtils.echo(msg) + "\r\n"); writer.println(SocketUtils.echo(msg)); writer.flush(); if ("bye".equals(msg)) { break; } } } catch (IOException e) { e.printStackTrace(); } finally{ SocketUtils.close(socket); } } } }
Client端代码(与上次代码一样):
package com.henushang.socket; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.Socket; import com.henushang.socket.util.SocketUtils; public class EchoClient { private String host = "127.0.0.1"; private int port = 8000; private Socket socket ; public EchoClient() throws Exception { socket = new Socket(host, port); } public void talk() throws IOException { try { BufferedReader reader = SocketUtils.getReader(socket); PrintWriter writer = SocketUtils.getWriter(socket); // 读取本地控制台的消息 BufferedReader localReader = new BufferedReader(new InputStreamReader(System.in)); String msg = null; while ((msg = localReader.readLine()) != null) { writer.println(msg); writer.flush(); System.out.println(reader.readLine()); if ("bye".equals(msg)) { break; } } } catch (Exception e) { e.printStackTrace(); }finally { SocketUtils.close(socket); } } public static void main(String[] args) throws Exception{ new EchoClient().talk(); } }
SocketUtils代码:
package com.henushang.socket.util; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.PrintWriter; import java.net.Socket; import java.nio.channels.SocketChannel; public class SocketUtils { public static PrintWriter getWriter(Socket socket) throws IOException { OutputStream os = socket.getOutputStream(); return new PrintWriter(os); } public static PrintWriter getWriter(SocketChannel socketChannel) throws IOException { return getWriter(socketChannel.socket()); } public static BufferedReader getReader(Socket socket) throws IOException{ InputStream is = socket.getInputStream(); return new BufferedReader(new InputStreamReader(is, "UTF-8")); } public static BufferedReader getReader(SocketChannel socketChannel) throws IOException{ return getReader(socketChannel.socket()); } public static void close(Socket socket) { try { if (socket != null) { socket.close(); } } catch (Exception e) { e.printStackTrace(); } } public static void close(SocketChannel socketChannel) { try { if (socketChannel != null) { socketChannel.close(); } } catch (Exception e) { e.printStackTrace(); } } public static String echo(String msg) { return "echo:" + msg; } }
相关推荐
"Java Socket学习---单线程阻塞"这个主题主要探讨了如何使用Java的Socket类进行单线程的阻塞式通信,这种模式通常用于简单的客户端-服务器应用。在这个场景中,服务器端通过一个线程处理一个客户端的请求,当请求被...
本篇文章将深入探讨如何使用Java NIO(非阻塞I/O)来实现阻塞多线程通信,这对于高性能服务器端应用尤其重要。我们将会分析`EchoServer.java`、`EchoClient.java`和`SocketUtils.java`这三个文件中的关键知识点。 ...
Java Socket多线程简易实现是网络编程中的一个基础概念,主要应用于客户端与服务器之间的通信。在Java中,Socket是基于TCP协议的,提供了一种可靠的、面向连接的字节流通信方式。多线程则是Java并发编程的重要特性,...
Java网络套接字编程是Java编程领域中的一个重要组成部分,它涉及到如何通过网络在不同设备间进行数据通信。...在实际开发中,还需要结合多线程、异常处理和安全性策略,以确保程序的稳定性和安全性。
- 对于高并发场景,可以考虑使用多线程或异步处理模型,避免阻塞主线程。 - 使用NIO(非阻塞I/O)的`Selector`和`Channel`可以提高服务器的吞吐量。 9. **安全性**: - 对于涉及敏感信息的通信,应使用SSL/TLS...
要查看具体的代码实现,你需要检查`src`目录下的文件,通常在`java`或`src/main/java`这样的路径下,找到相关的类文件,比如`ServerSocketThread.java`或其他类似的名字,那里会有实现多线程服务器的代码。
Java Socket多线程文件传输实例项目是一个典型的网络编程应用场景,主要涉及了Socket编程、多线程处理以及文件I/O操作等关键知识点。在这个项目中,开发者利用Java的Socket API实现了一个能够支持多个客户端同时进行...
为了提高性能和减少资源消耗,Socket编程还涉及连接管理和多线程技术。服务器可能需要同时处理多个客户端连接,这时可以使用线程池或者并发处理模型。Java的ExecutorService和Future接口可以方便地管理并发任务。 ...
Java Socket多线程聊天软件是基于Java编程语言构建的一个网络通信应用,主要利用Socket API来实现客户端与服务器之间的实时通信。在这个系统中,服务器端能够同时处理多个客户端连接,这得益于Java的多线程特性。SWT...
在Java编程领域,多线程Socket通信是一种常见且重要的网络编程技术。Socket是TCP/IP协议栈中的一个关键组件,用于在网络中实现进程间的通信。在这个名为"JAVA写的多线程socket通信程序源码"的项目中,我们可以看到...
本篇主要探讨的是如何在Java中实现多线程通信,利用Socket技术构建高效的并发服务器。我们将结合"Java Socket实战之二 多线程通信"这篇博文进行深入解析。 首先,了解Socket的基本概念。Socket在计算机网络中扮演着...
在主线程中通过控制台读取键盘输入时,会产生阻塞。故另外开启一个线程,用于接受客户端的socket消息。服务器在收到一个socket连接之后,把该socket保存到队列中,并对队列中的每个socket开启各自的读写线程。测试...
本项目"java socket多线程多人聊天室"旨在利用Java的Socket API创建一个支持多个客户端同时连接的聊天环境。在这个项目中,主要涉及三个关键组件:Server(服务器)、Client(客户端)和User(用户)。 首先,`...
这个学习资源可以帮助我们深入了解Java中的TCP Socket编程和多线程技术。 首先,让我们来看看TCP协议。TCP是一种面向连接的、可靠的传输协议,它保证了数据包在传输过程中的顺序和完整性。通过三次握手建立连接,四...
在本学习笔记中,我们将探讨如何使用Java的Socket编程实现多线程服务器,特别是通过ExecutorService创建线程池来处理客户端的并发请求。ExecutorService是一个高级的线程管理工具,它允许我们更有效地管理和控制线程...
学习和理解这个多线程Socket服务端代码可以帮助开发者更好地设计和实现高性能的网络服务,例如聊天服务器、文件传输服务或在线游戏服务器。同时,这也有助于理解并发编程和网络通信的基本原理,这些都是成为一名优秀...
- **线程管理**:网络操作通常在后台线程执行,防止UI阻塞。 - **异步处理**:如使用AsyncTask或Retrofit进行异步网络请求。 - **数据缓存**:为了提高用户体验,可能需要缓存部分数据。 - **Android Studio IDE**:...