【Java】同步阻塞式(BIO)TCP通信
TCP BIO
背景
网络编程的基本模型是Clien/Server模型,也就是两个进程之间进行相互通信,其中服务端提供位置信息(绑定的IP地址和监听端口),客户端通过连接操作向服务端监听的地址发起连接请求,通过三次握手建立连接,如果连接建立成功,双方就可以通过socket进行通信。socket相当于通信的媒介,用来传输数据。
Java处理TCP的类主要有Socket和ServerSocket,基于传统同步阻塞模型(Blocking IO)开发中,ServerSocket负责绑定IP地址,启动监听端口;Socket负责发起连接操作。连接成功之后,双方通过输入和输出流进行同步阻塞式通信。
模型
下图是一个BIO的服务端通信模型:采用BIO通信模型的服务端,通常由一个独立的Acceptor线程负责监听客户端的连接,它接受到客户端连接请求后为每一个客户端创建一个新的线程进行链路处理,处理完之后通过流应答给客户端,线程销毁。
这种模型的缺点十分明显,当客户端大量请求到达时,由于线程笨重、占用资源大等特点,服务端无法承受巨大的开销,易导致服务宕机。
代码
首先是客户端代码,在代码中可以看到,客户端向127.0.0.1:20006的地址发送连接请求,当连接建立时,通过IO流输出字符串到socket中,并读取socket返回的信息。代码比较简单,就没写注释了_
Client.java:
public class Client {
public static final int PORT = 20006;
public static final String ADDR = "127.0.0.1";
public static void main(String[] args) {
Socket socket = null;
BufferedReader in = null;
PrintStream out = null;
try {
socket = new Socket(ADDR, PORT);
socket.setSoTimeout(2000);
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
out = new PrintStream(socket.getOutputStream());
out.println("1:Hello server!");
out.println("2:Hello server!");
out.println("bye");
String line = in.readLine();
System.out.println("Receive from server: " + line);
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (SocketTimeoutException e) {
System.out.println("server time out, exit!");
}
catch (IOException e) {
e.printStackTrace();
} finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (out != null) {
out.close();
}
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
服务端代码如下,
服务端类首先创建ServerSocket对象,绑定要监听的端口,进行监听循环,当有客户端请求达到时,会触发accept事件并返回一个客户端socket对象,这时,就有多种处理方法了,我在Server.java中用注释写到三种处理客户端socket的方式:
1.单线程处理,即服务端只用一个线程处理客户端请求,一次只能处理一个请求,其他请求来了就在后面阻塞着吧。代码如注释中。
2.多线程处理,为每一个客户端请求分配一个线程去处理,处理完线程销毁,处理线程是Handler.java。
3.线程池处理,这个方法跟第二种方法区别主要在于分配了固定数量的线程,当一个线程处理完一个客户端请求时不会销毁而是回到线程池中。线程池类是HandlerExecutor.java。
Server.java
public class Server {
public static final int PORT = 20006;
public static void main(String[] args) throws IOException {
ServerSocket server = null;
try {
server = new ServerSocket(PORT);
Socket client = null;
System.out.println("Server is listening on " + PORT);
while (true) {
client = server.accept();
//单线程
// BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
// System.out.println(in.readLine());
// PrintWriter out = new PrintWriter(client.getOutputStream(), true);
// out.println("hello client");
// in.close();
// out.close();
//多线程
// new Thread(new Handler(client)).start();
//线程池
HandlerExecutor executor = new HandlerExecutor(10, 100);
executor.execute(new Handler(client));
// ExecutorService executor = Executors.newScheduledThreadPool(10);
// executor.submit(new Handler(client));
}
} finally {
if (server != null) {
System.out.println("server is closed!");
server.close();
}
}
}
}
处理类Handler.java
public class Handler implements Runnable {
private Socket socket;
public Handler (Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try {
BufferedReader in = new BufferedReader(new InputStreamReader(this.socket.getInputStream()));
while (true) {
String s = in.readLine();
if (s == null || "bye".equals(s)) {
break;
}
System.out.println(s);
}
PrintWriter out = new PrintWriter(this.socket.getOutputStream(), true);
out.println("hello client");
in.close();
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
线程池类:HandlerExecutor.java
public class HandlerExecutor {
private ExecutorService executor;
public HandlerExecutor(int maxPoolSize, int queueSize) {
executor = new ThreadPoolExecutor(Runtime.getRuntime().availableProcessors(), maxPoolSize, 120L,
TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(queueSize));
}
public void execute(Runnable task) {
executor.submit(task);
}
}
参考文献
- 《Netty权威指南》2.1章节
【Java】同步阻塞式(BIO)TCP通信的更多相关文章
- IO通信模型(一)同步阻塞模式BIO(Blocking IO)
几个概念 阻塞IO 和非阻塞IO 这两个概念是程序级别的.主要描述的是程序请求操作系统IO操作后,如果IO资源没有准备好,那么程序该如何处理的问题:前者等待:后者继续执行(但是使用线程一直轮询,直到有 ...
- java网络通信:同步阻塞式I/O模型(BIO)
缺点:一个线程只能处理一个客户端连接 服务端: public class TimeServer { public static void main(String[] args) throws IOEx ...
- Java NIO阻塞式通信
package com.nio.t; import java.io.IOException; import java.net.InetSocketAddress; import java.nio.By ...
- Java IO(2)阻塞式输入输出(BIO)的字节流与字符流
在上文中<Java IO(1)基础知识——字节与字符>了解到了什么是字节和字符,主要是为了对Java IO中有关字节流和字符流有一个更好的了解. 本文所述的输出输出指的是Java中传统的I ...
- Java IO(2)阻塞式输入输出(BIO)
在上文中<Java IO(1)基础知识——字节与字符>了解到了什么是字节和字符,主要是为了对Java IO中有关字节流和字符流有一个更好的了解. 本文所述的输出输出指的是Java中传统的I ...
- IO同步阻塞与同步非阻塞
BIO.NIO.AIO IO(BIO)和NIO区别:其本质就是阻塞和非阻塞的区别 阻塞概念:应用程序在获取网络数据的时候,如果网络传输数据很慢,就会一直等待,直到传输完毕为止. 非阻塞概念:应用程序直 ...
- Java基础知识强化之多线程笔记07:同步、异步、阻塞式、非阻塞式 的联系与区别
1. 同步: 所谓同步,就是在发出一个功能调用时,在没有得到结果之前,该调用就不返回.但是一旦调用返回,就必须先得到返回值了. 换句话话说,调用者主动等待这个"调用"的结果. 对于 ...
- java的nio之:java的bio流下实现的socket服务器同步阻塞模型和socket的伪异步的socket服务器的通信模型
同步I/O模型的弊端===>每一个线程的创建都会消耗服务端内存,当大量请求进来,会耗尽内存,导致服务宕机 伪异步I/O的弊端分析===>当对Socket的输入流进行读取操作的时候,它会一直 ...
- Java IO------------------BIO(同步阻塞)、NIO1.0(多路复用)、NIO2.0(AIO,非阻塞)
1. BIO JDK5之前, JDK的IO模式只有BIO(同步阻塞)问题: 因为阻塞的存在, 需对每个请求开启一个线程. 过多的线程切换影响操作系统性能解决: 使用线程池, 处理不过来的放入队列, 再 ...
随机推荐
- iOS 中的 xml 解析
在ios 中解析xml 的方法有很多种 1.苹果原生 NSXMLParser:SAX方式解析,使用简单 2.第三方框架 libxml2:纯c语言,默认包含在ios sdk中,同时支持DOM 和 SA ...
- spring整合ehcache2.5.2缓存异常-- net.sf.ehcache.CacheException
报错如下: The source of the existing CacheManager is: DefaultConfigurationSource [ ehcache.xml or ehcach ...
- Potential Pythonic Pitfalls
Potential Pythonic Pitfalls Monday, 11 May 2015 Table of Contents Not Knowing the Python Version Obs ...
- Linux 内核里的“智能指针”【转】
转自:http://blog.jobbole.com/88279/ 众所周知,C/C++语言本身并不支持垃圾回收机制,虽然语言本身具有极高的灵活性,但是当遇到大型的项目时,繁琐的内存管理往往让人痛苦异 ...
- llinux除了软连接本地文件夹同步:mount
mount --bind /srv/dir1 /srv/dir2dir1:被共享的文件夹dir2:需要同步的文件夹
- Vue+ajax的使用小结
js var vue = new Vue({ el:"#vueid", data:{ selectById : "", }, methods:{ yourMet ...
- ajax返回json对象的两种写法
1. 前言 dataType: 要求为String类型的参数,预期服务器返回的数据类型.如果不指定,JQuery将自动根据http包mime信息返回responseXML或responseText,并 ...
- MariaDB和mySQL到底区别在哪,实验说明问题!
先看图,插入数据和时间的对数图,实验条件一直且关闭了mysql默认事务保证不是单条事务而是批量事务 另外确保了mysql and mariaDB都是在支持事务存储引擎下测试的. MySQL之父Wide ...
- CCF2016092火车购票
问题描述 请实现一个铁路购票系统的简单座位分配算法,来处理一节车厢的座位分配. 假设一节车厢有20排.每一排5个座位.为方便起见,我们用1到100来给所有的座位编号,第一排是1到5号,第二排是6到10 ...
- 区间dp的一些模式和总结
参考博客:https://blog.csdn.net/my_sunshine26/article/details/77141398 https://blog.csdn.net/qq_38569113/ ...