网络编程的基本模型是C/S模型,即两个进程间的通信。服务端提供IP和监听端口,客户端通过连接操作向服务端监听的地址发起连接请求,通过三次握手连接,如果连接建立成功,双方就可以通过套接字进行通信。
传统的同步阻塞模型开发中,ServerSocket负责绑定IP地址,启动监听端口;
Socket负责发起连接操作。
BIO模型
特点
BIO的服务端通信模型:采用BIO通信模型的服务端,通常由一个独立的Acceptor线程负责监听客户端的连接,它接收到客户端连接请求后为每个客户端创建一个新的线程进行链路处理,处理完成后,通过输出流返回应答给客户端,线程销毁。
请求——应答通宵模型。
缺点
缺乏弹性伸缩能力;
当客户并发访问量增加后,服务端的线程个数和客户端并发访问数呈一比一关系,java中线程是比较宝贵的系统资源,线程数量快速膨胀后,系统的性能将急剧下降,最终系统死掉。
代码实现
客户端
public class BIOClient {
private final String IP="127.0.0.1";//代词
private final int port=5803;
private Socket socket;//实现TCP编码的工具包
private Scanner scanner;
private BufferedReader reader;
private BufferedWriter writer;
public BIOClient(){
scanner=new Scanner(System.in);
try {
socket=new Socket(IP,port);
//客户端主动请求链接的方法 TCP的三次握手的发起
reader=new BufferedReader(new InputStreamReader
( socket.getInputStream()));//输入流 接受数据时使用
writer=new BufferedWriter(new OutputStreamWriter
( socket.getOutputStream()));//输出流 发送数
} catch (IOException e) {
e.printStackTrace();
}
}
public void startClient(){
try {
while (true) {
System.out.println("请输入你的请求:");
String send = scanner.nextLine();
writer.write(send + "\n");
writer.flush();
if(send.equals("exit")){
break;
}
String back = reader.readLine();
System.out.println("接受到服务器发回的消息" + back);
}
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
if(socket!=null) {
socket.close();
socket=null;
}
if(reader!=null){
reader.close();
reader=null;
}
if(writer!=null){
writer.close();
writer=null;
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
new BIOClient().startClient();
}
}
服务端
class ServerRunnable implements Runnable {
private Socket clientSocket;
private BufferedReader reader;
private BufferedWriter writer;
private Scanner scanner;
public ServerRunnable(Socket clientSocket, BufferedWriter writer,
BufferedReader reader, Scanner scanner) {
this.clientSocket = clientSocket;
this.reader = reader;
this.writer = writer;
this.scanner = scanner;
}
@Override
public void run() {
try {
while (true) {
String s = null;
s = reader.readLine();
System.out.println("接受到客户端发送的数据" + s);
if (s.equals("exit")) {
break;
}
//根据收到的信息做相应的逻辑处理
System.out.println("请输入你向客户端回复的信息:");
String send = scanner.nextLine();
writer.write(send + "\n");//注意加“/n”刷新发送缓冲区
writer.flush();//针对writer刷新
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (reader != null) {
reader.close();
reader = null;
}
if (writer != null) {
writer.close();
writer = null;
}
if (clientSocket != null) {
clientSocket.close();
clientSocket = null;
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public class BIOServer {
private final int port = 5803;//如果不写就会随机分配一个(5000,65535)
private ServerSocket socket;//实现TCP编码的工具包
private BufferedReader reader;
private BufferedWriter writer;
private Scanner scanner;
public BIOServer() {
try {
socket = new ServerSocket(port);
scanner = new Scanner(System.in);
} catch (IOException e) {
e.printStackTrace();
}
}
public void startSrever() {
Socket clientSocket = null;
try {
while (true) {
clientSocket = socket.accept();//不能写到循环里 会阻塞
//阻塞方法:获取客户端socket的方法 这个socket是客户端与服务器完成连接建立之后得到的返回值
//TCP三次握手 clientSocket是与建立好连接的客户端是一一对应的
//所有的通信过程都是使用clientSocket
//字节和字符的转换 转换流解决
reader =
new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));//输入流 接收数据
writer = new BufferedWriter(
new OutputStreamWriter(clientSocket.getOutputStream()));//输出流 发送数据的时候使用
ServerRunnable runnable = new ServerRunnable(clientSocket, writer, reader, scanner);
Thread mythread = new Thread(runnable);
mythread.start();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (socket != null) {
socket.close();
socket = null;
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
new BIOServer().startSrever();
}
NIO模型
NIO太多了下篇介绍~