Java Socket 编程那些事(1)

2023-05-16

前言

最近在准备面试和笔试的一些东西,回去翻看了Java关于IO的基础,发现很多基础还是没有记牢固,现在回头重新学习,就从socket通讯开始吧,虽然说现在企业很少直接编写socket,都是使用一些封装好的框架,netty,mina等。不过对于这些基础的知识,还是需要掌握牢固的,对于以后学习更深的框架和笔试面试都很有裨益。

BIO、NIO、AIO的区别

Java中的IO的方式有三种
Java BIO : 同步并阻塞,服务器实现模式为一个连接一个线程,即客户端有连接请求时服务器端就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开销,当然可以通过线程池机制改善。在JDK1.4以前采用这种方式
Java NIO : 同步非阻塞,服务器实现模式为一个请求一个线程,即客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询到连接有I/O请求时才启动一个线程进行处理。
Java AIO(NIO.2) : 异步非阻塞,服务器实现模式为一个有效请求一个线程,客户端的I/O请求都是由OS先完成了再通知服务器应用去启动线程进行处理,

曾经在一篇文章中看到这么很好的比喻

如果你想吃一份宫保鸡丁盖饭:

同步阻塞:你到饭馆点餐,然后在那等着,还要一边喊:好了没啊!

同步非阻塞:在饭馆点完餐,就去遛狗了。不过溜一会儿,就回饭馆喊一声:好了没啊!

异步阻塞:遛狗的时候,接到饭馆电话,说饭做好了,让您亲自去拿。

异步非阻塞:饭馆打电话说,我们知道您的位置,一会给你送过来,安心遛狗就可以了。

这里我们从最简单的BIO开始学习吧

单线程通讯

首先我们先新建一个Server类,这个类将监听12345这个端口,等待客户端的连接,客户端与服务器连接后,客户端可以像服务器发送信息,如果发送bye,则结束通讯

package edu.gduf.bio.socket.demo1;

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

/**
 * 基于bio的socket服务器端
 * 
 * @author ZGJ
 * @date 2017年5月4日
 */
