第10章 - Java 网络IO

10 - Java 网络IO

 

1. Java Socket

    数据从一台主机发送到网络中的另一台主机需要经过如下步骤

       1).建立通讯物理渠道(物理链路)

       2).通信协议,进行数据传输

    TCP/IP协议是网络应用程序的首选

 

1.1 Java Socket的工作机制

    Socket是描述计算机之间完成相互通信的一种抽象功能。

    主机AB应用程序通信,就必须通过Socket建立连接,而Socket就必须使用TCP/IP协议来建立TCP连接、建立TCP连接需要用到IP协议来寻址网络中的主机。

    IP对应一台主机,一台主机上可能运行着多个应用程序,就需要通过TCPUDP的端口号来指定与哪个应用程序通信。这样就可以通过一个Socket实例为宜代表一个主机上的应用程序的通信链路了。

 

1.1.1 建立通信链路

    TCP网络程序设计师指利用Socket类编写通信程序. 利用TCP协议进行通信的两个应用程序室友主次之分的, 一个称为服务器程序, 另一个称为客户机程序. 两者的功能和编写方法大不一样.

    1).服务器程序创建一个ServerSocket(服务器Socket), 调用accept()方法等待客户机来连接

    2).客户端程序创建一个Socket, 请求与服务器建立连接

    3).服务器接收客户机的连接请求, 同时创建一个新的Socket与客户建立连接. 服务器继续等待新的请求

    客户端:当客户端要与服务端通信时,客户端首先要创建一个Socket实例,操作系统会为这个Socket实例分配一个没有被使用的本地端口号,并创建一个包含本地和远程地址和端口号的套接字数据结构,这个数据结构会一致保存在系统中直到这个连接关闭。创建Socket实例的构造函数正确返回之前,将要进行TCP的三次握手协议,完成后,SOcket实例对象才创建完成,否则抛出IOExpection异常

    服务端:创建ServerSocket实例,指定没有被占用的端口号,一般实例都会创建成功。系统同样会创建一个数据结构,这个数据结构会包含舰艇的端口和舰艇地址通配符(通常是"*")。当调用accept()时,进入阻塞状态,等待客户端的请求。当一个新的请求到来时,将为这个连接创建一个新的Socket数据结构来代表来源地址和端口信息。服务端接收的客户端创建的Socket实例,要等到三次握手完成后才返回。并将该Socket实例从未完成列表移到完成列表中。所以ServerSocket所关联的列表中每个数据结构都代表与一个客户端建立的TCP连接

 

1.1.2 数据传输

    当连接创建成功,服务端和客户端都会拥有一个Socket实例,每个Socket实例都有一个InputStreamOutputStream。可以通过这两个对象来交换数据。

    网络IO都是以字节流传输的,当创建Socket对象时,操作系统会为流分配一定大小的缓存区,数据的写入和读取都是通过这个缓存区完成的。

    如:SocketASocketB,写入端SocketA将数据写到OutputStream对应的SendQ队列中,当队列填满时,就会转移到SocketBInputStream中的RecvQ队列中,如果此时RecvQ满了,SocketAOutputStreamwrite方法将会阻塞。直到RecvQ队列有足够的空间容纳SendQ发送数据。

    这个缓存区大小及写入端速度和读取端的速度都会影响这个连接的数据传输效率,由于可能发生阻塞,所有网络IO与磁盘IO不同的是,写入和读取还要有一个协调过程,如果两边同时传送数据可能会产生死锁。

 

1.1.3 TCPUDP协议

TCP/IP协议栈中, 有两个高级协议

    1).传输控制协议(Transmission Control Protocol, TCP)

    2).用户数据报协议(User Datagram Protocol, UDP)

TCPUDP对比

TCP

UDP

  固接连接为基础的协议,提供可靠的数据传送。

  TCP可以保证服务从一端送至连接的另一端时能够确实送达, 而且抵达的数据的排列顺序和送出时的顺序相同, 因此TCP协议适合可靠性要求比较高的场合.

    HTTPFTPTelnet都需要使用可靠的通信频道

  无连接通信协议

  UDP不保证可靠数据的传输, 但能够向若干个目标发送数据, 接收发自若干个源的数据. UDP是以独立发送数据包的方式进行。UDP协议适合于对数据准确性要求不高的场合

  如:网络聊天室, 在线影片等

建立连接, 形成传输数据的通道

