网络的五层协议:
应用层(Application Layer)、传输层(Transport Layer)、网络层(Network Layer)、链路层(Link Layer)、物理层(Physical Layer) --自上而下
一、物理层:
实体层,就是把电脑连接起来的物理手段。它主要规定了网络的一些电气特性,作用是负责传送0和1的电信号。
二、链路层:
通过以太网协议在同一个子网络里发送数据包。
以太网协议:(不是Http协议)
以太网规定,一组电信号构成一个数据包,叫做"帧"(Frame)。每一帧分成两个部分:标头(Head)和数据(Data)。
"标头"包含数据包的一些说明项,比如发送者、接受者、数据类型等等;"数据"则是数据包的具体内容。
"标头"的长度,固定为18字节。"数据"的长度,最短为46字节,最长为1500字节。因此,整个"帧"最短为64字节,最长为1518字节。如果数据很长,就必须分割成多个包进行发送。
MAC地址:
"标头"中发送者和接受者的信息:以太网规定,连入网络的所有设备,都必须具有"网卡"接口。数据包是从一块网卡,传送到另一块网卡。网卡的地址,就是数据包的发送地址和接收地址,这叫做MAC地址。
三、网络层:
ip到ip的数据传送(点到点的链接),是否是在同一子网络,不在统一子网络的话,先把包发送给本网络网关,本网关再找另一个ip所在的网关.
网络层使用ip地址,使得我们能够区分不同的计算机是否属于同一个子网络。
于是,每台计算机有了两种地址,一种是MAC地址,另一种是网络地址。两种地址之间没有任何联系,MAC地址是绑定在网卡上的,网络地址则是管理员分配的。
ip地址确定计算机所在的子网络,MAC地址则将数据包送到该子网络中的目标网卡。先处理网络地址,然后再处理MAC地址。
四、传输层:
有了MAC地址和IP地址,我们已经可以在互联网上任意两台主机上建立通信。
接下来需要一个参数,表示这个数据包到底供哪个程序(进程)使用。这个参数就叫做"端口"(port),它其实是所每一个使用网卡的程序的编号。每个数据包都发到主机的特定端口,所以不同的程序就能取到自己需要的数据。
"传输层"的功能,就是建立"端口到端口"的通信。相比之下,"网络层"的功能是建立"主机到主机"的通信。只要确定主机和端口,我们就能实现程序之间的交流。(端到端的链接)
UPD协议:
"标头"部分主要定义了发出端口和接收端口,"数据"部分就是具体的内容。然后,把整个UDP数据包放入IP数据包的"数据"部分,而前面说过,IP数据包又是放在以太网数据包之中的,所以整个以太网数据包现在变成了下面这样:
UDP数据包非常简单,"标头"部分一共只有8个字节,总长度不超过65,535字节,正好放进一个IP数据包。
TCP协议:(打电话)
优点:TCP 具有高可靠性,确保传输数据的正确性,不出现丢失或乱序(有序)
缺点:TCP相对于UDP速度慢一点,效率低,而且要求系统资源较多,每个连接都会占用系统的 CPU、内存等硬件资源。
UDP协议:(寄信)
优点:UDP速度快、操作简单、要求系统资源较少
缺点:不可靠,可能会出现丢包、乱序、数据不完整
点击按钮,产生监听事件,执行监听方法,获得输出文本框的内容返回字节数组对象,获得地址,将信放进报文(信封)里,邮递员拿到信封,送信。 另一方准备一个空数组对象,空数据报,用来收信(通过端口号),拆信封
TCP和UDP的区别:
1、TCP 是面向连接的传输控制协议,而UDP 提供了无连接的数据报服务。
2、TCP是保证数据的正确性,UDP可能会丢包
3、UDP 具有较好的实时性,工作效率比 TCP 协议高。
4、每一条TCP连接只能是点到点的,UDP支持一对一,一对多,多对一和多对多的交互通信
5、TCP对系统资源要求较多,UDP对系统资源要求较少
三次握手 (三次握手就是为了检测双方的 发送和接收能力是否正常)
小明:我想和你建立连接,发送一个请求SYN,然后进入SYN_SEND状态
小李:好啊,我也想和你建立连接,这里是小李监听到连接请求之后,将连接放入内核等待队列,然后发送一个确认报文段ACK和请求SYN
小明:那我们开始建立联系吧。 这里就是小明收到小李的ACK和SYN后,发送一个确认报文段ACK,进入established状态,小李收到后也进入established状态
四次挥手
小明:我要挂电话了。发送一个结束报文段FIN包,进入FIN_WAIT1状态
小李:我知道了,你先别挂,我还有话说。 小李返回一个确认报文段ACK,然后继续发送数据, 此时小明收到小李的ACK之后,进入FIN_WAIT2状态
小李:我话说完了,可以挂了。小李发送一个结束报文段FIN包,进入LAST_ACK状态
小明:好的,等待2MSL时间之后也挂了。此时小明进入TIME_WAIT状态,发送确认报文段ACK,小李收到后进入CLOSED状态,断开连接,而小明在等待2MSL的时间之后也断开连接。
五、应用层:
"应用层"的作用,就是规定应用程序的数据格式。
应用层协议最著名的就是HTTP, FTP了, 还有一个重要的DNS。
举例来说,TCP协议可以为各种各样的程序传递数据,比如Email、WWW、FTP等等。那么,必须有不同协议规定电子邮件、网页、FTP数据的格式,这些应用程序协议就构成了"应用层"。
这是最高的一层,直接面对用户。它的数据就放在TCP数据包的"数据"部分。因此,现在的以太网的数据包就变成下面这样。
二、网关
我们已经知道,网络通信就是交换数据包。电脑A向电脑B发送一个数据包,后者收到了,回复一个数据包,从而实现两台电脑之间的通信。数据包的结构,基本上是下面这样:
有了这两个地址,数据包才能准确送到接收者手中。但是,前面说过,MAC地址有局限性,如果两台电脑不在同一个子网络,就无法知道对方的MAC地址,必须通过网关(gateway)转发。
上图中,1号电脑要向4号电脑发送一个数据包。它先判断4号电脑是否在同一个子网络,结果发现不是(后文介绍判断方法),于是就把这个数据包发到网关A。网关A通过路由协议,发现4号电脑位于子网络B,又把数据包发给网关B,网关B再转发到4号电脑。
1号电脑把数据包发到网关A,必须知道网关A的MAC地址。所以,数据包的目标地址,实际上分成两种情况:
场景 | 数据包地址 |
同一个子网络 | 对方的MAC地址,对方的IP地址 |
非同一个子网络 | 网关的MAC地址,对方的IP地址 |
发送数据包之前,电脑必须判断对方是否在同一个子网络,然后选择相应的MAC地址。接下来,我们就来看,实际使用中,这个过程是怎么完成的。
三、用户的上网设置
通常你必须做一些设置。有时,管理员(或者ISP)会告诉你下面四个参数,你把它们填入操作系统,计算机就能连上网了:
* 本机的IP地址 * 子网掩码 * 网关的IP地址 * DNS的IP地址
这四个参数缺一不可,后文会解释为什么需要知道它们才能上网。由于它们是给定的,计算机每次开机,都会分到同样的IP地址,所以这种情况被称作"静态IP地址上网"。
但是,这样的设置很专业,普通用户望而生畏,而且如果一台电脑的IP地址保持不变,其他电脑就不能使用这个地址,不够灵活。出于这两个原因,大多数用户使用"动态IP地址上网"。
所谓"动态IP地址",指计算机开机后,会自动分配到一个IP地址,不用人为设定。它使用的协议叫做DHCP协议。
这个协议规定,每一个子网络中,有一台计算机负责管理本网络的所有IP地址,它叫做"DHCP服务器"。新的计算机加入网络,必须向"DHCP服务器"发送一个"DHCP请求"数据包,申请IP地址和相关的网络参数。
前面说过,如果两台计算机在同一个子网络,必须知道对方的MAC地址和IP地址,才能发送数据包。但是,新加入的计算机不知道这两个地址,怎么发送数据包呢?
首先,它是一种应用层协议,建立在UDP协议之上,所以整个数据包是这样的:
(1)最前面的"以太网标头",设置发出方(本机)的MAC地址和接收方(DHCP服务器)的MAC地址。前者就是本机网卡的MAC地址,后者这时不知道,就填入一个广播地址:FF-FF-FF-FF-FF-FF。
(2)后面的"IP标头",设置发出方的IP地址和接收方的IP地址。这时,对于这两者,本机都不知道。于是,发出方的IP地址就设为0.0.0.0,接收方的IP地址设为255.255.255.255。
(3)最后的"UDP标头",设置发出方的端口和接收方的端口。这一部分是DHCP协议规定好的,发出方是68端口,接收方是67端口。
这个数据包构造完成后,就可以发出了。以太网是广播发送,同一个子网络的每台计算机都收到了这个包。因为接收方的MAC地址是FF-FF-FF-FF-FF-FF,看不出是发给谁的,所以每台收到这个包的计算机,还必须分析这个包的IP地址,才能确定是不是发给自己的。当看到发出方IP地址是0.0.0.0,接收方是255.255.255.255,于是DHCP服务器知道"这个包是发给我的",而其他计算机就可以丢弃这个包。
接下来,DHCP服务器读出这个包的数据内容,分配好IP地址,发送回去一个"DHCP响应"数据包。这个响应包的结构也是类似的,以太网标头的MAC地址是双方的网卡地址,IP标头的IP地址是DHCP服务器的IP地址(发出方)和255.255.255.255(接收方),UDP标头的端口是67(发出方)和68(接收方),分配给请求端的IP地址和本网络的具体参数则包含在Data部分。
新加入的计算机收到这个响应包,于是就知道了自己的IP地址、子网掩码、网关地址、DNS服务器等等参数。
java.net包中的主要的类和可能产生的异常包括:
面向IP层的类:InetAddress
面向应用层的类:URL、URLConnection
面向网络层的类:
TCP协议相关类:Socket、ServerSocket
UDP协议相关类:DatagramPacket、DatagramSocket、MulticastSocket
可能产生的异常:
BindException、ConnectException、MalformedURLException、NoRouteToHostException、ProtocolException、SocketException、UnknownHostException、UnknownServiceException
使用InetAddress:
类InetAddress可以用于标识网络上的硬件资源,它提供了一系列方法以描述、获取及使用网络资源。
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类的几个主要方法:
public byte[] getAddress():获得本对象的IP地址(存放在字节数组中)。
public String getHostAddress():获得本对象的IP地址“%d.%d.%d.%d”。
public String getHostName():获得本对象的机器名。
下面的例子演示Java如何根据域名自动到DNS(域名服务)上查找IP地址(与DNS服务器的连接减至一行):
public class getIP
{
public static void main(String args[])
{
InetAddress address= null;
try{
address= InetAddress.getByName(“www.ztenc.com.cn”);
}catch(UnknownHostException e) {}
System.out.println(address);
}
}
通过InetAddress,可以获取本机的IP地址:
public class getLocalHostTest
{
public static void main()
{
InetAddress myIP = null;
try
{
myIP = InetAddress.getLocalHost();
}
catch(UnknownHostException e){}
System.out.println(myIP);
}
}
使用URL:
URL是统一资源定位符(Uniform Resource Locator)的简称,它表示Internet上某一资源的地址。Internet上的资源包括HTML文件、图象文件、声音文件、动画文件以及其他任何内容(并不完全是文件,也可以是一个对数据库的查询等)。
通过URL,就可以访问Internet。浏览器或其他程序通过解析给定的URL就可以在网络上查找相应的文件或其他资源。
一个URL包括两部分内容:协议名称和资源名称,中间用冒号隔开:
Protocol:resourceName 如:http://www.ztenc.com.cn
协议名称指的是获取资源时所使用的应用层协议,如http,ftp,file等,资源名称则是资源的完整地址,包括主机名、端口号、文件名或文件内部的一个应用。当然,并不是所有的URL都必须包含这些内容。
在java.net包中,提供了类URL来表示URL。类URL提供了很多构造方法来生成一个URL对象:
public URL(String spec)
public URL(URL context, String spec)
public URL(String protocol, String host, String file)
public URL(String protocol, String host, int port, String file)
以下是一些具体的构造实例:
URL url1 = new URL(“http:// www.ztenc.com.cn /map/index.html”);
URL base = new URL(“http:// www.ztenc.com.cn”);
URL url2 = new URL(base, “mywork1.html”);
URL url3 = new URL(base, “mywork2.html”);
URL url4 = new URL(“http”, “gis.pku.edu.cn”,“/~lyw/test.html”);
URL url5 = new URL(“http”, “www.abc.com”, 8080, “/java/network.html”);
另外还有两种稍微复杂些的构造方法。
一个URL对象生成后,其属性是不能被改变的,但可以通过它给定的方法来获取这些属性:
public String getProtocol():获取该URL的协议名
public String getHost() :获取该URL的主机名
public String getPort() :获取该URL的端口号
public String getPath() :获取该URL的文件路径
public String getFile() :获取该URL的文件名
public String getRef() :获取该URL在文件中的相对位置
public String getQuery() :获取该URL的查询名
Applet中的网络通信需要将URL和InetAddress联合使用来得到相关的IP地址。
URL url = getCodeBase();
String host = url.getHost();
Try{
InetAddress address = InetAddress.getByName(host);
}catch(Exception e){}
Try{
DatagramSocket socket = new DatagramSocket();
DatagramPacket packet = new DatagramPacket(buf, length, address, port);
socket.send(packet);
}catch(Exception e){}
通过URL类提供的方法openStream(),就可以读取一个URL对象所指定的资源。
public final InputStream openStream()
方法openStream()与指定的URL建立连接并返回一个InputStream对象,将URL位置的资源转成一个数据流。通过这个InputStream对象,就可以读取资源中的数据。
通过URL读取www信息
import java.net.*;
import java.io.*;
public class URLReader
{
public static void main (String args[])
{
try{
URL gis = new URL("http://www.ztenc.com.cn/test.htm");
BufferedReader in = new BufferedReader(
new InputStreamReader( gis.openStream() ) );
String line;
while( (line = in.readLine()) != null )
{
System.out.println(line);
}
in.close();
}catch(Exception e){
System.out.println(e);
}
}
}
URL链接:
通过URL类提供的方法openConnection(),就可以获得一个URL连接(URLConnection)对象。
public URLConnection openConnection()
通过URL的方法openStream(),只能从网络上读取资源中的数据。通过URLConnection类,可以在应用程序和URL资源之间进行交互,既可以从URL中读取数据,也可以向URL中发送数据。URLConnection类表示了应用程序和URL资源之间的通信连接。
try{
URL url = new URL(“http://gis.pku.edu.cn”);
URLConnection uc = url.openConnection();
}catch(MalformedURLException e1){
…
}catch(IOException e2){
…
}
public class URLConnectionReader
{
public static void main (String args[])
{
try{
URL gis = new URL("http://gis.pku.edu.cn/test.htm");
URLConnection uc = gis.openConnection();
BufferedReader in = new BufferedReader(
new InputStreamReader( uc.getInputStream() ) );
String line;
while( (line = in.readLine()) != null )
{
System.out.println(line);
}
in.close();
}catch(Exception e){
System.out.println(e);
}
}
}
URL中最常用的两个方法是:
public InputStream getInputStream()
public OutputStream getOutputStream()
通过getInputStream() 方法,应用程序就可以读取资源中的数据。
事实上,类URL的方法openStream()就是通过URLConnection类来实现的,它等价于:
openConnection().getInputStream();
Socket通信:
在Java中,基于TCP协议实现网络通信的类有两个:在客户端的Socket类和在服务器端的ServerSocket类。
1.客户端socket
1. 在客户端通过规定一个主机和端口号创建一个 socket实例,连到服务器上。
2.服务器端ServerSocket
1. 在服务器端通过指定一个用来等待的连接的端口号创建一个 ServerSocket实例。 2. ServerSocket类的accept方法使服务器处于阻塞状态,等待用户请求2.
类Socket
构造方法:
public Socket(String host, int port)
public Socket(InetAddress address, int port)
public Socket(String host, int port, InetAddress localAddr, int localPort)
public Socket(InetAddress address, int port, InetAddress localAddr,
int localPort)
这些方法都将抛出例外IOException,程序中需要捕获处理
Socket的输入/输出流管理
public InputStream getInputStream()
public void shutdownInput()
public OutputStream getOutputStream()
public void shutdownOutput()
这些方法都将抛出例外IOException,程序中需要捕获处理。
关闭Socket
public void close() throws IOException
设置/获取Socket数据
public InetAddress getInetAddress()、public int getPort(),…
public void setSoTimeout(int timeout),…
这些方法都将抛出例外SocketException,程序中需要捕获处理。
类ServerSocket
构造方法:
public ServerSocket(int port)
public ServerSocket(int port, int backlog):支持指定数目的连接
public ServerSocket(int port, int backlog, InetAddress bindAddr)
这些方法都将抛出例外IOException,程序中需要捕获处理。
主要方法
public Socket accept():等待客户端的连接
public void close():关闭Socket
设置/获取Socket数据
public InetAddress getInetAddress()、public int getLocalPort(),…
public void setSoTimeout(int timeout),…
这些方法都将抛出例外SocketException,程序中需要捕获处理。
无论一个Socket通信程序的功能多么齐全、程序多么复杂,其基本结构都是一样的,都包括以下四个基本步骤:
1、在客户方和服务器方创建Socket/Servet。
2、打开连接到Socket的输入/输出流。
3、利用输入/输出流,按照一定的协议对Socket进行读/写操作。
4、关闭输入/输出流和Socket。
通常,程序员的主要工作是针对所要完成的功能在第3步进行编程,第1、2、4步对所有的通信程序来说几乎都是一样的。