public class Server {
    public static void main(String[] args) {
        //创建一个serversocket在10000号端口监听
        try (ServerSocket server = new ServerSocket(12345)) {
            //等待客户端连接,将一直阻塞直到有客户端连接
            Socket socket = server.accept();
            BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            PrintWriter out = new PrintWriter(socket.getOutputStream());

            while (true) {
                String msg = in.readLine();
                System.out.println(msg);
                out.println("Server received " + msg);
                out.flush();
                if (msg.equals("bye")) {
                    break;
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

这里try (ServerSocket server = new ServerSocket(12345))采用了java7的try-with-resources语法,这样写的好处是try里面声明的资源在最后都会自动关闭,而不需要我们手动关闭,简化了语法

Client类

package edu.gduf.bio.socket.demo1;

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

/**
 * 基于bio的socket客户端
 * 
 * @author ZGJ
 * @date 2017年5月4日
 */
public class Client {
    public static void main(String[] args) {
        try (Socket socket = new Socket("127.0.0.1", 12345)) {
            //获取socket输入流
            BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            //socket输出流
            PrintWriter out = new PrintWriter(socket.getOutputStream());
            //标准输入流
            BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
            while (true) {
                String msg = reader.readLine();
                out.println(msg);
                out.flush();
                if (msg.equals("bye")) {
                    break;
                }
                System.out.println(in.readLine());
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}

运行结果:
Client:

hello
Server received hello
haha
Server received haha
bye

Server:
hello
haha
bye

多线程通讯

我们发现,服务器只能处理一个客户端的请求,服务器处理了第一个客户端的请求之后,后续的Client就不能再连接,这个时候我们需要做一些改动,当服务器收到客户端的连接请求后,客户端的请求放在一个新的线程中去处理,而主线程仍然继续等待其他客户端的连接,这样就不会阻塞服务器处理其他客户端的请求了,只需要修改服务器的代码,客户端代码和原来的一样

package edu.gduf.bio.socket.demo2;

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

/**
 * 处理多个client的server
 * @author ZGJ
 * @date 2017年5月4日
 */
public class MulitClientServer {
    public static void main(String[] args) {
        try(ServerSocket server = new ServerSocket(12345)) {
            //循环接受客户端请求
            while(true) {
                Socket socket = server.accept();
                handle(socket);
            }
        } catch(IOException e) {
            e.printStackTrace();
        }
    }
    /**
     * 处理客户请求
     * @param socket
     */
    private static void handle(Socket socket) {
        //开启一个线程,lambda表达式
        new Thread(() -> {
            try(BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                    PrintWriter writer = new PrintWriter(socket.getOutputStream(), true)) {
                while(true) {
                    String message =  in.readLine();
                    System.out.println(message);
                    writer.println("Server received: " + message);
                    if("bye".equals(message)) {
                        break;
                    }
                }
            } catch(IOException e) {
                e.printStackTrace();
            }
        }).start();
    }
}

我们可以看到,当服务器接受到一个客户单的请求之后,采用handle()方法去处理客户端的请求,这里使用了Java8中lambda表达式来替代匿名内部类的语法,来简化我们的编程,使我们的语法更加简洁。对于每一个客户端的请求都开启一个新的线程去处理,当然,如果还想做到更加优化,可以采用Executor线程池去处理,节省创建和关闭线程的开销。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java Socket 编程那些事(1) 的相关文章

  • 让Everything搜索结果更清爽

    Everything的文件搜索功能很强大 xff0c 但是默认设置下搜索出的结果过于丰富 xff0c 总是会有一些乱七八糟的后缀名文件 xff08 如下图 xff09 xff0c 或许我们并不想搜索出那些文件 这时我们需要对它设置里的排除列
  • 上机 Qt5.14.2 编程应用

    上机 Qt5 14 2 编程应用 关于QT Qt是一个1991年由Qt Company开发的跨平台C 43 43 图形用户界面应用程序开发框架 它既可以开发GUI程序 xff0c 也可用于开发非GUI程序 xff0c 比如控制台工具和服务器
  • Android Studio报错:Error:Could not find com.android.tools.build:gradle:4.1 记一次不长记性的坑

    本文地址 xff1a https blog csdn net zengsidou article details 79797417 看字面意思 xff0c 这个问题是Gradle没有对应版本 在搜索引擎没有找到方法之后 xff0c 尝试自己
  • VBox关闭dhcp

    VBox关闭dhcp C Program Files Oracle VirtualBox gt VBoxManage exe list dhcpservers NetworkName HostInterfaceNetworking Virt
  • Android 使用LottieAnimationView 做启动动画

    lt xml version 61 34 1 0 34 encoding 61 34 utf 8 34 gt lt RelativeLayout xmlns android 61 34 http schemas android com ap
  • Android OkHttp★

    1 OkHttp OkHttp是Square公司开发的一个处理网络请求的开源项目 是目前Android使用最广泛的网络框架 OkHttp的特点 支持HTTP 2并允许对同一主机的所有请求共享一个socket连接 如果非HTTP 2 则通过连
  • Android GestureDetector★★★

    1 GestureDetecor 用户触摸屏幕时会产生许多手势 xff0c 一般通过重写View类的onTouch 方法可以处理一些触摸事件 xff0c 但是这个方法太过简单 xff0c 如果需要处理一些复杂的手势 xff0c 用这个接口就
  • Android canvas

    1 Canvas Canvas指画布 xff0c 表现在屏幕上就是一块区域 xff0c 可以在上面使用各种API绘制想要的东西 canvas内部维持了一个mutable Bitmap xff0c 所以它可以使用颜色值去填充整个Bitmap
  • Android apk打包流程★

    1 apk打包 Android开发中打包apk主要有两种方式 使用Android Studio集成直接生成apk 使用ant工具在命令行方式下打包apk 不管哪种方式 打包apk的本质过程都是一样的 Android的apk包文件包括两部分
  • Android ViewPager用法

    1 适配器PagerAdapter ViewPager使用适配器类将数据和view的处理分离 xff0c ViewPager的适配器叫PagerAdapter xff0c 这是一个抽象类 xff0c 不能实例化 xff0c 所以它有两个子类
  • Android Fragment★★

    1 Fragment fragment译为 碎片 xff0c 是Android 3 0 xff08 API 11 xff09 提出的 xff0c 最开始是为了适配大屏的平板 Fragment看起来和Activity一样 xff0c 是一个用
  • Android设计模式—适配器模式★★★

    1 适配器模式 适配器模式是指把一个类的接口变换成客户端所期待的另一种接口 xff0c 从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作 适配器模式是为了解决接口不兼容问题的 比如厂商给你的接口和你现有的接口对接不起来 旧的数据
  • Android 类加载机制

    nbsp 1 类加载机制 java文件不是可执行的文件 需要先编译成 class文件才可以被虚拟机执行 而类加载就是指通过类加载器把 class文件加载到虚拟机的内存空间 具体来说是方法区 类通常是按需加载 即第一次使用该类时才加载 Jav
  • Android Bitmap防止内存溢出

    1 Bitmap 在Android开发中经常会使用到Bitmap xff0c 而Bitmap使用不当很容易引发OOM Bitmap占用内存大小的计算公式为 xff1a 图片宽度 图片高度 一个像素点所占字节数 xff0c 因此减小这三个参数
  • Swift NSAttributedString的使用

    NSMutableAttributedString let testAttributes 61 NSAttributedStringKey foregroundColor UIColor blue NSAttributedStringKey
  • Android ViewStub

    1 ViewStub ViewStub是一个可用于性能优化的控件 xff0c 它是一个不可见的 零尺寸的View xff0c 可以在运行时进行延迟加载一个布局文件 xff0c 从而提高显示速率 viewstub和include比较像 xff
  • Android Jetpack—LiveData和数据倒灌

    1 LiveData LiveData是Android Jetpack包提供的一种可观察的数据存储器类 xff0c 它可以通过添加观察者被其他组件观察其变更 不同于普通的观察者 xff0c LiveData最重要的特征是它具有生命周期感知能
  • Gradle build 报错:Received status code 400 from server: Bad Request

    全部错误是这样的 xff1a Could not GET 39 https dl google com dl android maven2 com android tools build gradle 3 1 2 gradle 3 1 2
  • 排列组合详解

    在笔试题中看到的一个选择题 用1 3的瓷砖密铺3 20的地板有几种方式 xff1f 排列组合问题 排列和组合问题 xff0c 其实是两种问题 xff0c 区分它们的原则是是否需要考虑顺序的不同 排列问题 xff0c 考虑顺序 xff1b 组
  • SCKKRS-关键词、关键短语提取

    1 简介 SCKKRS Self supervised Contextual Keyword and Keyphrase Retrieval with Self Labelling 本文根据2019年 Self supervised Con

随机推荐

  • kali安装vnc

    一 安装x11vnc 1 经过N多次的实验 xff0c kali一直报错 xff0c tightvncserver一直报错 怎么配置都是黑屏 xff0c 奔溃 最后退而求其次 xff0c 安装x11vnc 2 很简单的命令 sudo apt
  • 计算机硬件技术基础第一章总结

    1 1 计算机发展概述 1 1 1 计算机的发展简史 第一台计算机 xff1a ENIAC 第一代 xff1a 电子管数字计算机 xff08 1946 1958 xff09 逻辑元件 xff1a 真空电子管体积大 xff0c 功耗高 xff
  • CentOS7安装Oracle JDK1.8

    JDK1 8下载地址 https www oracle com java technologies javase javase8 archive downloads html 需要登录之后才能下载文件 xff0c 下载jdk 8u202 l
  • Ubuntu 16.04 安装 rtl8812au系列 (DWA-182) wireless adapter driver

    Ubuntu 16 04 安装 rtl8812au系列 DWA 182 wireless adapter driver 刚刚开始使用Linux xff0c 一脸懵逼 xff0c 命令行搞得一愣一愣的 xff0c 不过熟悉了之后就好很多了 一
  • SpringBoot项目启动失败报错Annotation-specified bean name ‘xx‘ for bean class [xxx] conflicts with existing

    问题描述 xff1a 项目启动就会报 xff1a Annotation specified bean name xx for bean class xxx conflicts with existing non compatible bea
  • Visual Studio高效实用的扩展工具、插件

    说明 xff1a 对一个有想法的程序员来说 xff0c 善于使用一款高效的开发工具是很重要的 xff0c 今天给大家介绍的是宇宙第一IDE vs用起来很不错的开发工具 xff0c 假如大家觉得不错也可以尝试的用用 xff0c 毕竟对于我们这
  • java琐事

    并发编程 并发的意义 并发通常是提高运行在单处理器上的程序的性能 如果程序中的某个任务因为该程序控制范围之外的某些条件 I O 而导致不能继续执行 xff0c 那么这个任务或线程就阻塞了 如果没有并发 xff0c 整个程序都讲停下来 从性能
  • java类的初始化和实例化的初始化(类的初始化过程)

    Java类的加载顺序 父类静态代变量 父类静态代码块 子类静态变量 子类静态代码块 父类非静态变量 xff08 父类实例成员变量 xff09 父类构造函数 子类非静态变量 xff08 子类实例成员变量 xff09 子类构造函数 上面的说法也
  • 最优吞吐量和最短停顿时间

    在实践活动中 xff0c 我们通过最优吞吐量和最短停顿时间来评价jvm系统的性能 吞吐量越高算法越好 暂停时间越短算法越好 首先让我们来明确垃圾收集 GC 中的两个术语 吞吐量 throughput 和暂停时间 pause times JV
  • sql执行慢的原因有哪些,如何进行sql优化?

    一 导致SQL执行慢的原因 1 硬件问题 如网络速度慢 xff0c 内存不足 xff0c I O吞吐量小 xff0c 磁盘空间满了等 2 没有索引或者索引失效 xff08 一般在互联网公司 xff0c DBA会在半夜把表锁了 xff0c 重
  • 阿里java开发手册2019年最新版619(华山版)PDF下载

    链接 https pan baidu com s 1ANvBu1hidnvRCZILDGXuQA 密码 ugq8
  • Mockito:org.mockito.exceptions.misusing.InvalidUseOfMatchersException

    org span class token punctuation span mockito span class token punctuation span exceptions span class token punctuation
  • 一个简单通用的基于java反射实现pojo转为fastjson对象的方法

    最近在公司工作需要实现一个工具实现一个pojo转为fastjson对象的通用工具 xff0c 直接上源码 span class token comment 通用的pojo转为Json对象的方法 64 author ZFX 64 date20
  • Java魔法类:Unsafe应用解析

    这个美团大神对于Unsafe的分析很全面 https tech meituan com 2019 02 14 talk about java magic class unsafe html
  • Linux X-Window Error: Can‘t open display: :0

    问题过程描述 许多经常部署Oracle数据的管理员经常需要对数据库软件进行部署 xff0c 但大多数都是通过远程部署的方式进行部署 xff0c 使用远程部署有两种方式 xff0c 一种是通过脚本部署 xff0c 另一种就是通过图形化进行部署
  • maven打包生成war跳过单元测试

    maven将项目打包成war包的命令是 mvn install 或mvn package 每次生成war包时会进行所以的单元测试 xff0c 如果想跳过单元测试直接生成war包有以下3种方式 方法1 xff1a 在pom xml中加入如下代
  • 程序员每天工作多少个小时_程序员每天实际工作几个小时?

    程序员每天工作多少个小时 您如何看待 xff0c 程序员每天实际工作多长时间 xff1f 大多数人会说答案是8到9个小时 有人说他们每天工作12个小时或更长时间 尽管这是正确的 xff0c 但它并不是大多数程序员实际工作的数量 xff0c
  • ubuntu 显示缺少库文件 libcom_err.so.2 解决办法

    运行任何代码都显示 xff1a error while loading shared libraries libcom err so 2 cannot open shared object file No such file or dire
  • 记CVTE第一次面试

    首先说明一下博主是一个大三的学生 xff0c 专业计算机科学与技术 xff0c 主学的方向是Web后台开发 xff0c 主语言是Java 前几天看到CVTE有校园招聘实习生 xff0c 就报名参加了 xff0c 做了CVTE的笔试题 xff
  • Java Socket 编程那些事(1)

    前言 最近在准备面试和笔试的一些东西 xff0c 回去翻看了Java关于IO的基础 xff0c 发现很多基础还是没有记牢固 xff0c 现在回头重新学习 xff0c 就从socket通讯开始吧 xff0c 虽然说现在企业很少直接编写sock