Java Network Programming [Java网络编程]
127.0.0.1 本机地址
192.168.0.0–192.168.255.255为私有地址,属于非注册地址,专门为组织机构内部使用。
IP地址用来标识一台计算机,但是一台计算机上可能提供多种网络应用程序,需要用端口来区分这些不同的程序呢。
端口是虚拟的概念,并不是说在主机上真的有若干个端口。通过端口,可以在一个主机上运行多个网络应用程序。 端口的表示是一个16位的二进制整数,对应十进制的0-65535。所以端口号总共有65536个
1024以下端口号不要用,预留号码。同一个协议下,端口号不能重复。不同协议,端口号可以重复。
所以IP地址好比每个人的地址(门牌号),端口好比是房间号。必须同时指定IP地址和端口号才能够正确的发送数据。
URL & URI
在www上,每一信息资源都有统一且唯一的地址,该地址就叫URL(Uniform Resource Locator),它是www的统一资源定位符。URL由4部分组成:协议 、存放资源的主机域名、资源文件名和端口号。如果未指定该端口号,则使用协议默认的端口。例如http 协议的默认端口为 80。 在浏览器中访问网页时,地址栏显示的地址就是URL。
在java.net包中提供了URL类,该类封装了大量复杂的涉及从远程站点获取信息的细节。
URL[Uniform Resource Locator] 统一资源定位
URI[Uniform Resource Identifier] 统一资源标识,其实就是统一资源。所以URI就是统一资源而URL是统一资源的定位服务。
DNS
DNS[Domain Name Server,域名服务器]主要进行域名解析服务,也就是把域名比如www.google.com
,翻译成与之相对应的IP地址。DNS中保存了一张域名[domain name]和与之相对应的IP地址[IP address]的表,以解析消息的域名。
InetAddress类 & InetScoketAddress类
InetAddress封装计算机的IP地址和DNS,但没有端口信息。
由于这个类没有构造方法。如果要得到对象,只能通过静态方法getLocalHost()、getByName()、 getAllByName()、 getAddress()、getHostName()来获得。下面是使用实例:
import java.net.InetAddress;
import java.net.UnknownHostException;
public class Test1 {
public static void main(String[] args) throws UnknownHostException {
InetAddress addr = InetAddress.getLocalHost();
//返回IP地址
System.out.println(addr.getHostAddress());
//输出计算机名
System.out.println(addr.getHostName());
}
}
import java.net.InetAddress;
import java.net.UnknownHostException;
public class Test2 {
public static void main(String[] args) throws UnknownHostException {
InetAddress addr = InetAddress.getByName("www.sxt.cn");
// 返回 服务器的IP
System.out.println(addr.getHostAddress());
// 输出:主机名
System.out.println(addr.getHostName());
}
}
import java.net.InetAddress;
import java.net.UnknownHostException;
public class Test3 {
public static void main(String[] args) throws UnknownHostException {
InetAddress addr = InetAddress.getByName("59.110.14.7");
// 返回机器的IP
System.out.println(addr.getHostAddress());
/*
* 输出ip而不是域名。如果这个IP地址不存在或DNS服务器不允许进行IP地址
* 和域名的映射,getHostName方法就直接返回这个IP地址。
*/
System.out.println(addr.getHostName());
}
}
InetScoketAddress包含IP和端口信息,常用于Socket通信。此类实现IP套接字地址[IP 地址 + 端口号],不依赖任何协议。下面是使用实例:
import java.net.InetSocketAddress;
public class Test4 {
public static void main(String[] args) {
InetSocketAddress socketAddress = new InetSocketAddress("127.0.0.1", 8080);
InetSocketAddress socketAddress2 = new InetSocketAddress("localhost", 9000);
System.out.println(socketAddress.getHostName());
System.out.println(socketAddress2.getAddress());
}
}
TCP & UDP
TCP协议和UDP协议是传输层的两种协议。Socket是传输层供给应用层的编程接口,所以Socket编程就分为TCP编程和UDP编程两类。
在网络通讯中,TCP方式就类似于拨打电话,使用该种方式进行网络通讯时,需要建立专门的虚拟连接,然后进行可靠的数据传输,如果数据发送失败,则客户端会自动重发该数据。而UDP方式就类似于发送短信,使用这种方式进行网络通讯时,不需要建立专门的虚拟连接,传输也不是很可靠,如果发送失败则客户端无法获得。
这两种传输方式都在实际的网络编程中使用,重要的数据一般使用TCP方式进行数据传输,而大量的非核心数据则可以通过UDP方式进行传递,在一些程序中甚至结合使用这两种方式进行数据传递。
由于TCP需要建立专用的虚拟连接以及确认传输是否正确,所以使用TCP方式的速度稍微慢一些,而且传输时产生的数据量要比UDP稍微大一些。
TCP在建立连接时分三步走:
-
是请求端(客户端)发送一个包含SYN即同步(Synchronize)标志的TCP报文,SYN同步报文会指明客户端使用的端口以及TCP连接的初始序号。
-
服务器在收到客户端的SYN报文后,将返回一个SYN+ACK的报文,表示客户端的请求被接受,同时TCP序号被加一,ACK即确认(Acknowledgement)。
-
客户端也返回一个确认报文ACK给服务器端,同样TCP序列号被加一,到此一个TCP连接完成。然后才开始通信的第二步:数据处理。
这就是所说的TCP的三次握手(Three-way Handshake)。
基于UDP协议的通信方式,称为数据报通信方式。在这种方式中,每个数据发送单元被统一封装成数据包的方式,发送方将数据报包发送到网络中,数据报包在网络中去寻找它的目的地。
总结
-
TCP是面向连接的,传输数据安全,稳定,效率相对较低。
-
UDP是面向无连接的,传输数据不安全,效率较高。
UDP 通信
DatagramSocket:用于发送或接收数据报包
当服务器要向客户端发送数据时,需要在服务器端产生一个DatagramSocket对象,在客户端产生一个DatagramSocket对象。服务器端的DatagramSocket将DatagramPacket发送到网络上,然后被客户端的DatagramSocket接收。
DatagramSocket有两种常用的构造函数。一种是无需任何参数的,常用于客户端;另一种需要指定端口,常用于服务器端。如下所示:
DatagramSocket() :构造数据报套接字并将其绑定到本地主机上任何可用的端口。
DatagramSocket(int port) :创建数据报套接字并将其绑定到本地主机上的指定端口。
DatagramSocket常用方法:
-
send(DatagramPacket p) :从此套接字发送数据报包。
-
receive(DatagramPacket p) :从此套接字接收数据报包。
-
close() :关闭此数据报套接字。
DatagramPacket:数据容器(封包)的作用。此类表示数据报包,数据报包用来实现封包的功能。
DatagramPacket常用方法:
-
DatagramPacket(byte[] buf, int length) :构造数据报包,用来接收长度为 length 的数据包。
-
DatagramPacket(byte[] buf, int length, InetAddress address, int port) :构造数据报包,用来将长度为 length 的包发送到指定主机上的指定端口号。
-
getAddress() :获取发送或接收方计算机的IP地址,此数据报将要发往该机器或者是从该机器接收到的。
-
getData() :获取发送或接收的数据。
-
setData(byte[] buf) :设置发送的数据。
UDP通信编程基本步骤:
-
创建客户端的DatagramSocket,创建时,定义客户端的监听端口。
-
创建服务器端的DatagramSocket,创建时,定义服务器端的监听端口。
-
在服务器端定义DatagramPacket对象,封装待发送的数据包。
-
客户端将数据报包发送出去。
-
服务器端接收数据报包。
TCP 通信
在TCP网络通讯中,第一次主动发起通讯的程序被称作客户端(Client)程序,简称客户端,而在第一次通讯中等待连接的程序被称作服务器端(Server)程序,简称服务器。一旦通讯建立,则客户端和服务器端完全一样,没有本质的区别。
Socket类用于发送TCP消息。ServerSocket类用于创建服务器。
套接字是一种进程间的数据交换机制。这些进程既可以在同一机器上,也可以在通过网络连接的不同机器上。换句话说,套接字起到通信端点的作用。单个套接字是一个端点,而一对套接字则构成一个双向通信信道,使非关联进程可以在本地或通过网络进行数据交换。一旦建立套接字连接,数据即可在相同或不同的系统中双向或单向发送,直到其中一个端点关闭连接。套接字与主机地址和端口地址相关联。主机地址就是客户端或服务器程序所在的主机的IP地址。端口地址是指客户端或服务器程序使用的主机的通信端口。
在客户端和服务器中,分别创建独立的Socket,并通过Socket的属性,将两个Socket进行连接,这样,客户端和服务器通过套接字所建立的连接使用输入输出流进行通信。
TCP/IP套接字是最可靠的双向流协议,使用TCP/IP可以发送任意数量的数据。
实际上,套接字只是计算机上已编号的端口。如果发送方和接收方计算机确定好端口,他们就可以通信了。
TCP/IP通信连接的简单过程:
位于A计算机上的TCP/IP软件向B计算机发送包含端口号的消息,B计算机的TCP/IP软件接收该消息,并进行检查,查看是否有它知道的程序正在该端口上接收消息。如果有,他就将该消息交给这个程序。
要使程序有效地运行,就必须有一个客户端和一个服务器。
通过Socket的编程顺序:
-
创建服务器ServerSocket,在创建时,定义ServerSocket的监听端口(在这个端口接收客户端发来的消息)。
-
ServerSocket调用accept()方法,使之处于阻塞状态[阻塞的意思是如果accept方法无法正常执行,程序就会停滞在这里直到正常执行]。
-
创建客户端Socket,并设置服务器的IP及端口。
-
客户端发出连接请求,建立连接。
-
分别取得服务器和客户端Socket的InputStream和OutputStream。
-
利用Socket和ServerSocket进行数据传输。
-
关闭流及Socket。
通过类似的流程可以建立基于socket的单向或者双向连接。