Skip to content

Latest commit

 

History

History
326 lines (222 loc) · 17.7 KB

ch10.md

File metadata and controls

326 lines (222 loc) · 17.7 KB
title
网络编程和通信

[TOC]

#网络编程和通信

##网络

###端口

Internet上传输的数据都带有标识目的主机与端口号的地址信息,主机的地址由32位的IP地址标识,IP协议通过该地址把数据发送到正确的目的主机; 端口号由一个16位的数字标识,TCP与UDP协议根据端口号把数据传送给正确的应用程序。

端口号的范围是0~65535,其中1~1023之间的端口号是为HTTP、FTP等系统应用保留的,FTP协议的端口号是21,HTTP协议的端口号是80,Telnet协议的端口号是23,用户应用程序只能使用1024以上的端口号,其中1024~4999可任意被用户用作客户端套接字端口,5000~65535可任意被用户用作服务端套接字端口。

##Java提供的网络功能

针对网络通信的不同层次,Java提供的网络功能有四大类:InetAddress 、URLs、Sockets、Datagram。

  • InetAddress: 面向IP层,用于标识网络上的硬件资源。

  • URL和URLConnection: 面向应用层,通过URL,Java程序可以直接送出或读入网络上的数据。

  • Sockets

    • 面向传输层。
    • Datagram则使用UDP协议,是另一种网络传输方式,它把数据的目的地纪录在数据包中,然后直接放在网络上。
  • Datagram:

    • 面向传输层。
    • Sockets使用的是TCP协议,这是传统网络程序最常用的方式,可以想象为两个不同的程序通过网络的通信信道进行通信。

###java.net包中的主要的类

  • 面向IP层的类:InetAddress

  • 面向应用层的类:URL、URLConnection

  • 面向传输层的类:

    • TCP协议相关类:Socket、ServerSocket
    • UDP协议相关类:DatagramPacket、DatagramSocket、 MulticastSocket

###可能产生的异常:

  • BindException、
  • ConnectException、
  • MalformedURLException、
  • NoRouteToHostException、
  • ProtocolException、
  • SocketException、
  • UnknownHostException、
  • UnknownServiceException

##Socket通信

###Socket通信机制

提供了两种通信方式:

  • 有连接方式(TCP) 有连接方式中,通信双方在开始时必须进行一次连接过程,建立一条通信链路。通信链路提供了可靠的、全双工的字节流服务。

  • 无连接方式(UDP数据报)。 无连接方式中,通信双方不存在一个连接过程,一次网络I/O以一个数据报形式进行,而且每次网络I/O可以和不同主机的不同进程进行。无连接方式开销小于有连接方式,但是所提供的数据传输服务不可靠,不能保证数据报一定到达目的地。

Java语言同时支持有连接和数据报通信方式,在这两种方式中都采用了Socket表示通信过程中的端点。

###Socket通信

  • 端到端的连接与通信
  • 网络上的两个程序(进程)通过一个双向的通信连接实现数据的交换。
  • 双向链路的一端称为一个socket(套接字)
  • 主机—端口(用于区分同一台主机上的不同的通信应用进程:01023系统 102465535用户)

###Socket通信过程

服务器端的程序首先选择一个端口(port)注册,然后调用accept()方法对此端口进行监听,即等待其它程序的连接申请。如果客户端的程序申请和此端口连接,那么服务器端就利用accept()方法来取得这个连接的Socket。客户端的程序建立Socket时必须指定服务器的地址(host)和通信的端口(port),这个端口必须与服务器端监听的端口保持一致。

##URL通信

URL(Uniform Resource Locator):统一资源定位器,它表示Internet/Intranet上一个资源的引用或地址,这些资源可以是一个文件、一个目录或一个对象。

URL是由一个字符串来描述的,URL包括协议和资源名称两部分,协议表示访问资源所需的协议,如HTTP、FTP等;资源名称表示要访问的资源地址。

###InetAddress类

InetAddress类是IP地址的封装类,描述了32位或128位IP地址。InetAddress类含有IP地址和域名,借助于这个类,既可以通过主机域名获得IP地址,也可通过主机IP地址获得域名。

