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(套接字)
- 主机—端口(用于区分同一台主机上的不同的通信应用进程:0
1023系统 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地址。
##练习
- 什么是端口号?服务器端和客户端分别如何使用端口号?
- 什么事套接字,其作用是什么?
- 编写一个可以查询网络域名的程序。
- 编写一个功能完善的聊天室程序。
- 编写一个客户/服务器程序,服务器端的功能是计算圆的面积。客户端将圆的半径发送给服务器,服务器端将计算得出的圆面积发送给客户端,并在客户端显示。
本文档 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>