网络编程之每天学习一点点[day1]-----传统的bio编程
发布日期:2021-06-30 13:45:15 浏览次数:2 分类:技术文章

本文共 4945 字,大约阅读时间需要 16 分钟。

Socket套接字编程介绍

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中,缓冲区数据就绪,服务端开启一个线程处理处理业务逻辑。

 

BIO的java编码实现

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: 服务器端回送响应数据.

 


 

 

 

转载地址:https://jeffsheng.blog.csdn.net/article/details/80716041 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:网络编程之每天学习一点点[day2]-----伪异步IO
下一篇:每天一例多线程[day25]-----Disruptor之多生产者多消费者

发表评论

最新留言

第一次来,支持一个
[***.219.124.196]2024年05月05日 15时47分10秒