记录《疯狂Java讲义精粹》划线内容及理解(第十二章 网络编程)

12.1.1 网络基础知识

通信协议:计算机网络中实现通信的一些约定🌂

通信协议的组成:语义,语法,变换规则(时序)

国际标准化阻止ISO于1978年,提出”开放系统互连参考模型“,既OSI七层协议(物理层,数据链路层,网络层,传输层,会话层,表示层,应用层)

IP(网际互联协议)/TCP(传输控制协议),最早出现在UNIX操作系统中,该协议将网络分为四层(应用层,传输层,网络层,物理层+数据链路层)

<br>

12.1.2 IP地址和端口号

端口:一个16位整数,用于表述数据交给那个程序处理

同一台机器上,同一端口不能被两个程序使用

端口号范围0 --65535

  • 0 到1023 —— 公认端口,他们紧密绑定一些特定的服务

  • 1024 到 49151 —— 注册端口,松散绑定一些服务

  • 49152 到 65535 —— 动态和私有端口

<br>

12.2 Java的基本网络支持

12.2.1 使用InetAddress

该类代表Ip地址,它的两个子类Inet4Address,InetAddress分别代表IPv4和IPv6

获取InetAddress实例

  • getByName(String):根据主机名获取对应的InetAdderss对象

  • getByAddress(byte【】):根据IP地址来获取对应的InetAddress对象

  • getLocalHost():获取本机IP地址对应的InetAddress实例

获取实例中的IP地址和主机名

  • String getCanonicalHostName():获取此IP地址的全限定域名

  • String getHostAddress():返回该InetAddress实例对应的饿IP地址,的字符串形式

  • String getHostName():获取此实例代表的主机名

测试通信方法

  • isReachable():用于测试是否可以到达该地址

    • 该方法将尽最大努力试图到达主机,如果可以访问到,将发送类似ping命令的报文,如没有获取权限,它将试图在目标主机的端口7(Echo)上,建立TCP连接

<br>

12.2.2 使用URLDecoder和URLEncoder

这里讨论一个有趣的现象,打开浏览器,随便输入中文字符串来进行搜索,回车之后,中文字符将以get方式传输到搜索引擎的服务器,并且链接中的中文字符好像变成了一堆乱码的样子,并不是的,这一堆像乱码的东西,叫application/x-www-form-urlencoded MIME 字符串

当URL中包含非西欧字符的字符串时,系统会将这些,非西欧字符转换为application/x-www-form-urlencoded MIME字符串。下面称为特殊字符串


URLDecoder

  • decode(String,String):将特殊字符转换位普通字符串

URLEncoder

  • encode(String,String):将普通字符串转换位特殊字符串

这里的转换方式为,西欧字符串无需转换,中文字符每个占两字节,每个字节转换为2个十六进制的数字,所以每个中文字符转换为”%XX%XX“的形式,需要注意这里的转换字节数还和使用字符集有关

<br>

12.2.3 使用URL和URLConnection

URL(统一资源定位符),是指向互联网资源的指针

URL的组成 —— 协议名://主机:端口/资源

java中也提供了URL对应的类,就叫URL

获取URL类对象

  • 通过构造方法

URL类的方法

  • String getFile():获取该URL资源名

  • String getHost():获取该URL主机名

  • String getPath():获取该URL的路径部分

  • int getPort():获取该URL的端口号

  • String getProtocol():获取该URL的协议名称

  • String getQuery():获取该URL的查询字符串部分

  • URLConnection openConnection():返回一个URLConnection对象,该对象代表了与URL所引用的远程对象的连接

  • InputStream openStream():打开与此URL的连接,并返回一个用于读取该URL资源的输入流(InputStream)

设置请求头的通用方法

setRequestproperty(String key,String value):设置URLConnection的key请求头字段的值为value

<br>

12.3 基于TCP协议的网络编程

java在网络通信的两端各建立一个Socket对象,通过该对象来生成虚拟链路,来实现TCP的可靠通信,同时使用该对象来产生IO流,来进行网络通信

<br>

12.3.2 使用ServerSocket创建TCP服务器端

服务器端的对象,使用serverSocket来表示,该对象包含一个方法

accept(),该方法如果接收到一个客户端的Socket连接请求,将返回一个与客户端Socket对应的Socket,否则该方法一直处于等待状态,线程也被阻塞

获取serverSocket对象

  • ServerSocket(int):用指定端口来创建一个ServerSocket

  • ServerSocket(int port,int backlog):增加一个用来改变连接队列长度的参数 backlog

  • ServerSocket(int port,int backlog,InetAddress localAddr):在机器存在多个IP地址的情况下,允许通过localAddr参数来指定,将ServerSocket绑定到指定的IP地址

<br>

12.3.3 使用Socket进行通信

获取Socket对象

  • Socket(InetAddress/String remoteAddress,int port):连接到远程主机,指定要连接主机的端口号,本地Socket使用默认IP地址,默认使用系统动态分配的端口

  • Socket(InetAddress/String remoteAddress,int port,InetAddress localAdde,int localPort):创建连接,连接到远程主机,该方法可以指定本地IP和本地端口

获取Socket的输入流和输出流

  • InputStream getInputStream():返回Socket对象对应的输入流

  • OutputStream getOutputStream():返回该Socket对象对应的输出流

