BIO编程方式通常是在JDK1.4版本之前常用的编程方式
一、编程实现的过程:
先在服务端启动一个ServerSocket来监听网络请求,客户端启动Socket发起网络请求,默认情况下ServerSocket会建立一个线程来处理此请求,如果服务端没有线程可用,客户端则会阻塞等待或者遭到拒绝,并且建立好的连接,在通信过程中是同步的,在并发处理上效率较低;
同步并阻塞,服务器实现模式为一个连接一个线程,即客户端有连接请求时服务器端就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开销,也可以通过线程池机制改善
BIO方式适用于连接数目比较小且固定的架构,这种方式对服务器资源要求比较高,并发局限于应用之中,是JDK1.4之前的唯一选择,但程序直观简单;
二、BIO编程步骤
-
Server:
- 创建ServerSocket实例;
- 绑定占用端口;
- 通过accept()方法监听并等待客户端的连接;
- 如果有客户端连接则会返回一个socket实例;
- 通过socket实例进行读写操作;
- 关闭占用资源和socket;
代码:(单线程)
public class BIOServer {
public static void main(String[] args) throws IOException {
//创建ServerSocket实例
ServerSocket socket = new ServerSocket();
//绑定端口
System.out.println("服务端启动");
socket.bind(new InetSocketAddress(666));
//监听等待客户端的连接,会阻塞直至用户端的连接
boolean flg = false;
while (true) {
Socket socket1 = socket.accept();
//进行通信
//读操作流
BufferedReader reader = null;
try {
reader = new BufferedReader(new InputStreamReader(socket1.getInputStream()));
OutputStream outputStream = socket1.getOutputStream();
String msg = null;
while ((msg = reader.readLine()) != null) {
System.out.println(msg);
outputStream.write(msg.getBytes());
outputStream.flush();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//关闭流
try {
reader.close();
socket1.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
-
Client
- 创建Socket实例;
- 通过connect()连接服务端;
- 进行读写操作;
- 关闭资源;
代码:
public class BIOClient {
public static void main(String[] args) throws IOException {
//客户端创建socket实例
Socket socket = new Socket();
//连接服务端
InetSocketAddress inetSocketAddress = new InetSocketAddress(666);
socket.connect(inetSocketAddress);
System.out.println("客户端连接成功");
//读写操作
OutputStream outputStream = socket.getOutputStream();
InputStream inputStream = socket.getInputStream();
Scanner scanner = new Scanner(System.in);
scanner.useDelimiter("\n");
while (scanner.hasNext()) {
//接收键盘输入
String nextLine = scanner.nextLine();
//发送操作
outputStream.write((nextLine + "\n").getBytes());
//接收服务端返回
byte[] bytes = new byte[1024];
int read = inputStream.read(bytes);
String revc = new String(bytes,0,read);
System.out.println("revc :" + revc);
if ("exit".equals(nextLine)) {
break;
}
}
outputStream.close();
scanner.close();
socket.close();
}
}
可以使用线程池对Server端代码进行优化,这里没有使用线程池而是手动创建一个子线程处理新用户的连接;
package network.BIO;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
/**
* @Author Daria
* @Description
* @Date 2019/5/18 -- 11:18
*/
class MyThread implements Runnable {
Socket socket;
public MyThread(Socket socket) { //将主线程拿到的socket实例交给子线程
this.socket = socket;
}
@Override
public void run() {
System.out.println("有新用户连接" + Thread.currentThread().getName() );
//进行通信
//读操作流
BufferedReader reader = null;
try {
reader = new BufferedReader(new InputStreamReader(this.socket.getInputStream()));
OutputStream outputStream = this.socket.getOutputStream();
String msg = null;
while ((msg = reader.readLine()) != null) {
System.out.println(msg);
outputStream.write(msg.getBytes());
outputStream.flush();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//关闭流
try {
reader.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public class BIOServer {
public static void main(String[] args) throws IOException {
//创建ServerSocket实例
ServerSocket socket = new ServerSocket();
//绑定端口
System.out.println("服务端启动");
socket.bind(new InetSocketAddress(666));
//监听等待客户端的连接,会阻塞直至用户端的连接
boolean flg = false;
while (true) {
Socket socket1 = socket.accept();
new Thread(new MyThread(socket1)).start(); //可以new Thread类,也可以使用λ表达式
/*new Thread(()-> {
System.out.println("有新用户连接" );
//进行通信
//读操作流
BufferedReader reader = null;
try {
reader = new BufferedReader(new InputStreamReader(socket1.getInputStream()));
OutputStream outputStream = socket1.getOutputStream();
String msg = null;
while ((msg = reader.readLine()) != null) {
System.out.println(msg);
outputStream.write(msg.getBytes());
outputStream.flush();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//关闭流
try {
reader.close();
socket1.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();*/
}
}
}
三、测试
启动Server端后打开两个Client