【网络编程(一)】Socket入门实操与BIO详讲

news2024/11/20 15:35:08

Socket

两台计算机使用Socket套接字进行 TCP 连接数据传输时过程如下:

  • 服务器实例化一个 ServerSocket 对象,表示通过服务器上的端口通信。
  • 服务器调用 ServerSocket 类的 accept() 方法,该方法一直会等待,直到客户端连接到服务器上给定的端口。
  • 服务器正在等待时,一个客户端实例化一个 Socket 对象,指定服务器名称和端口号来请求连接。
  • Socket 类的构造函数试图将客户端连接到指定的服务器和端口号。如果通信被建立,则在客户端创建一个 Socket 对象能够与服务器进行通信。
  • 在服务器端,accept() 方法返回服务器上一个新的 Socket 引用,该 Socket 连接到客户端的 Socket。

image-20210914114356892

以上是使用 Socket 套接字实现TCP连接数据传输过程,当然使用 Socket 套接字也可以实现 UDP 数据传输,使用 UDP 就比较简单了,客户端和服务器端不需要建立连接,直接通过数据报进行数据交互即可,缺点就是无状态

使用 Socket 套接字编程需要用到的工具类。

1. InteAddress

InteAddress 全称 Internet Protocol(IP)Address

InetAddress的使用

序号方法描述
1static InetAddress getByAddress(byte[] addr)在给定原始 IP 地址的情况下,返回 InetAddress 对象。
2static InetAddress getByAddress(String host, byte[] addr)根据提供的主机名和 IP 地址创建 InetAddress。
3static InetAddress getByName(String host)在给定主机名的情况下确定主机的 IP 地址。
4String getHostAddress()返回 IP 地址字符串(以文本表现形式)。
5String getHostName()获取此 IP 地址的主机名。
6static InetAddress getLocalHost()返回本地主机。
7String toString()将此 IP 地址转换为 String。

2. URL

URL 中所指明的协议可以为:http、https、file等等。例如:file:///D:/test.txt,file:// -》协议;/D:/test.txt 资源路径。根据协议的不同都会有默认端口,例如http默认端口是80,https默认端口是443.

URL 构造方法。

序号方法描述
1public URL(String protocol, String host, int port, String file) throws MalformedURLException通过给定的参数(协议、主机名、端口号、文件名)创建URL。
2public URL(String protocol, String host, String file) throws MalformedURLException使用指定的协议、主机名、文件名创建URL,端口使用协议的默认端口。
3public URL(String url) throws MalformedURLException通过给定的URL字符串创建URL
4public URL(URL context, String url) throws MalformedURLException使用基地址和相对URL创建

URL 对象方法的使用。

序号方法描述
1public String getPath()返回URL路径部分。
4public int getPort()返回URL端口部分
5public int getDefaultPort()返回协议的默认端口号。
6public String getProtocol()返回URL的协议
7public String getHost()返回URL的主机
8public String getFile()返回URL文件名部分
10public URLConnection openConnection() throws IOException打开一个URL连接,并运行客户端访问资源。

案例

public static void main(String[] args) throws IOException {
    URL resource = new URL("file:///D:/a.txt");
    URLConnection urlConnection = resource.openConnection();
    InputStream inputStream = urlConnection.getInputStream();

    byte[] buf = new byte[1024];
    int len;
    while ((len = inputStream.read(buf)) != -1){
        System.out.println(new String(buf,0,len));
    }
}

代码测试

服务端实现

public class SocketServer {

    public static void main(String[] args) throws IOException {
        // 创建 Socket 服务端对象
        ServerSocket serverSocket = new ServerSocket();
        // 绑定 IP+端口号
        serverSocket.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(),8888));
        while(true){
            // 请求客户端的连接,请求成功会返回客户端的 Socket 对象,失败会一直阻塞
        		Socket accept = serverSocket.accept();
        		System.out.println("已和客户端建立连接");
        		// 通过Socket中的inputstream去读取客户端发送来的数据报
        		InputStream inputStream = accept.getInputStream();
		
        		byte[] readBytes = new byte[1024];
        		int read = -1;
            	if (read != -1) {
                	System.out.println(new String(msg, 0, read));
            	}
        		// while ((read = inputStream.read(readBytes))!=-1) {
        		    // System.out.println(new String(readBytes,0,read));
       		 // }
        }
    }
}

客户端实现

public class SocketClient {

    public static void main(String[] args) throws IOException {
        // 创建 Socket 对象 指代客户端
        Socket socket = new Socket();
        // 与服务端建立 TCP 连接
        socket.connect(new InetSocketAddress(InetAddress.getLoopbackAddress(),8888));
        // 通过 socket 中的输出流进行发送数据
        OutputStream outputStream = socket.getOutputStream();
        outputStream.write("I'm OK!".getBytes());

        outputStream.close();
        socket.close();
    }
}

运行结果
在这里插入图片描述

BIO(同步并阻塞)

测试案例的分析

