网络编程之BIO(同步阻塞)

介绍

  • 介绍: BIO是同步阻塞型(传统阻塞型),客户端有一个连接请求时,服务端就会开启一个线程去处理请求(对客户端进行读写),如果该连接什么都不做,会造成不必要的线程开销(可以通过线程池进行优化,)
  • 适用场景: 连接数少且固定的架构, jdk1.4之前,只有这种IO模型
  • 模型过程: 1.服务端通过ServerSocket绑定端口,并启动服务端,等待客户端连接(通过死循环一直在监听看是否有客户端连接上来)
  • 2.客户端通过Socket与服务端进行通信,默认请情况下服务端需要对每一个客户端建立一个线程与之通信
  • 3.服务端监听到连接请求,接受请求(severSocket.accept())
  • 4.客户端发送信息
  • 5.服务端读取信息并写回响应,释放资源(socket, 输出流, 输入流)
  • 6.客户端接收到响应,释放资源(释放资源(socket, 输入流,输出流))

1.服务端

package com.io.bio2;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;

import static java.util.concurrent.Executors.newCachedThreadPool;
/**
 * @author yangmin
 * @version 1.0
 * @description: bio的服务端
 * 介绍: BIO是同步阻塞型(传统阻塞型),客户端有一个连接请求时,服务端就会开启一个线程去处理请求(对客户端进行读写),如果该连接什么都不做,会造成不必要的线程开销(可以通过线程池进行优化,)
 * 适用场景: 连接数少且固定的架构, jdk1.4之前,只有这种IO模型
 * 模型过程: 1.服务端通过ServerSocket绑定端口,并启动服务端,等待客户端连接(通过死循环一直在监听看是否有客户端连接上来)
 * 2.客户端通过Socket与服务端进行通信,默认请情况下服务端需要对每一个客户端建立一个线程与之通信
 * 3.服务端监听到连接请求,接受请求(severSocket.accept())
 * 4.客户端发送信息
 * 5.服务端读取信息并写回响应,释放资源(socket, 输出流, 输入流)
 * 6.客户端接收到响应,释放资源(释放资源(socket, 输入流,输出流))
 * @date 2022/4/20 11:50
 */
public class TimeServer {

    public static final ExecutorService executorService;

    static {
        executorService = newCachedThreadPool();
    }
    public static void main(String[] args) {
        tcpAccept();
    }

    public static void tcpAccept() {
        ServerSocket serverSocket = null;
        try {
            /**Tcp 服务器监听端口,ip 默认为本机地址*/
            serverSocket = new ServerSocket(8080);
            /**循环监听客户端的连接请求
             * accept 方法会一直阻塞,直到 客户端连接成功,主线程才继续往后执行*/
            Socket socket = null;
            while (true) {
                System.out.println("等待客户端连接..........");
                socket = serverSocket.accept();
                System.out.println("客户端连接成功..........");
                /**
                 * 为每一个客户端连接都新开线程进行处理
                 */
                //new Thread(new TimeServerHandler(socket)).start();
                //采用线程池
                executorService.execute(new TimeServerHandler(socket));
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            /**发生意外时,关闭服务端*/
            if (serverSocket != null && !serverSocket.isClosed()) {
                try {
                    serverSocket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

处理器(为每一个客户端新开一个线程去处理)

package com.io.bio2;

import java.io.*;
import java.net.Socket;
import java.util.Date;

/**
 * Created by Administrator on 2018/10/14 0014.
 * 为每个 TCP 客户端新开线程进行处理
 */
public class TimeServerHandler implements Runnable {
    private Socket socket = null;

    /**
     * 将每个 TCP 连接的 Socket 通过构造器传入
     *
     * @param socket
     */
    public TimeServerHandler(Socket socket) {
        this.socket = socket;
    }

    @Override
    public void run() {
        DataInputStream dataInputStream = null;
        DataOutputStream dataOutputStream = null;
        try {
            /**读客户端数据*/
            InputStream inputStream = socket.getInputStream();
            dataInputStream = new DataInputStream(inputStream);
            String message = dataInputStream.readUTF();
            System.out.println(Thread.currentThread().getName() + " 收到客户端消息:" + message);
            /**往客户端写数据*/
            OutputStream outputStream = socket.getOutputStream();
            dataOutputStream = new DataOutputStream(outputStream);
            dataOutputStream.writeUTF(new Date().toString());
            dataOutputStream.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            /**操作完成,关闭流*/
            if (dataOutputStream != null) {
                try {
                    dataOutputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (dataInputStream != null) {
                try {
                    dataInputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            /**操作完成,关闭连接,线程自动销毁*/
            if (socket != null && !socket.isClosed()) {
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

客户端

package com.io.bio2;

import java.io.*;
import java.net.Socket;

/**
 * Created by Administrator on 2018/10/14 0014.
 * 时间 客户端
 */
public class TtimeClient {
    public static void main(String[] args) {
        /**
         * 3个线程模拟3个客户端
         */
        for (int i = 0; i < 3; i++) {
            new Thread(() -> tcpSendMessage()).start();
        }
    }

    /**
     * Tcp 客户端连接服务器并发送消息
     */
    public static void tcpSendMessage() {
        Socket socket = null;
        DataOutputStream dataOutputStream = null;
        DataInputStream dataInputStream = null;
        try {
            /**
             * Socket(String host, int port):
             *      host)被连接的服务器 IP 地址
             *      port)被连接的服务器监听的端口
             * Socket(InetAddress address, int port)
             *      address)用于设置 ip 地址的对象
             * 此时如果 TCP 服务器未开放,或者其它原因导致连接失败,则抛出异常:
             * java.net.ConnectException: Connection refused: connect
             */
            socket = new Socket("127.0.0.1", 8080);
            System.out.println("连接成功.........." + Thread.currentThread().getName());

             /**往服务端写数据*/
            OutputStream outputStream = socket.getOutputStream();
            dataOutputStream = new DataOutputStream(outputStream);
            dataOutputStream.writeUTF("我是长城" + Thread.currentThread().getName());
            dataOutputStream.flush();

            /**读服务端数据*/
            InputStream inputStream = socket.getInputStream();
            dataInputStream = new DataInputStream(inputStream);
            String message = dataInputStream.readUTF();
            System.out.println("收到服务器消息:" + message);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            /**关闭流,释放资源*/
            if (dataOutputStream != null) {
                try {
                    dataOutputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (dataInputStream != null) {
                try {
                    dataInputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            /** 操作完毕关闭 socket*/
            if (socket != null && !socket.isClosed()) {
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值