网络编程之每天学习一点点[day1]-----传统的bio编程

Socket又称“套接字”,应用程序通常通过“套接字”向网络发出请求或者应答网络发来的请求。

Socket和ServerSocket类库位于java.net包中,ServerSocket用于服务器端,Socket是建立网络连接时使用的。

在TCP连接成功时,在应用程序两端都会产生一个Socket实例,操作这个实例完成所需的会话。

对于一个TCP网络连接来说,套接字是平等的,不因为是在服务器端或者客户端而级别不同。

不管是Socket还是ServerSocket,它们的工作都是通过SocketImpl类及子类完成的。


在套接字之间的连接过程,可以分为四个步骤:服务器监听、客户端请求服务器、服务器确认、客户端确认。

(1)服务器监听:是服务器端套接字并不定位具体的客户端套接字,而是处于等待TCP连接的状态,实时监控网络状态。

(2)客户端请求:是指由客户端的套接字提出TCP连接请求,要连接的目标是客户端的套接字。因此,客户端的套接字必须描述其要连接的客户端的套接字,指出服务器端套接字的地址和端口,然后就向服务器端套接字提出TCP连接请求。

(3)服务器端连接确认:是指服务器端套接字监听到客户端的套接字的TCP连接请求,它就响应客户端套接字的TCP连接请求,建立一个新的线程,把服务器端的套接字描述发给客户端。也就是“一个TCP连接,一个线”。

(4)客户端连接确认:一旦客户端确认了此描述,连接就建立好了,双方开始通信,而服务器端套接字继续处于监听状态,继续接收其他客户端套接字的TCP连接请求。


网络编程的基本模型是Client/Server模型,也就是两个进程互相进行网络通信,其中服务器端提供配置信息(绑定的ip地址和端口),客户端通过连接操作向服务器端监听的端口发起TCP连接请求,通过三次握手建立连接,如果连接成功,则双方即可以通过网络套接字Socket进行通信。

如图:


服务器端为每一个Client发起的TCP连接建立了一个线程,这样做的缺点是,当客户端越来越多,服务器端将为每一个客户端发起的每一个TCP连接创建一个线程,这样服务器端将很容易不堪重负,内存消耗严重,且多线程的切换也会消耗CPU。此种编程方式称之为BIO-----blocking io,即阻塞IO。此种方式也是同步的,也叫同步阻塞IO。

  • 同步

同步(强调下BIO和NIO都是同步的IO,只是NIO是非阻塞的)体现在:应用程序会直接参与IO读写,并且

(1)使用BIO时,同步体现在:我们的应用程序会直接阻塞到某一个方法上,比如InputStream或者OutPutStream直到数据准备就绪才会继续执行下一步逻辑。

(2)使用NIO时,同步体现在:采用轮询的策略实时检查数据的就绪状态,如果就绪则获取数据执行下一步逻辑。

既然,BIO和NIO都是同步的,那么异步IO究竟是什么样子?

答:异步时,所有的IO读写操作交给操作系统来完成,与我们的应用程序没有直接关系,我们的程序不需要关心IO读写,当操作系统完成IO读写操作时,会给我们的应用程序发通知,应用程序直接把数据拿走即可。

同步和异步一般是我们到底使用的是操作系统还是应用程序对IO操作的角度来说的。


  • 阻塞

阻塞:应用程序在获取网络数据的时候,如果网络数据传输的很慢,那么程序就一直等待,直到传输完毕为止。

非阻塞:应用程序可以直接获取缓冲区准备好的数据,无需等待。像nio中,缓冲区数据就绪,服务端开启一个线程处理处理业务逻辑。




代码:

Server

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;


public class Server extends Thread {

	final static int PROT = 8765;
	
	public void run() {
			ServerSocket server = null;
			try {
				server = new ServerSocket(PROT);
				System.out.println(" server start .. ");
				while(true){
					//进行阻塞
					Socket socket = server.accept();
					/**
					 * 一个TCP连接一个线程
					 * 新建一个线程执行客户端的任务
					 */
					new Thread(new ServerHandler(socket)).start();
				}
			} catch (Exception e) {
				e.printStackTrace();
			} finally {
				if(server != null){
					try {
						server.close();
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
				server = null;
			}
}
	
	public static void main(String[] args) throws InterruptedException {
		Server server = new Server();
		server.start();
	}

	
}

Client:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;

public class Client extends Thread{

	final static String ADDRESS = "127.0.0.1";
	final static int PORT = 8765;
	
	private Socket socket;
	
	public Client(Socket socket){
		this.socket = socket;
	}
	
	public void run() {
		BufferedReader in = null;
		PrintWriter out = null;
		try {
			in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
			out = new PrintWriter(socket.getOutputStream(), true);
			//向服务器端发送数据
			out.println("接收到客户端的请求数据...");
			String response = in.readLine();
			System.out.println("Client: " + response);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if(in != null){
				try {
					in.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			if(out != null){
				try {
					out.close();
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
			if(socket != null){
				try {
					socket.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			socket = null;
		}
	}
	
	public static void main(String[] args) throws UnknownHostException, IOException, InterruptedException {
		Socket socket = new Socket(ADDRESS, PORT);
		Client client = new Client(socket);
		client.start();
		Thread.sleep(5000);
		Socket socket2 = new Socket(ADDRESS, PORT);
		Client client2 = new Client(socket2);
		client2.start();
	}
}

ServerHandler:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;

public class ServerHandler implements Runnable{

	private Socket socket ;
	
	public ServerHandler(Socket socket){
		this.socket = socket;
	}
	
	@Override
	public void run() {
		BufferedReader in = null;
		PrintWriter out = null;
		try {
			//读取字符串
			in = new BufferedReader(new InputStreamReader(this.socket.getInputStream()));
			out = new PrintWriter(this.socket.getOutputStream(), true);
			String body = null;
			while(true){
				//读取客户端发送的字符串 每次读取一行
				body = in.readLine();
				if(body == null) break;
				System.out.println("Server :" + body);
				out.println("服务器端回送响应数据.");
			}
			
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if(in != null){
				try {
					in.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			if(out != null){
				try {
					out.close();
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
			if(socket != null){
				try {
					socket.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			socket = null;
		}
		
		
	}

}

打印:

服务器端打印:

 server start .. 
Server :接收到客户端的请求数据...

客户端打印:

Client: 服务器端回送响应数据.






猜你喜欢

转载自blog.csdn.net/shengqianfeng/article/details/80716041