上面的测试代码中是存在阻塞问题的,一处是请求客户端连接的地方,一处是使用 InputStream 去拿到客户端的内容(即 read 的时候)。

上面测试代码会出现以下所述问题:服务端在处理完第一个客户端的所有时间之前,无法为其他客户端提供服务。

上面那个服务,如果我开启两个cmd窗口,然后通过 telnet 127.0.0.1 8888 用来指示两个客户端来测试服务,则会出现同时申请建立连接会出现下面情况:即显示了一次“已和客户端建立连接”。这说明后面开的客户端建立的连接被阻塞了。(如果是想开启 telnet 服务,需在windows下的控制面板-》程序-》启动或关闭Windows功能-》搜telnet 打开telnet 客户端即可。)

在这里插入图片描述

只有当一个客户端发送完数据被接受完后才会和第二个客户端建立连接:
在这里插入图片描述

解决方法:

阻塞的原因很简单就可以看出,就是是主线程去处理的读取客户端数据操作时,被阻塞了,导致主线程无法去处理监听到的其他客户端,那现在将处理读取客户端数据的业务新建一个线程去完成,就不会出现上面的问题了:阻塞客户端的连接,阻塞客户端发送数据。

while (true) {
            Socket accept = serverSocket.accept();
            System.out.println("已和客户端建立连接");
            new Thread(() -> {
                try {
                    byte[] msg = new byte[1024];
                    InputStream inputStream = accept.getInputStream();
                    int read = -1;
                    read = inputStream.read(msg);
                    if (read != -1) {
                        System.out.println(new String(msg, 0, read));
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }).start();
        }

先在开启两个窗口去扮演客户端身份访问服务端,即会出现下面现象:两个都成功建立了连接。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tnVwdg5I-1691516018243)(C:\Users\myz03\AppData\Roaming\Typora\typora-user-images\image-20230809012419620.png)]

发送消息和接受消息也都是🆗的。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lueL79I5-1691516018243)(C:\Users\myz03\AppData\Roaming\Typora\typora-user-images\image-20230809012506236.png)]

但是现在也存在一个问题:就是当我客户端没有向服务端发送数据的时候,那服务端对于处理接受数据的业务操作对于的线程就不会结束,就会一直阻塞且存在于内存中,那当我们有大量这样的连接的时候,就会有好多好多线程,最后会 IMEMORYERROR。

通过案例分析引出BIO概念

Java BIO:同步并阻塞(传统阻塞型),服务器实现模式为一个连接一个线程,即客户端有连接请求时服务器端就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开销。

image-20210916114632687

缺点:

  • IO 代码里 read 操作是阻塞操作,如果连接不做数据读写操作会造成线程阻塞,浪费资源。
  • 如果线程很多,会导致服务器线程太多,压力太大。

总结:如果说客户端只是建立一个连接而已,不进行任何读写,这个线程可以说是没有干任何事情的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/851453.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[编程开发工具-6]:master 分支和 dev 分支区别

目录 Git 中的 master 分支和 dev 分支之间有几个重要的区别: Git分支实践: master: develop: Feature: feature/{故障号_description}。 hotfix: Git 中的 master 分支和 dev 分支之间有几个重要的区别: 功能:master 分支是…

2.5D游戏是如何做出来的呢,2.5D游戏快速制作教程

前言 【Unity实战篇 】 | 如何制作一款2.5D游戏,2.5D游戏制作案例一、2.5D 游戏概念二、绘制地图三、添加玩家动画和移动等操作四、视角配置4.1 调整摄像机与场景对象的角度4.2 增加镜头旋转功能 五、游戏效果展示 总结 前言 玩过游戏的朋友都知道,市面…

sql注入漏洞

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 原因危害如何挖寻找注入点测试是否有绕过实质分类sqli靶场盲注时间盲注别人的总结UA注入referer注入DNSlog外带cookie注入宽字节注入堆叠注入sqlmap工具getshellacc…

网络防御(8)

根据以下问题总结当天内容 1.什么是数据认证,有什么作用,有哪些实现的技术手段? 2.什么是身份认证,有什么作用,有哪些实现的技术手段? 3.什么VPN技术? 4.VPN技术有哪些分类? 5.IPSEC技术能够提供哪些安全服务? 6.IPSEC的技术…

Elastic Stack 8.9:更快的跨集群搜索和指标聚合

作者:Tyler Perkins, Gilad Gal, Teresa Soler, Shani Sagiv, Bernhard Suhm, George Kobar Elastic Stack 8.9 在多个方面实现了显着的性能改进:Kibana 中更快的跨集群搜索、Elasticsearch 更快的聚合,以及更快、更相关的向量搜索&#xff0…

C++ ModBUS TCP客户端工具 qModMaster 介绍及使用

qModMaster工具介绍 QModMaster是一个基于Qt的Modbus主站(Master)模拟器,用于模拟和测试Modbus TCP和RTU通信。它提供了一个直观的图形界面,使用户能够轻松设置和发送Modbus请求,并查看和分析响应数据。 以下是QModM…