将数据及源和目的封装成数据包中, 不需要建立连接

在连接中进行大数据量传输

每个数据报的大小限制在64K

通过三次握手完成连接, 是可靠协议

因无连接, 是不可靠协议

必须建立连接, 效率会稍低

不需要建立连接, 速度快

    由于TCP协议在认证上存在额外耗费, 有可能使传输速度减慢. UDP协议可能会更适合这些对传输速度和时效要求非常高的网站, 即使有一小部分数据包的遗失或传送顺序有所不同, 并不会严重危害这项通信

【注: 一些防火墙和路由器会设置成不允许UDP数据包传输, 若遇到UDP连接方面的问题, 先确定是否允许UDP协议】

 

 

 

2.2 TCP程序设计

2.2.1 InetAddress

(示例: basic.socket.InetAddressDemo)

    java.net包中的InetAddress类是IP地址相关的类, 利用该类可以获取IP地址、主机地址等信息, 子类Inet4Address, Inet6Address

InetAddress类常用的方法

方法

说明

InetAddress  getByName(String host)

获取与host相对应的InetAddress对象

String  getHostAddress()

获取InetAddress对象所含的IP地址

String  getHostName()

获取此IP地址的主机名

InetAddress  getLocalHost()

返回本地户籍的InetAddress对象

    访问网页都是访问IP地址, 但IP地址不利于记忆, 所以有了利于记忆的万维网地址(每个地址与IP地址对应)

访问一个网页流程:

    1).输入http://www.sina.com.cn(域名)

    2).访问DNS服务器(域名解析服务器(本地也有域名服务器的配置, 比如127.0.0.1对应localhost)), 寻找是否有对应IP地址

    3).如果有对应IP地址, 访问该IP地址

关于屏蔽网页原理:

    C:\Windows\System32\drivers\etc\hosts(服务器配置)

    127.0.0.1 activate.adobe.com

    127.0.0.1 practivate.adobe.com

    当访问activate.adobe.com都会跳转到127.0.0.1  即屏蔽原理

 

2.2.2 ServerSocket

    java.net包中的ServerSocket类用于表示服务器Socket, 其主要功能是等待来自网络上的"请求", 它可以通过指定的端口来等待连接的Socket.

    服务器Socket一次可以与一个Socket连接, 如果多态客户机同时提出连接请求, 服务器Socket会将其他链接的客户机存入队列中, 然后从中取出一个Socket, 与服务器新建的Socket连接起来. 若请求连接数大于最大容纳数, 则多出的连接请求被拒绝. 队列的默认大小为50

构造方法:

public ServerSocket() throws IOException

public ServerSocket(int port) throws IOException

public ServerSocket(int port, int backlog) throws IOException

public ServerSocket(int port, int backlog, InetAddress bindAddr) throws IOException

    port:指定段都,默认1080

    backlog:请求传入队列的最大长度连接,默认50

    bindAddress:绑定到的本地IP地址。适用于计算机上有多块网卡和多个IP的情况, 可以明确规定在哪块网卡或IP地址上等待客户的连接请求

常用方法:

public Socket accept() throws IOException // 阻塞,等待客户机的连接, 若连接, 则创建一个Socket

public SocketAddress getLocalSocketAddress()

public int getLocalPort() // 返回服务器Socket等待的端口号

public InetAddress getInetAddress() // 返回此服务器Socket的本地地址

public void bind(SocketAddress endpoint) throws IOException

public void bind(SocketAddress endpoint, int backlog) throws IOException // ServerSocket绑定到特定地址(IP地址和端口号)

public ServerSocketChannel getChannel()

public boolean isBound() // 判断ServerSocket的绑定状态

public void close() throws IOException // 关闭服务器Socket

public boolean isClosed() // 返回服务器Socket的关闭状态

public synchronized void setSoTimeout(int timeout) throws SocketException

public synchronized int getSoTimeout() throws IOException

public void setReuseAddress(boolean on) throws SocketException

public boolean getReuseAddress() throws SocketException

   调用ServerSocket类的accept()方法, 将返回一个与客户端Socket对象相连接的Socket对象, 服务器端的Socket对象使用getOutputStream()方法获取的输出流对象, 将指向客户端Socket对象使用getInputStream()方法获得的输入流对象.

    同样服务器端的Socket对象使用getInputStream ()方法获取的输入流对象, 将指向客户端Socket对象使用getOutputStream ()方法获得的输出流对象.

    也就是说当服务器向输出流写入信息时, 客户端通过相应的输入流就能读取, 反之亦然