InetAddress类没有构造函数,因此不能用new来构造一个InetAddress实例。通常是用它提供的静态方法来获取: public static InetAddress getByName(String host) :host可以是一个机器名,也可以是一个形如“%d.%d.%d.%d”的IP地址或一个DSN域名。 public static InetAddress getLocalHost() public static InetAddress[] getAllByName(String host) 这三个方法会产生UnknownHostException异常,应在程序中捕获处理。

InetAddress类的几个主要方法: String getHostName():获取InetAddress对象所含的域名 getHostAddress():获取InetAddress对象所含的IP地址

###URL类

####URL类的构造方法 (1) public URL(String spec) (2) public URL(String protocol, String host, String file) (3) public URL(String protocol,String host,String port,String file) (4) public URL(URL context,String spec) 注意:类URL的构造方法都声明抛出非运行时异常(MalformedURLException),因此生成URL对象时,我们必须要对这一异常进行处理,用try-catch语句进行捕获。

####URL类的成员方法

成员方法 功能说明
public int getPort() 获取端口号。若端口号未设置,返回–1
public String getProtocol() 获取协议名。若协议未设置,返回null
public String getHost() 获取主机名。若主机名未设置,返回null
public String getFile() 获取文件名。若文件名未设置,返回null
public boolean equals(Object obj) 与指定的URL对象obj进行比较,如果相同返回true,否则返回false
public final InputStream openStream() 获取输入流。若获取失败,则抛出一个java.io.Exception异常。
public URLConnection openConnection() 生成关联该URL的一个URLConnection对象
String toString() 将此URL对象转换成字符串形式

###URLConnection类

通过URLConnection类,可以在应用程序和URL资源之间进行交互,既可以从URL中读取数据,也可以向URL中发送数据。URLConnection类表示了应用程序和URL资源之间的通信连接。

1.创建URLConnection类的对象 URLConnection类是一个抽象类,创建URLConnection对象分两步完成:创建一个URL对象,然后调用该URL对象的openConnection()方法返回一个对应其URL地址的URLConnection对象。

2.向服务器端写数据 首先建立输出数据流: PrintStream out=new PrintStream(con.getOutputStream()); 然后向服务器写入信息: out.println(String data);

3.从服务器端读数据 建立输入数据流: InputStreamReader ins=new InputStreamReader(con.getInputStream()); BufferedReader in=new BufferedReader(ins); 或: DataInputStream dis=new DataInputStream(con.getInputStream()); 然后从服务器读信息: in.readLine(); 或:is.readLine();

###TCP Socket通信

TCP(Transport Control Protocol) 两主机之间有连接的、可靠的、端对端(end-to-end)的数据流的传输 如http, ftp, telnet 的传输层均使用此协议

为了支持TCP/IP面向连接的网络程序的开发,java.net包提供了Socket类与ServerSocket类,ServerSocket类和Socket类均直接继承于Java的Object根类。 其中,ServerSocket类用于服务端程序,它有一个accept方法专门用来监听客户端的连接,并产生一个与客户端连接相对应的Socket对象; Socket类则是服务端程序和客户端程序都要用到的类,该类专门用来处理连接双方的数据通信。 一个Socket由一个IP地址和一个端口号唯一确定。

####URL通信与Socket通信的区别

URL通信与Socket通信都是面向连接的通信。区别在于:

  • (1)Socket通信方式为主动等待客户端的服务请求方式,而URL通信方式为被动等待客户端的服务请求方式。

  • (2)利用Socket进行通信时,在服务器端运行了一个Socket通信程序,不停地监听客户端的连接请求,当接到客户端请求后,马上建立连接并进行通信。利用URL进行通信时,在服务器端常驻一个CGI程序,但它一直处于睡眠状态,只有当客户端的连接请求到达时才被唤醒,然后建立连接并进行通信。

  • (3)在Socket通信方式中,服务器端的程序可以打开多个线程与多个客户端进行通信,并且还可以通过服务器使各个客户端之间进行通信,这种方式适合于一些较复杂的通信。而在URL通信方式中,服务器端的程序只能与一个客户进行通信,这种方式比较适合于B/S通信模式。

####使用Socket通信过程

