Socket网络通信之BIO

如果要让两台计算机实现通信,需要的条件:ip,port,协议。

目前我们用的最多的就是TCP/IP协议和UDP协议。TCP三次握手,所以比较慢,且安全;UDP速度快,但是可能丢包,不能保证安全。

网络通讯基本都是通过Socket来通讯的。(客户端的Socket类;服务端的ServerSocket类)

客户端和服务端这样建立连接:第一步客户端发起建立连接的请求,第二部服务端收到请求建立连接的请求,并同意和该客户端建立连接,并响应给客户端,第三步客户端收到服务端响应的建立连接的消息,并确认和服务端建立连接,通过这样三部客户端和服务端就真正的建立了连接,服务端和客户端就可以开始通讯,交互了.通过这样三次的握手交互服务端和客户端就成功的建立了连接,如下图所示

而JAVA中实现通信的IO主要是:同步阻塞IO(BIO)、同步非阻塞IO(NIO)、异步非阻塞IO(AIO)

同步阻塞IO(BIO)— 原生态

public class BioServer {

    private  static Charset charset = Charset.forName("UTF-8");
public static void main(String[] args) {
int port = 1100; try ( ServerSocket socketServer = new ServerSocket(port)){
while (true){
//接收连接,如果没有连接建立,这里会阻塞
Socket socket = socketServer.accept();
BufferedReader reader = new BufferedReader(
new InputStreamReader(socket.getInputStream(), charset)
);
String msg = null;
//连接进来后,会在这里等待客户端发送消息。
while ((msg =reader.readLine())!=null){
System.out.println(msg);
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}

BioServer

如上为server代码,下面为client代码

public class BioClient implements  Runnable{
private String address;
private int port; public static void main(String[] args) {
BioClient client = new BioClient("localhost", 1100);
client.run();
} @Override
public void run() {
try(Socket socket = new Socket(address, port);
OutputStream outputStream = socket.getOutputStream()) { Scanner scanner = new Scanner(System.in);
System.out.println("请输入:");
String msg = scanner.nextLine();
outputStream.write(msg.getBytes("UTF-8"));
} catch (IOException e) {
e.printStackTrace();
}
} public int getPort() {
return port;
} public void setPort(int port) {
this.port = port;
} public String getAddress() {
return address;
} public void setAddress(String address) {
this.address = address;
}
public BioClient(String address, int port) {
super();
this.address=address;
this.port = port;
}
}

BioClient

首先用debug启动BioServer。
可以看到在debug模式下,下一步不能再执行,程序阻塞在连接处,等待连接。

启动客户端BioClient以后,可以看到服务端已经连接,debug可以下一步,如下图。

执行下一步下一步之后,等待客户端发送信息处,又阻塞,程序debug再次执行不下去,如下图:

现在如果在客户端输入信息,再次debug下一步,服务端就会收到相应的信息。
这就是一个简单的BIO,从这个过程中,我们可以看到:服务器端代码必须要在连接处和接收消息处阻塞,只用得到了相应的信息,才会往下继续执行。如果多个客户端一起请求,大家都会阻塞在此处,这样的程序效率及其低下,甚至长期等待不能用。有什么办法能够解决这样的问题呢?。

同步阻塞IO(BIO)— 多线程

public class BIOServerV2 {
private static Charset charset = Charset.forName("UTF-8");
public static void main(String[] args) {
int port = 1101;
try (ServerSocket ss = new ServerSocket(port);) {
while (true) {
Socket s = ss.accept();
// 开一个线程去处理这个连接
new Thread(new SocketProcess(s)).start();
}
} catch (IOException e) {
e.printStackTrace();
}
} static class SocketProcess implements Runnable {
Socket s;
public SocketProcess(Socket s) {
super();
this.s = s;
} @Override
public void run() {
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(s.getInputStream(), charset));) {
// 接收数据、打印
String mess = null;
while ((mess = reader.readLine()) != null) {
System.out.println(mess);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

BIOServerV2

如上代码所示,我们稍微改动了一下服务器端的代码,客户端只需要改动和服务端一样的端口号就行,这里使用多线程的方式。

这里是利用多线程的方式来实现,在连接处多开线程去处理,这样多个客户端连接时,就不会大家一致排队阻塞在此处,但是阻塞还是存在的。还有什么更好的办法来解决这样的问题吗?

同步阻塞IO(BIO)— 线程池

public class BIOServerV3 {
private static Charset charset = Charset.forName("UTF-8");
public static void main(String[] args) {
int port = 1102;
int threads = 100;
ExecutorService tpool = Executors.newFixedThreadPool(threads); try (ServerSocket ss = new ServerSocket(port);) {
while (true) {
Socket s = ss.accept();
// 丢到线程池中去跑
tpool.execute(new SocketProcess(s));
}
} catch (IOException e) {
e.printStackTrace();
}
tpool.shutdown();
} static class SocketProcess implements Runnable {
Socket s; public SocketProcess(Socket s) {
super();
this.s = s;
} @Override
public void run() {
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(s.getInputStream(), charset));) {
// 接收数据、打印
String mess = null;
while ((mess = reader.readLine()) != null) {
System.out.println(mess);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

BIOServerV3

如上所示,我们再次改动,改成以线程池的办法来连接。但是线程池也有问题:

请求大于线程,没有足够的线程来处理,响应时间很长,甚至服务器拒绝。

阻塞等待接收客户端的数据时,这段时间占着线程,而池中线程数是有限的,并发量大时,将导致没有线程处理请求,请求的响应时间长,甚至拒绝服务。

从上面三部分的代码可以看出来,代码性能等问题,全是阻塞惹的祸,如果没有阻塞就好了,如果能不阻塞,在没有数据时,就去干点别的事情,有数据了才处理数据。

详情请见下一个博客:Socket网络通信之NIO

Socket网络通信之BIO的更多相关文章

  1. Socket网络通信之NIO

    Socket网络通信之NIO NIO:new io ,java1.4开始推出的可非阻塞IO. java.nio 包,可解决BIO阻塞的不足 但比BIO学习.使用复杂. 可以以阻塞.非阻塞两种方式工作. ...

  2. Socket 网络通信

    Socket 网络通信 1.OSI (Open System Interconnect Reference Model)(开放系统互联参考模型) 从下低到高 :物理层.数据链路层.网络层.传输层.会话 ...

  3. socket网络通信

    1.socket通常也称作"套接字",用于描述IP地址和端口.在internet上的主机一般运行了多个服务软件,同时提供几种服务,每种服务都打开一个socket,并绑定到一个端口上 ...

  4. java实现最基础的socket网络通信

    一.网络通信基础 网络中存在很多的通信实体,每一个通信实体都有一个标识符就是IP地址. 而现实中每一个网络实体可以和多个通信程序同时进行网络通信,这就需要使用端口号进行区分. 二.java中的基本网络 ...

  5. 从Socket入门到BIO,NIO,multiplexing,AIO

    Socket入门 最简单的Server端读取Client端内容的demo public class Server { public static void main(String [] args) t ...

  6. 从Socket入门到BIO,PIO,NIO,multiplexing,AIO(未完待续)

    Socket入门 最简单的Server端读取Client端内容的demo public class Server { public static void main(String [] args) t ...

  7. 随笔 -- IO -- Socket/ServerSocket -- Echo(BIO)实例

    随笔 -- IO -- Socket/ServerSocket -- 系统概述 Java中提供的专门的网络开发程序包------java.net Java的网络编程提供的两种通信协议:TCP和UDP ...

  8. Socket网络通信编程(二)

    1.Netty初步 2.HelloWorld 3.Netty核心技术之(TCP拆包和粘包问题) 4.Netty核心技术之(编解码技术) 5.Netty的UDP实现 6.Netty的WebSocket实 ...

  9. Socket网络通信编程(一)

    1.学习基本概念.传统的同步阻塞式I/O编程.伪异步IO实现 2.学习基于NIO的同步非阻塞式编程 3.了解基于NIO2.0的异步非阻塞(AIO)编程 1.1 基本概念 Socket又称“套接字”,应 ...

随机推荐

  1. CSS3 -- FlexBox(弹性盒子)

    盒子模型 CSS中有一种基础设计模式叫盒模型,盒模型定义了Web页面中的元素如何来解析. 在盒模型中主要包括width.height.border.background.padding和margin这 ...

  2. 安卓--ListView

    实验目的: 学习使用ListView 实验要求: 实现一个列表,其中显示班级学号姓名,提供添加功能,如需要删去某一项,长按该项,通过弹出菜单显示删除功能. package com.flyuz.app3 ...

  3. Django 自定义模板标签 报错django.template.exceptions.TemplateSyntaxError: '####' is not a registered tag library. Must be one of:

    我写代码遇到这个错误,但是发现程序没有写错,好像是程序有缓存,重新运行几次就好了. 自定义模板标签,可以不用写views,url直接通过自定义函数把变量传给模板. 具体实现: 1.在app下新建Pyt ...

  4. FMDB----SQL----数据库

    #pragma mark -- 数库 - (void)createDatabase{ //路径 NSString *path = [NSString stringWithFormat:@"% ...

  5. Ubuntu 16.04设置root用户登录图形界面

    ubuntu桌面版默认不开启root登录,所以需要进行设置, 可以参考博客 https://www.linuxidc.com/Linux/2017-01/139094.htm

  6. MySQL安全优化

    一.数据库相关 1. MySQL版本的选择 在正式生产环境中,建议使用5.6或以上系列的版本(5.7不建议,曾经用过这个版本,问题有点多). 2. 运行用户与端口的配置 2.1.确保MySQL运行用户 ...

  7. tfs强行签入和删除工作区

    作者:为爱痴狂 原文:http://www.cnblogs.com/splyn/archive/2011/10/31/2230213.html 域用户被网络管理员重建,或者其他用户牵出文档,导致的TF ...

  8. Codeforces-C-Nice Garland(枚举+暴力)

    You have a garland consisting of nn lamps. Each lamp is colored red, green or blue. The color of the ...

  9. UVA12558 Egyptian Fractions (HARD version)(埃及分数)

    传送门 题目大意 给出一个真分数 a/b,要求出几个互不相同的埃及分数(从大到小),使得它们之和为 a/b (埃及分数意思是分子为1的分数,详见百度百科) 如果有多组解,则分数数量少的优先 如果分数数 ...

  10. Hash Join是Oracle CBO时代经常出现的一种连接方式

    Hash Join是Oracle CBO时代经常出现的一种连接方式,对海量数据处理时经常出现在执行计划里.本篇的上篇(http://space.itpub.net/17203031/viewspace ...