互联网时代下如何搞好网络口碑?

移动互联网时代到来,网络口碑对于任何一家企业都不可忽视,没有口碑的企业广告满天飞但是成交的客户寥寥无几,口碑好的企业没有广告但是仍然能保持业绩增长,这是一个不争的事实。 有人会说,业绩好的是人家产品好所以口碑…

选读SQL经典实例笔记20_Oracle语法示例

1. 计算一年有多少天 1.1. sql select Days in 2005: ||to_char(add_months(trunc(sysdate,y),12)-1,DDD)as reportfrom dualunion allselect Days in 2004: ||to_char(add_months(trunc(to_date(01-SEP-2004),y),12)-1,DDD)from dual REPORT ----------------- Days in 200…

Java中的SimpleDateFormat方法分析

Java中的SimpleDateFormat方法分析 先进行专栏介绍SimpleDateFormat方法分析 常用方法构造方法格式化(从Date到String)举例分析 解析(从String到Date)举例分析 设置方法:注意 代码示例代码结果 综合案例效果 先进行专栏介绍 本专栏是自己学J…

服装行业多模态算法个性化产品定制方案 | 京东云技术团队

一、项目背景 AI赋能服装设计师,设计好看、好穿、好卖的服装 传统服装行业痛点 • 设计师无法准确捕捉市场趋势,抓住中国潮流 • 上新周期长,高库存滞销风险大 • 基本款居多,难以满足消费者个性化需求 解决方案 • GPT数据…

封装统一Api接口

第一步 第二步 第三步 因为是新的页面,所以需要在路由上面写 第四步 操作商品的所有接口 第五步 浏览器结果

14.3.6 【Linux】LVM 相关指令汇整与 LVM 的关闭

至于文件系统阶段 (filesystem 的格式化处理) 部分,还需要以 xfsgrowfs 来修订文件系统实际的大小才行。至于虽然 LVM 可以弹性的管理你的磁盘容量,但是要注意,如果你想要使用 LVM 管理您的硬盘时,那么在安…

性能分析5部曲:瓶颈分析与问题定位,如何快速解决瓶颈?

一、引言 很多做性能测试的同学都问过我这样一个问题:鱼哥(Carl_奕然),你说性能测试的重点是什么? 我的回答很简单:瓶颈分析与问题定位。 在性能项目的整个周期,不管是脚本设计,脚本编写还是脚本执行,都…

深入探索 Spring MVC:构建优雅的Web应用

文章目录 前言一、什么是 Spring MVC1.1 什么是 MVC1.2 什么是 Spring MVC 二、Spring MVC 项目的创建2.1 项目的创建2.2 第一个 Spring MVC 程序 —— Hello World 三、RequestMapping 注解3.1 常用属性3.2 方法级别和类级别注解3.3 GetMapping、PostMapping、PutMapping、Del…

贝叶斯深度学习的温和介绍

一、说明 欢迎来到令人兴奋的概率编程世界!本文是对这个领域的温和介绍,你只需要对深度学习和贝叶斯统计有一个基本的了解。如果像我一样,你听说过贝叶斯深度学习,并且你猜它涉及贝叶斯统计,但你不知道它是如何使用的&…

SaaS化大型微服务架构智慧工地云平台源码

智慧工地云平台建设是采用先进的移动互联、物联网、云计算、大数据等新一代信息技术,主要由信息采集层、网络接入层、网络传输层、信息储存与处理层组成,主要包括云管理平台、综合管理系统、质量管理系统、安全管理系统等模块。施工管理人员可通过PC端&a…

【2.1】Java微服务: Nacos的使用

目录 Nacos介绍 Nacos安装 下载和安装 修改端口 启动 服务注册与发现 导入Nacos管理依赖 导入服务依赖 配置Nacos的服务地址 启动服务,查看已注册的服务 服务分级存储模型 分级存储模型介绍 具体结构 配置实例集群 同集群优先的负载均衡策略 服务权重配置…

spring-boot webservice的例子

webservice发布服务 源码下载地址 spring-boot-webservice例子资源-CSDN文库 webservice cilent调用 源码下载地址 spring-boot-clintwebservice调用服务的例子资源-CSDN文库

CSS的引入方式有哪些?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 内联样式(Inline Styles)⭐ 内部样式表(Internal Stylesheet)⭐ 外部样式表(External Stylesheet)⭐ 导入样式表(Import Stylesheet)⭐ 写在最…

Netty:ChannelHandler的两个生命周期监听事件方法:handlerAdded 和 handlerRemoved

说明 io.netty.channel.ChannelHandler有两个生命周期监听事件方法: handlerAdded(ChannelHandlerContext ctx):当ChannelHandler被添加到实际的上下文、并且已经准备就绪等待处理事件的时候被调用。 handlerRemoved(ChannelHandlerContext ctx)&#…