利用socket进行有连接的通信过程包括以下三个步骤:

  • (1) 创建socket,建立连接 java.net包中的两个类Socket与ServerSocket分别表示连接的Client端和Server端,进行网络通信的方法也都封装在这两个类中。建立连接首先要创建这两个类的对象并把它们关联起来。

  • (2) 打开连接到Socket的输入输出流,按照一定的协议对Socket进行读写操作 连接建立后,要进一步获取连接上的I/O流,并通过这些流进行数据传输。

  • (3) 关闭Socket

####Socket类

#####构造方法:

构造方法 功能说明
public Socket(InetAddress address,int port) 使用InetAddress对象所表示的IP地址以及端口号(port)向服务器发起连接,若成功则创建Socket对象,否则抛出异常
public Socket(InetAddress address,int port, boolean stream) 同上,若布尔参数为true,则采用流式通信方式,否则为数据报通信方式
public Socket(String host,int port) 使用指定端口port和主机host,向服务器发起连接,若成功则创建Socket对象,否则抛出异常
public Socket(String host,int port,Boolean stream) 同上,布尔参数为true,则采用流式通信方式

#####常用成员方法

常用成员方法 功能说明
public void close() 关闭Socket,释放资源
public InputStream getInputStream() 获取与Socket相关联的字节输入流,用于从Socket中读数据
public OutputStream getOutputStream() 获取与Socket相关联的字节输出流,用于向Socket中写数据
public int getLocalPort() 返回本地Socket中的端口号
public int getPort() 返回对方Socket中的端口号
public InetAddress getLocalAddress() 返回本地Socket中IP的InetAddress对象
public InetAddress getInetAddress() 返回对方Socket中IP的InetAddress对象
public void setSoTimeout(int timeout) 设置客户端的连接超时时间。当程序调用Socket输入流对象的read方法读取数据后,程序将处于阻塞状态,直到setSoTimeout方法所设置的timeout时间超时为止。如果timeout为0,将表示read方法无限期地等待数据来读取

####ServerSocket类 #####构造方法:

构造方法 功能说明
public ServerSocket(int port) throws IOException 在指定的端口创建一个服务器Socket对象,默认可接收50个客户端连接。如果端口号设置为0,则自动挑选一个空闲的端口号。如果打开这个套接字时出现I/O错误,则抛出异常对象IOException
public ServerSocket(int port,int count) throws IOException 在指定的端口port创建一个服务器 Socket对象,并说明服务器端所能支持的最大连接数count,如果超过此数目,客户端连接将被拒绝
public ServerSocket(int port,int count, InetAddress bindArr) throws IOException 在指定的端口port创建一个服务器 Socket对象,并说明服务器端所能支持的最大连接数count,bindAddr可用来绑定服务器程序所使用的IP地址。如果运行服务端程序的机器配置了多个IP地址(多网卡),这个构造函数将非常有用

#####常用成员方法

常用成员方法 功能说明
public Socket accept() throws IOException 监听客户端的连接请求。accept方法调用后,服务器程序将处于阻塞状态,直到监听到客户端连接,返回一个新创建的Socket对象。接下来利用这个返回的Socket对象与客户端进行数据收发
public void setSoTimeout(int timeout) 设置服务器程序等待客户端连接的最长时间timeout,时间单位为毫秒。如果timeout为0,将表示无限期等待客户端连接。该方法必须在accept方法之前被调用
public void close() throws IOException 关闭套接字资源

###基于TCP的socket编程

####服务器程序编写

①调用ServerSocket(int port)创建一个服务器端套接字,并绑定到指定端口上; ②调用accept(),监听连接请求,如果客户端请求连接,则接受连接,返回通信套接字。 ③调用Socket类的getOutputStream()和getInputStream获取输出流和输入流,开始网络数据的发送和接收。 ④最后关闭通信套接字。

####客户端程序编写:

①调用Socket()创建一个流套接字,并连接到服务器端; ②调用Socket类的getOutputStream()和getInputStream获取输出流和输入流,开始网络数据的发送和接收。 ③最后关闭通信套接字。

###数据报通信

