`

Java Socket学习---多线程阻塞

阅读更多

上篇 Java Socket学习---单线程阻塞 

这次文章中,是在上篇的基础上,在服务端使用了多线程的方式来管理连接,主线程负责接收连接,在接到连接后变创建新的线程,每个线程负责与自己的客户端进行通信。

与单线程阻塞的例子相比来说,服务端可以与多个客户端进行通信了,不过多线程频繁的创建与销毁便会带来很大的资源开销,而系统的网络资源等都是有限的;因此便可以引入线程池,可以在某种程度上重用线程,减少线程的创建和销毁的次数以减少开销。

 

下例代码中包含了使用和不使用线程池(针对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;
	}
}

 

 

2
1
分享到:
评论

相关推荐

    Java Socket学习---单线程阻塞

    "Java Socket学习---单线程阻塞"这个主题主要探讨了如何使用Java的Socket类进行单线程的阻塞式通信,这种模式通常用于简单的客户端-服务器应用。在这个场景中,服务器端通过一个线程处理一个客户端的请求,当请求被...

    Java Socket学习---nio实现阻塞多线程通信

    本篇文章将深入探讨如何使用Java NIO(非阻塞I/O)来实现阻塞多线程通信,这对于高性能服务器端应用尤其重要。我们将会分析`EchoServer.java`、`EchoClient.java`和`SocketUtils.java`这三个文件中的关键知识点。 ...

    java socket 多线程 简易实现

    Java Socket多线程简易实现是网络编程中的一个基础概念,主要应用于客户端与服务器之间的通信。在Java中,Socket是基于TCP协议的,提供了一种可靠的、面向连接的字节流通信方式。多线程则是Java并发编程的重要特性,...

    Java-network-socket-programming.zip_java programming_java socket

    Java网络套接字编程是Java编程领域中的一个重要组成部分,它涉及到如何通过网络在不同设备间进行数据通信。...在实际开发中,还需要结合多线程、异常处理和安全性策略,以确保程序的稳定性和安全性。

    java socket 学习资料

    - 对于高并发场景,可以考虑使用多线程或异步处理模型,避免阻塞主线程。 - 使用NIO(非阻塞I/O)的`Selector`和`Channel`可以提高服务器的吞吐量。 9. **安全性**: - 对于涉及敏感信息的通信,应使用SSL/TLS...

    Java Socket实例(服务器多线程)

    要查看具体的代码实现,你需要检查`src`目录下的文件,通常在`java`或`src/main/java`这样的路径下,找到相关的类文件,比如`ServerSocketThread.java`或其他类似的名字,那里会有实现多线程服务器的代码。

    java socket多线程文件传输实例项目

    Java Socket多线程文件传输实例项目是一个典型的网络编程应用场景,主要涉及了Socket编程、多线程处理以及文件I/O操作等关键知识点。在这个项目中,开发者利用Java的Socket API实现了一个能够支持多个客户端同时进行...

    Java TCP-IP Socket编程-卡尔弗特.pdf

    为了提高性能和减少资源消耗,Socket编程还涉及连接管理和多线程技术。服务器可能需要同时处理多个客户端连接,这时可以使用线程池或者并发处理模型。Java的ExecutorService和Future接口可以方便地管理并发任务。 ...

    java socket多线程聊天

    Java Socket多线程聊天软件是基于Java编程语言构建的一个网络通信应用,主要利用Socket API来实现客户端与服务器之间的实时通信。在这个系统中,服务器端能够同时处理多个客户端连接,这得益于Java的多线程特性。SWT...

    JAVA写的多线程socket通信程序源码

    在Java编程领域,多线程Socket通信是一种常见且重要的网络编程技术。Socket是TCP/IP协议栈中的一个关键组件,用于在网络中实现进程间的通信。在这个名为"JAVA写的多线程socket通信程序源码"的项目中,我们可以看到...

    Java Socket实战之二 多线程通信 .

    本篇主要探讨的是如何在Java中实现多线程通信,利用Socket技术构建高效的并发服务器。我们将结合"Java Socket实战之二 多线程通信"这篇博文进行深入解析。 首先,了解Socket的基本概念。Socket在计算机网络中扮演着...

    java socket通讯例程 多线程读写 可以同时收发不同终端的消息

    在主线程中通过控制台读取键盘输入时,会产生阻塞。故另外开启一个线程,用于接受客户端的socket消息。服务器在收到一个socket连接之后,把该socket保存到队列中,并对队列中的每个socket开启各自的读写线程。测试...

    java socket多线程多人聊天室

    本项目"java socket多线程多人聊天室"旨在利用Java的Socket API创建一个支持多个客户端同时连接的聊天环境。在这个项目中,主要涉及三个关键组件:Server(服务器)、Client(客户端)和User(用户)。 首先,`...

    TCP-socket.zip_java_java Tcp _java socket _socket_socket多线程

    这个学习资源可以帮助我们深入了解Java中的TCP Socket编程和多线程技术。 首先,让我们来看看TCP协议。TCP是一种面向连接的、可靠的传输协议,它保证了数据包在传输过程中的顺序和完整性。通过三次握手建立连接,四...

    学习笔记:多线程Java Socket编程示例

    在本学习笔记中,我们将探讨如何使用Java的Socket编程实现多线程服务器,特别是通过ExecutorService创建线程池来处理客户端的并发请求。ExecutorService是一个高级的线程管理工具,它允许我们更有效地管理和控制线程...

    socket-多线程-服务端代码

    学习和理解这个多线程Socket服务端代码可以帮助开发者更好地设计和实现高性能的网络服务,例如聊天服务器、文件传输服务或在线游戏服务器。同时,这也有助于理解并发编程和网络通信的基本原理,这些都是成为一名优秀...

    api-ntrip-java-client-master.zip_android_ntrip_ntrip java实现_ntr

    - **线程管理**:网络操作通常在后台线程执行,防止UI阻塞。 - **异步处理**:如使用AsyncTask或Retrofit进行异步网络请求。 - **数据缓存**:为了提高用户体验,可能需要缓存部分数据。 - **Android Studio IDE**:...

Global site tag (gtag.js) - Google Analytics