【注: accept()方法会阻塞线程的继续执行, 直到接收到客户的呼叫, 如果没有则阻塞, 通常是使用了一个还在被其他程序占用的端口号, ServerSocket绑定没有成功】

 

2.2.3 Socket

    Socket主要代表客户端,通过构造函数与指定服务器Socket进行通讯

构造方法:

public Socket()

public Socket(Proxy proxy)

protected Socket(SocketImpl impl) throws SocketException

public Socket(String host, int port) throws UnknownHostException, IOException

public Socket(InetAddress address, int port) throws IOException

public Socket(String host, int port, InetAddress localAddr, int localPort) throws IOException

public Socket(InetAddress address, int port, InetAddress localAddr, int localPort) throws IOException

    host:指定主机

    port:指定主机端口

常用方法:

public InputStream getInputStream() throws IOException // 获取InputStream进行读取

public OutputStream getOutputStream() throws IOException // 获取OutputSream进行写入

public synchronized void close() throws IOException // 关闭,断开连接

 

 

2.3 UDP程序设计基础

    用户数据协议包协议(UDP)是网络信息传输的另一种形式. 基于UDP的通信和基于TCP的通信不同, UDP的信息传递更快, 但不提供可靠的保证.

    使用UDP传递数据时, 用户无法知道数据能否正确地到达主机, 也不能确定到达目的地的顺序是否和发送的顺序相同, 虽然UDP是一种不可靠的协议, 但有时需要较快地传输信息, 能容忍小的错误, 可以考虑使用UDP

基于UDP通信的基本模块如下

    1).将数据打包(称为数据包), 然后将数据包发往目的地

    2).接收别人发来的数据包, 然后查看数据包

发送数据包:

    1).使用DatagramSocket()方法创建一个数据包Socket

    2).使用DatagramPackage(byte[] buf, int offset, int length, InetAddress, int port)方法创建要发送的数据包

    3).使用DatagramSocket类的send()发送数据包

接收数据包:

    1).使用DatagramSocket(int port)方法创建数据包Socket, 绑定到指定的端口

    2).使用DatagramPackage (byte[] buf, int length)方法创建字节数组来接收数据包

    3).使用DatagramSocket类的receive()方法接收UDP

【注: 使用DatagramSocket类的receive()方法接收数据时, 如果还没有可以接收的数据, 在正常情况下receive()方法将阻塞, 一直等到网络上有数据到来才接收该数据并返回. 如果网络上没有数据发送过来, receive()方法也没有阻塞, 肯定是程序有问题, 大多数是用了一个被其他程序占用的端口号】

 

2.3.1 DatagramPacket

    java.net包的DatagramPacket类用来表示数据包. 构造函数如下:

        1).DatagramPacket(byte[] buf, int length)

        2).DatagramPacket(byte[] buf, int length InetAddress address, int port)

    第一种构造函数创建DatagramPacket对象, 指定数据包的内存空间和大小.

    第二种构造函数不仅指定数据包的内存空间和大小, 而且还指定数据包的目标地址和端口, 在发送数据时, 必须指定接收方的Socket地址和端口号, 因此使用第二种构造函数可创建发送数据的DatagramPacket对象

 

2.3.2 DatagramSocket

    java.net包中的DatagramSocket类用来标识发送和接收数据包的Socket,其构造函数如下:

    1). DatagramSocket()

       构造数据包Socket并将其绑定到本地主机上任何可用的端口

    2). DatagramSocket(int port)

       构造数据包Socket并将其绑定到本地主机上指定的端口

    3). DatagramSocket(int port, InetAddress addr)

       构造数据包Socket并将其绑定到本指定的地址, 适用于有多块网卡和多个IP的情况

【注: 在接收程序时, 必须指定一个端口号, 不要让系统随机生成(随机生成端口号, 自己都不知道!)

 

2.3.3 UDP网络程序

    根据前面所讲的网络编程的基本知识, 以及UDP网络编程的特点, 下面创建一个广播数据包程序. 广播数据包是一种较新的技术, 类似于广播电台, 需要在指定的波段和频率上广播信息, 收听者也要将收音机调到指定的波段, 频率才可以接听广播内容

 

转载于:https://my.oschina.net/vwFisher/blog/2244638

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值