指定超时时长

  • setSoTimeout(int):在超过int时间之后,抛出异常(SocketTimeoutException异常)

指定连接超时

  • connect(InetAddress实例,超时时间):连接到指定远程主机,指定超时时间

<br>

12.3.4 加入多线程

该操作,将每个客户端放在一个线程体中,让后让Serversocket的accept方法监听,只要监听到,则创建对应的线程,然后子线程单独处理每个客户端

需要注意的是,书中这里创建了一个ArrayList的集合,来保存创建的socket对象,之后每个线程向服务器发送信息时,服务器会向,连接到该服务器的所有客户端,转发该信息

<br>

12.3.5 记录用户信息

在这里使用了一个Map来记录用户名和对应的输入流,用于来实现私聊功能

之后使用了一个自定义接口,定义了成员变量来定义了一些特殊字符,这些特殊字符用作标识符,来区分不同的功能

<br>

12.3.6 半关闭的Socket

对于文件类的c/s模式,客户端可以在传完文件后直接关闭输入流,但对于网络的聊天类应用不能这样做,于是有了半关闭式Socket

  • shutdownInput():关闭该Socket的输入流,输出流正常

  • shutdownOutput():关闭该Socket的输出流,输入流正常

  • isInputShutdown():判断该Socket是否处于半读状态(read-half)

  • isOutputShutdown():判断该Socket是否处于半写状态(write-half)


注意,如果使用上面方法关闭流,则无法再打开该Socket,已被关闭的流

<br>

12.3.7 使用NIO实现非阻塞Socket通信

java的NIO为非阻塞式Socket通信提供了如下几个类

  • Selector:可调用该类的open()静态方法来创建Selector实例

Selector可同时监控多个SelectableChannel的IO状况,是非阻塞IO的核心,一个Selector实例有三个SelectionKey集合

  1. 所有SelectionKey集合,代表了注册在该Selector上的Channel,可通过keys()方法返回

  2. 被选择的SelectionKey集合,代表了所有可通过select(0方法获取的,需要IO处理的Channel,可通过selectedKeys()返回

  3. 被取消的SelectionKey集合,代表了所有被取消注册的Channel,在下一次执行select()方法是,该集合将会被cedilla删除

Selector方法

  • int select():监控所有这侧的Channel,当他们中间需要IO处理时,还方法返回,并将对应的SelectionKey加入被选择的SelectionKey,该方法返回CHannel的数量

  • int select(long timeout):设置超时时长

  • int selectNow():执行一个立即返回的select()操作,该方法不会阻塞线程

  • Selector wakeup():是一个还未返回的select()方法立刻返回

  • SelectableChannel:他代表可以支持非阻塞IO操作的Channel对象,可被注册到Selector上,这种注册关系由SelectionKey实例表示,Selector对象提供了一个select()方法,该方法允许应用程序用时监控多个IOChannel

  • register():将一个SelectableChannel注册到指定Selector上

  • SelectableChannel configureBlocking(boolean block):设置是否采用阻塞模式

  • boolean isBlocking():该Channel是否是阻塞模式(false为非阻塞)

  • int validOps():返回一个整数,表示这个Channel所支持的IO操作

serverSocketChannel代表一个ServerSocket,它只支持OP_ACCEPT操作

在SelectionKey中,用静态常量定义了4种IO操作

  • OP_READ(1)

  • OP_WRITE(4)

  • OP_CONNECT(8)

  • OP_AACCEPT(16)

这里的值,计算的非常巧妙,这里的值任意2个,3个,4个,进行按位或的结果,和相加的结果相等,同时他们相加的结果总是互不相同

所以系统可以根据validOps()方法的返回值,确定该SelectableChannel支持的操作

获取AelectableChannel的注册状态

  • boolean isRegistered():返回该Channel是否已注册在一个或多个Selector上

  • SelectionKey keyFor(Selector sel):返回该Channel和sel Selector之间的注册关系,如不存在注册关系,则返回null

  • SelectionKey:该对象代表了SelectableCHannel和Selector之间的注册关系

  • ServerSocketChannel:支持非组设操作,对应java.net.serverSocket类只支持OP_ACCEPT操作,

  • SocketChannel:支持非阻塞操作,对应java.netSocket这个类,支持OP_CONNECT、OP_READ 和 OP_WRITE 操作。这个类还实现了 ByteChannel 接口、ScatteringByteChannel 接口和GatheringByteChannel 接口,所以可以直接通过SocketChannel来读写ByteBuffer对象。


那么整理一下上面的工作流程,

1.服务器上的所有Channel都需要向Selector注册,

2.Selector则负责监视这些Socket的IO状态(通过select()方法)

3.只要当前select()方法返回值大于0,则使用selectedKeys()来获取需要处理的IO集合


书中接下来是使用NIO和AIO来实现聊天程序的具体代码实现和优化,实在繁琐,如有需要再回来看


后言

心野掉了就念不进书,就没心思干活,就只适合日复一日地坐在野地里发呆,在黄昏和夜晚的缝隙中一次又一次地消融。你就很难再回到真实的人世间,捡起上进心,努力去做一个世俗的成功者了。(陈春成 《夜晚的潜水艇》)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值