用户数据报协议UDP是传输层的无连接通信协议。数据报是一种在网络中独立传播的自身包含地址信息的消息,它能否到达目的地、到达的时间以及到达时内容能否保持不变,这些都是不能保证的。由于UDP通信速度较快,所以常常被应用在某些无须实时交互、准确性要求不高、但传输速度要求较高的场合。 Java.net软件包中的DatagramSocket类和DatagramPacket类为实现UDP通信提供了支持。DatagramSocket用于在程序中间建立传送数据报的通信连接,DatagramPacket则用来表示一个数据报。

####数据报方式的通信过程 (1) 创建数据报Socket; (2) 构造用于接收或发送的数据报,并调用所创建Socket的receive()方法进行数据报接收或调用send()发送数据报。 (3)通信结束,关闭Socket。

####DatagramSocket类 DatagramSocket类的三个构造方法如下: (1) DatagramSocket():创建DatagramSocket对象并与本地主机某个可用端口相连。 (2) DatagramSocket(int port):创建DatagramSocket对象并与指定端口相连。 (3) DatagramSocket(int port,InetAddress iaddr):创建一个于本地地址绑定的DatagramSocket对象。

####基于UDP的socket编程

#####接收端程序编写: ①调用DatagramSocket(int port)创建一个数据报套接字,并绑定到指定端口上; ②调用DatagramPacket(byte[] buf, int length),建立一个字节数组以接收UDP包 。 ③调用DatagramSocket类的receive(),接收UDP包。 ④最后关闭数据报套接字。

#####发送端程序编写: ①调用DatagramSocket()创建一个数据报套接字; ②调用DatagramPacket(byte[] buf, int offset, int length, InetAddress address, int port),建立要发送的UDP包。 ③调用DatagramSocket类的send(),发送UDP包。 ④最后关闭数据报套接字。

#####DatagramSocket类的常用方法如下: (1) void receive(DatagramPacket packet)throws IOException receive()方法将使程序中的线程一直处于阻塞状态,直到从当前socket中接收到信息时,将收到的信息存储在receive()方法的对象参数packet的存储机构中。 (2) void send(DatagramPacket packet)throws IOException send()方法将其参数DatagramPacket对象packet中包含的数据报文发送到所指定的IP地址主机的指定端口。 (3) void setSotimeout(int timeout) throws IOException 当程序调用DatagramSocket的receive方法以读取数据后,程序将处于阻塞状态,知道setSoTimeout方法所设置时间超时为止。 (4) void close() 关闭数据报套接字,它不会抛出异常对象。

####DatagramPacket类 当DatagramSocket套接字创建后,就可以用它来发送和接收数据报了。数据报是一个DatagramPacket类的对象,创建时必须指明目的端的IP地址和端口号,这样发送到网络上的数据报才可以被网关路由。DatagramPacket类的构造方法,分别对应接收数据报和发送数据报:

(1) public DatagramPacket(byte[] buf,int length) 创建接收length长度的数据报对象。其中buf为接收数据报的字节数组,length为读取的字节数,length必须小于等于buf.length。

(2) public DatagramPacket(byte[]buf, int offset, int length, InetAddress address, int port) 这个构造方法用来创建发送数据报对象。其中,buf代表发送数据报的字节数组;length代表发送数据报的长度;address代表发送数据报的目的地址,即接收者的IP地址;port代表发送数据报的端口号。

#####DatagramPacket类的常用方法如下: (1) public InetAddress getAddress() 返回发出数据报或接收数据报的机器的IP地址。 (2) public int getPort() 返回发出数据报或接收数据报的远程主机的端口号。 (3) public void setAddress(InetAddress iaddr) 设置接收数据报的机器的IP地址。

##练习

  1. 什么是端口号?服务器端和客户端分别如何使用端口号?
  2. 什么事套接字,其作用是什么?
  3. 编写一个可以查询网络域名的程序。
  4. 编写一个功能完善的聊天室程序。
  5. 编写一个客户/服务器程序,服务器端的功能是计算圆的面积。客户端将圆的半径发送给服务器,服务器端将计算得出的圆面积发送给客户端,并在客户端显示。

本文档 Github : https://github.com/bushehui/Java_tutorial

<script type="text/javascript" async src="https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-MML-AM_CHTML"> </script> <script type="text/x-mathjax-config"> MathJax.Hub.Config({tex2jax: {inlineMath: [['$','$'], ['\\(','\\)']]}}); </script>