网络通信
网络通信是指物理上位于两台计算机上的两个进程之间通过网络交换信息的过程。
网络通信的核心是协议。协议是指进程之间交换信息为完成任务所使用的一系列规则和规范。在Internet网络通信中,主要使用的协议有适用于网络层的IP协议,适用于传输层的TCP、UDP协议,适用于应用层的HTTP、FTP、SMTP、NNTP(主要用于解释数据内容)。
当用Java语言进行网络编程时,程序主要处理的是应用层的任务,但需要根据传输层所选择的协议而选用不同网络API以完成实际的网络通信任务。这些基本网络类包括在Java.net包中。
Java网络通信可以在三个层次上进行:
1)URL层次,即最高层次,基于应用层通信协议,利用URL诸暨人进行Internet上的资源访问和数据传输。
2)Socket层次,即传统网络编程经常采用的流式套接字方式,通过在C/S(客户机/服务器)结构的应用程序之间建立Socket套接字连接,然后在连接之上进行数据通信。
3)Datagram数据包层次,即最低层次,采用一种无连接的数据包套接字传输方法,是用户数据报(UDP)协议的通信方式。
1. 使用URL访问网络资源
URL(Uniform Resource Locator,统一资源定位器)表示网络上某一资源的地址。URL由协议名称和资源名称两部分组成。资源名称应该是资源的完整地址,包括主机名、端口号、文件名或文件内部的一个引用,格式为:
<协议名>://<主机名>:<端口号>/<文件名>#<引用>
例:
http://Java.sun.com/index.html#chapter1
(端口号是用来区分不同的网络服务,如果没有端口号,则表示端口号为该协议的默认值)
- URL类
1. 创建URL
1)public URL(String spec)。最简单常用,spec表示一个完整的可在浏览器看到的URL地址。
URL u = new URL(http://www.xatu.edu.cn/);
2)public URL(String protocol,String host,String file)。
3)public URL(String protocol,String host,int port,String file)。
URL u = new URL("http","www.126.net","/index.html");
URL u = new URL("http","Java.sun.com",80,"docs/books/shuqi.intro.html");
4)public URL(URL context,String spec)。这方法基于一个已有的URL对象创建一个新的URL对象,多用于访问同一个主机上不同路径的文件。
URL u = new URL("http://Java.sun.com:80/docs/books/");
URL u1 = new URL(u,"shuqi.intro.html");
URL u2 = new URL(u,"shuqi.supre.html");
使用URL构造方法创建对象时,若出现参数出错时,应处理一个产生的非运行时的异常。
try{
URL u = new URL(...);
}catch(MalfromedURLException e){
....
}
2. 获取URL对象的属性
getProtocol():返回URL的协议标志部分。
getHost():返回URL的主机名部分。
getPort():将端口号作为整数返回,如没有设置则返回-1。
getPath():返回该URL的路径。
getFile():返回URL的文件名部分。
getRef():返回URL的引用部分。快速导航到指定界面。
在这些URL属性获取方法中,如果某些属性不存在,这些方法就返回null或-1。
【实例】
import java.net.MalformedURLException;
import java.net.URL;
public class URLTest {
public static void main(String[] args) {
URL u = null;
URL u1 = null;
try {
// 创建URL对象
u = new URL("http","Java.sun.com",80,"docs/books/shuqi.intro.html");
u1 = new URL("http://Java.sun.com:80/docs/books#down");
} catch (MalformedURLException e) {
e.printStackTrace();
}
// 显示u对象的各属性值
System.out.println("协议: "+u.getProtocol());
System.out.println("主机名: "+u.getHost());
System.out.println("端口名: "+u.getPort());
System.out.println("文件名: "+u.getFile());
System.out.println("锚点: "+u.getRef());
System.out.println("协议: "+u1.getProtocol());
System.out.println("主机名: "+u1.getHost());
System.out.println("端口名: "+u1.getPort());
System.out.println("文件名: "+u1.getFile());
System.out.println("锚点: "+u1.getRef());
}
}
运行结果:
3. 通过URL对象访问网络资源
URL对象创建后,就可以通过它来访问指定的www资源。这时需要调用URL类的openStream()方法,其定义如下:
public final InputStream openStream();
该方法与指定URL建立连接并返回一个InputStream类的对象,这样访问网络资源的操作就变成了熟悉的I/O操作,通过这个InputStream对象,可用字节流的方式读取资源数据。
- URLConnection类
URLConnection类可以实现同网络资源的双向通信,表示Java程序和URL在网络上的通信连接。当与一个URL建立连接时,首先要在一个URL对象上通过URL类提供的openConnection()获得对应的URLConnection对象,其定义为:
public URLConnection openConnection();
此时调用URLConnection类的getInputStream()和getOutputStream()方法就可以得到输入/输出流。
通过URLConnection类,可以在应用程序和URL资源之间进行交互,既可以从URL中读取数据,也可以向URL中发送数据。
创建URLConnection实例:
URL myurl = new URL("http://www.sina.com.cn");
URLConnection urlCon = myurl.openConnection();
通过写URLConnection对象,Java程序可以与服务器cgi-bin下的程序交互,其步骤是:创建URL对象,打开到URL对象的连接,设置写URLConnection对象,获得URLConnection对象的流,写输出流和关闭流。
2. Socket通信
TCP提供了一个可靠的通信通道,client-server应用程序在Internet上就通过这个双向的通信连接实现数据的交换,这个双向链路的一端称为一个套接字(Socket)。套接字通常用来实现客户端和服务器端的连接。一个套接字由一个IP地址和一个端口号唯一确定,在Java环境下,Socket编程主要指基于TCP/IP协议的网络编程。
- Socket通信原理
Socket连接是一个点对点的连接,在建立连接前,必须有一方在监听,另一方在请求。一旦建立Socket连接,就可以实现数据之间的双向传输。
1. Socket类
表示双向连接的客户端
常用的构造方法:
public Socket(String host,int port)throws UnknownHostException,IOException;
public Socket(InetAddress address,int port)throws IOException.
其中,port用于指定服务器端程序监听的端口号,address根据InetAddress对象指定服务器端IP地址。
Socket对象实例化成功,即表示与服务器方建立好连接,但数据的发送和接收还需要从Socket对象中得到输入流和输出流才能进行,流的获取方法:
1) pubic InputStream getInputStream() throws IOException.
获取与Socket相关联的字节输出流,用于从Socket中读数据。
2)public OutputStream getOutputStream() throws IOException.
获取与Socket相关联的字节输出流,用于向Socket中写数据。
3)public int getLocalPort().
获得本地Socket中的端口号。
此后,就可以用与处理I/O流相同的方式开始通信。Socket对象会占用重要的非内存资源,垃圾收集器无法自动清除它。因此,通信结束时必须调用如下方法确保妥善关闭Socket:
public void close() throws IOException
用Socket建立客户端主要的四个步骤:
在要相互通信的程序之间创建一个Socket;
利用Socket类提供的方法来货的输入/输出流;
利用输入/输出流处理数据;
关闭Socket。
2. SeverSocket类
表示双向连接的服务器端
常用的构造方法:
public ServerSocket(int port)throws IOException;
public ServerSocket(int port,int backlog)throws IOException;
其中,port用于指定端口号;backlog指定连接队列的最大长度,即可同时连接的客户端数量。
完成监听端口和等待连接功能,所采用的方法:
public Socket accept() throws IOException;
该方法是阻塞方法,该方法被调用后,将一直处于等待状态中,直到意外中止或客户端发来连接请求为止。
当客户端发来请求时,该方法返回一个对应于客户的新建Socket对象,代表服务器端的Socket。这时,
服务器端程序则用该Socket对象与客户端Socket进行通信,接下来就是由各个Socket分别打开各自的输入/输出流。
同样,服务器端也可以调用其方法close()关闭。
使用SeverSocket类建立服务器的主要步骤:
创建一个SeverSocket;
服务器对客户端进行监听;
服务器调用Socket类的方法获得输入/输出流;
利用输入、输出流处理数据;
关闭连接。
【实例】
服务器端:
public class Server {
public static void main(String[] args) {
//申请一个端口
ServerSocket ss = null;
Socket s = null;
InputStream in = null;
ObjectInputStream obji = null;
try {
ss = new ServerSocket(8888);
//等待客户连接
System.out.println("等待客户连接...");
s = ss.accept();
System.out.println("已连接[客户IP"+s.getInetAddress().getHostAddress()+":"+ s.getPort()+"]");
in = s.getInputStream();
obji = new ObjectInputStream(in);
int a = obji.readInt();
Boolean b = obji.readBoolean();
Double c = obji.readDouble();
Object d = obji.readObject();
System.out.println(a + ":" + b + ":" + c + ":" + (Date)d);
} catch (Exception e) {
e.printStackTrace();
}
}
}
客户端:
public class Client {
public static void main(String[] args) {
Socket s = null;
OutputStream out = null;
ObjectOutputStream objo = null;
try {
s = new Socket("127.0.1.1", 8888);
out = s.getOutputStream();
objo = new ObjectOutputStream(out);
objo.writeInt(200);
objo.writeBoolean(false);
objo.writeDouble(22.3);
objo.writeObject(new Date());
out.flush();
Thread.sleep(1000);
}catch (Exception e) {
e.printStackTrace();
}
运行结果:
- Java的Socket通信实现
通信步骤如下:
在服务器端创建一个SeverSocket对象,指定端口。
运行ServerSocket的accept()方法,等候客户端请求。
客户端建立一个Socket对象,指定计算机地址和端口号,向服务器端发出连接请求。
服务器端接收到客户端请求后,创建Socket对象与客户端建立连接。
服务器端和客户端分别建立输入/输出数据流,进行数据传输。
通信结束后,服务器端和客户端分别关闭响应的Socket连接。
服务器端程序运行结束后,调用ServerSocket对象的close(1)方法停止等候客户端请求。