【网络模型】
OSI 应用层、表示层、会话层、传输层、网络层、数据链路层、物理层
TCP/IP --------应用层--------、传输层、网际层、----主机至网络层--
【网络通讯要素】
IP地址
端口号
传输协议
【网络分层】
1.物理层
主要定义物理设备标准,如网线的接口类型,光纤的接口类型、各种传输介质的
传输速率等。它的主要作是传输比特流(就是由1、0转化为电流强弱来进行传输
到达目的地后再转化为1、0,也就是我们常说的数模转换与模数转换)。这一层的数据叫做比特
2.数据链路层
主要从物理层接收的数据进行MAC(网卡的地址)的封装与解封装。常把这一层的数据叫做
帧。在这一层工作的设备是交换机,数据通过交换机来传输。
3.网络层
主要将从下层接收到的数据进行IP地址(例如:192.168.0.1)的封装与解封装。在这一层的
工作设备是路由器,常把这一层叫做数据包。
4.传输层
定义了一些传输数据的协议和端口号(WWW端口80等),如:TCP(传输控制协议,传输效率低
,可靠性强用于传输可靠性要求高,数据量大的数据),UDP(用户数据包协议,与TCP特性恰恰相反
,用于传输可靠性要求不高,数据量小的数据,如QQ聊天数据就是通过这种方式传输的)。主要
是将从下层接收的数据进行分段和传输,到达目的地址后再进行重组。常常把这一层数据叫做段。
5.会话层
通过传输层(端口号:传输端口与接收端口)建立数据传输的同路。主要在你的系统之间发起会话或者接收
会话请求(设备之间需要互相认识可以是IP也可以是MAC或者主机名)
6.表示层
主要是进行对接收的数据进行解释、加密与解密、压缩与解压缩等(也就是把计算机能识别的东西转成人可以识别的
的东西如:图片、声音)
7.应用层
主要是一些终端应用,比如说FTP(各种文件下载)、WEB(IE浏览),QQ之类的。(可以理解为我们再电脑屏幕上可以看到的东西,就是终端应用)
【网络通讯要素】
1.IP地址:InetAddress
网络中设备的标识
不易记忆,可用主机名
本地回环地址:127.0.0.1主机名:localhost
IP地址
由四段数字,每段数字一个字节组成,范围是(0~255)。
因为由四段数字组成的排列组合是有限的,当年国际标准化组织通过子网掩码将把IP地址分成了A类B类C类,每一类都有自己的用途,我们一般用的是C类地址段,而全球的计算机又那么多,所以就不可能每台计算机
分配一个IP,这个时候就形成了很多局域网,通过一个代理服务器分配一个公共的IP地址。
现在地址不够了,就推出了IPV4版本,后面又有IPV6版本,这些版本融入了字母
端口号
用于标识进程的逻辑地址,不同进程的标识
有效端口:0-65335,其中0-1027系统使用或保留端口,我们尽量不要使用。
传输协议
通讯的规则
常见协议:UDP、TCP
UDP:
将数据及源和目的封装层数据包中,不需要建立连接
每个数据包的大小限制在64k内
因无连接,是不可靠协议
不需要建立连接,速度快
TCP:
建立连接,形成传输数据的通道
在连接中进行大数据量传输
通过三次握手完成连接,是可靠协议
必须建立连接,效率会稍低
【InetAddress】
因为IP地址相对来说内容比较复杂,而且它又有自己的主机名相对应,
所以IP地址在JAVA中也被封装成了对象InetAddress。
//获取本地主机IP地址对象
InetAddress ip=InetAddress.getLocalHost();
//获取其他主机的IP地址对象,可以通过主机名和IP获取
ip=InetAddress.getByName("192.160.1.102");
//ip=InetAddress.getByName("主机名");
System.out.println(ip.getHostAddress());//获取主机地址
System.out.println(ip.getHostName());//获取主机名
【域名解析】
我们在去访问一台主机的时候,比如说通过浏览器访问新浪网页,我们需要去访问它的主机(10.1.1.1),
那么按道理我们应该在浏览器里面输入它的IP地址来进行访问,凡是访问其他主机走的必须是IP,但是由于
互联网上面的主机非常多,主机也非常多,我们不可能记住所有的IP。所以国际组织就想到了一个方法,我们给
主机起名字,记名字就好办多了,如:http://www.sina.com.cn(www是主机名,sina代表域名,com代表商业化组织,以营利为主,org是营利的),这样的域名。
但是当我们在浏览器里面输入这个一串之后,并不是直接访问新浪的主机,在互联网上有很多台公共的服务器,他们里边就存放着主机和IP的对应关系,
输入网址后访问的就是这台主机,这台主机的名字就叫做(DNS),然后通过DNS找到和主机名对应IP供我们访问。
那我们上网为什么都没有去访问过DNS,也没有指定过DNS呢?
这是因为宽带运营商已经为我们指定了。
本地解析:
我们可以在自己本机配置域名解析,在C:\Windows\System32\drivers\etc\hosts这个文件中配置
其实域名解析一开始并不是直接访问互联网,而是先走的本机解析,本地解析不了才走互联网。
【Socket】
就是为网络服务提供的一种机制。
通信的两端都有Socket
网络通信其实就是Socket间的通信
数据在两个Soket间通过IO传输
可以理解为对讲机,可以发送也可以接收
【UDP传输】
DatagramSocket与DatagramPacket(数据包)
建立发送端,接收端。
建立数据包
调用Socket的发送接收方法
关闭Socket。
发送与接收端是两个独立的运行程序
【发送】
public class UDPSendDemo {
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
System.out.println("发送端启动......");
/*
* 创建UDP传输的发送端。
* 思路:
* 1,建立udp的socket服务。
* 2,将要发送的数据封装到数据包中。
* 3,通过udp的socket服务将数据包发送出去。
* 4,关闭socket服务。
*/
//1,udpsocket服务。使用DatagramSocket对象。
DatagramSocket ds = new DatagramSocket(8888);
//2,将要发送的数据封装到数据包中。
String str = "udp传输演示:哥们来了!";
//使用DatagramPacket将数据封装到的该对象包中。
byte[] buf = str.getBytes();
DatagramPacket dp =
new DatagramPacket(buf,buf.length,InetAddress.getByName("192.168.1.100"),10000);
//3,通过udp的socket服务将数据包发送出去。使用send方法。
ds.send(dp);
//4,关闭资源。
ds.close();
}
}
改成在控制台输入
public class UDPSendDemo2 {
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
System.out.println("发送端启动......");
/*
* 创建UDP传输的发送端。
* 思路:
* 1,建立udp的socket服务。
* 2,将要发送的数据封装到数据包中。
* 3,通过udp的socket服务将数据包发送出去。
* 4,关闭socket服务。
*/
//1,udpsocket服务。使用DatagramSocket对象。
DatagramSocket ds = new DatagramSocket(8888);
// String str = "udp传输演示:哥们来了!";
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
String line = null;
while((line=bufr.readLine())!=null){
byte[] buf = line.getBytes();
DatagramPacket dp =
new DatagramPacket(buf,buf.length,InetAddress.getByName("192.168.1.100"),10000);
ds.send(dp);
if("886".equals(line))
break;
}
//4,关闭资源。
ds.close();
}
}
【接收】
public class UDPReceDemo {
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
System.out.println("接收端启动......");
/*
* 建立UDP接收端的思路。
* 1,建立udp socket服务,因为是要接收数据,必须要明确一个端口号。
* 2,创建数据包,用于存储接收到的数据。方便用数据包对象的方法解析这些数据.
* 3,使用socket服务的receive方法将接收的数据存储到数据包中。
* 4,通过数据包的方法解析数据包中的数据。
* 5,关闭资源
*/
//1,建立udp socket服务。
DatagramSocket ds = new DatagramSocket(10000);
//2,创建数据包。
byte[] buf = new byte[1024];
DatagramPacket dp = new DatagramPacket(buf,buf.length);
//3,使用接收方法将数据存储到数据包中。
ds.receive(dp);//阻塞式的。
//4,通过数据包对象的方法,解析其中的数据,比如,地址,端口,数据内容。
String ip = dp.getAddress().getHostAddress();
int port = dp.getPort();
String text = new String(dp.getData(),0,dp.getLength());
System.out.println(ip+":"+port+":"+text);
//5,关闭资源。
ds.close();
}
}
改成不关闭
public class UDPReceDemo2 {
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
System.out.println("接收端启动......");
/*
* 建立UDP接收端的思路。
* 1,建立udp socket服务,因为是要接收数据,必须要明确一个端口号。
* 2,创建数据包,用于存储接收到的数据。方便用数据包对象的方法解析这些数据.
* 3,使用socket服务的receive方法将接收的数据存储到数据包中。
* 4,通过数据包的方法解析数据包中的数据。
* 5,关闭资源
*/
//1,建立udp socket服务。
DatagramSocket ds = new DatagramSocket(10000);
while(true){
//2,创建数据包。
byte[] buf = new byte[1024];
DatagramPacket dp = new DatagramPacket(buf,buf.length);
//3,使用接收方法将数据存储到数据包中。
ds.receive(dp);//阻塞式的。
//4,通过数据包对象的方法,解析其中的数据,比如,地址,端口,数据内容。
String ip = dp.getAddress().getHostAddress();
int port = dp.getPort();
String text = new String(dp.getData(),0,dp.getLength());
System.out.println(ip+":"+port+":"+text);
}
//5,关闭资源。
// ds.close();
}
}
【聊天室】
发送线程任务:
public class Send implements Runnable {
private DatagramSocket ds;
public Send(DatagramSocket ds){
this.ds = ds;
}
@Override
public void run() {
try {
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
String line = null;
while((line=bufr.readLine())!=null){
byte[] buf = line.getBytes();
//DatagramPacket dp = new DatagramPacket(buf,buf.length,InetAddress.getByName("192.168.1.100"),10001);
//在我们的IP地址段,我们如果走的是c类地址的话,如:192.168.1.100 子网掩码是255.255.255.0
//那么192.168.1都是网络位,100是IP地址位(1~254),255是广播地址位。
DatagramPacket dp = new DatagramPacket(buf,buf.length,InetAddress.getByName("192.168.1.255"),10001);
ds.send(dp);
if("886".equals(line))
break;
}
ds.close();
} catch (Exception e) {
}
}
}
接收线程任务:
public class Rece implements Runnable {
private DatagramSocket ds;
public Rece(DatagramSocket ds) {
this.ds = ds;
}
@Override
public void run() {
try {
while (true) {
// 2,创建数据包。
byte[] buf = new byte[1024];
DatagramPacket dp = new DatagramPacket(buf, buf.length);
// 3,使用接收方法将数据存储到数据包中。
ds.receive(dp);// 阻塞式的。
// 4,通过数据包对象的方法,解析其中的数据,比如,地址,端口,数据内容。
String ip = dp.getAddress().getHostAddress();
int port = dp.getPort();
String text = new String(dp.getData(), 0, dp.getLength());
System.out.println(ip + "::" + text);
if(text.equals("886")){
System.out.println(ip+"....退出聊天室");
}
}
} catch (Exception e) {
}
}
}
测试:
public class ChatDemo {
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
DatagramSocket send = new DatagramSocket();
DatagramSocket rece = new DatagramSocket(10001);
new Thread(new Send(send)).start();
new Thread(new Rece(rece)).start();
}
}
【TCP连接】
客户端:
public class ClientDemo {
/**
* @param args
* @throws IOException
* @throws UnknownHostException
*/
public static void main(String[] args) throws UnknownHostException, IOException {
//客户端发数据到服务端
/*
* Tcp传输,客户端建立的过程。
* 1,创建tcp客户端socket服务。使用的是Socket对象。
* 建议该对象一创建就明确目的地。要连接的主机。
* 2,如果连接建立成功,说明数据传输通道已建立。
* 该通道就是socket流 ,是底层建立好的。 既然是流,说明这里既有输入,又有输出。
* 想要输入或者输出流对象,可以找Socket来获取。
* 可以通过getOutputStream(),和getInputStream()来获取两个字节流。
* 3,使用输出流,将数据写出。
* 4,关闭资源。
*/
//创建客户端socket服务。
Socket socket = new Socket("192.168.1.100",10002);
//获取socket流中的输出流。
OutputStream out = socket.getOutputStream();
//使用输出流将指定的数据写出去。
out.write("tcp演示:哥们又来了!".getBytes());
//关闭资源。
socket.close();
}
}
服务端:
public class ServerDemo {
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
// 服务端接收客户端发送过来的数据,并打印在控制台上。
/*
* 建立tcp服务端的思路:
* 1,创建服务端socket服务。通过ServerSocket对象。
* 2,服务端必须对外提供一个端口,否则客户端无法连接。
* 3,获取连接过来的客户端对象。
* 4,通过客户端对象获取socket流读取客户端发来的数据
* 并打印在控制台上。
* 5,关闭资源。关客户端,关服务端。
*/
//1创建服务端对象。
ServerSocket ss = new ServerSocket(10002);
//2,获取连接过来的客户端对象。
Socket s = ss.accept();//阻塞式.
String ip = s.getInetAddress().getHostAddress();
//3,通过socket对象获取输入流,要读取客户端发来的数据
InputStream in = s.getInputStream();
byte[] buf = new byte[1024];
int len = in.read(buf);
String text = new String(buf,0,len);
System.out.println(ip+":"+text);
s.close();
ss.close();
}
}
客户端和服务端交互:
public class ClientDemo2 {
/**
* @param args
* @throws IOException
* @throws UnknownHostException
*/
public static void main(String[] args) throws UnknownHostException, IOException {
//客户端发数据到服务端
/*
* Tcp传输,客户端建立的过程。
* 1,创建tcp客户端socket服务。使用的是Socket对象。
* 建议该对象一创建就明确目的地。要连接的主机。
* 2,如果连接建立成功,说明数据传输通道已建立。
* 该通道就是socket流 ,是底层建立好的。 既然是流,说明这里既有输入,又有输出。
* 想要输入或者输出流对象,可以找Socket来获取。
* 可以通过getOutputStream(),和getInputStream()来获取两个字节流。
* 3,使用输出流,将数据写出。
* 4,关闭资源。
*/
Socket socket = new Socket("192.168.1.100",10002);
OutputStream out = socket.getOutputStream();
out.write("tcp演示:哥们又来了!".getBytes());
//读取服务端返回的数据,使用socket读取流。
InputStream in = socket.getInputStream();
byte[] buf = new byte[1024];
int len = in.read(buf);
String text = new String(buf,0,len);
System.out.println(text);
//关闭资源。
socket.close();
}
}
public class ServerDemo2 {
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
// 服务端接收客户端发送过来的数据,并打印在控制台上。
/*
* 建立tcp服务端的思路:
* 1,创建服务端socket服务。通过ServerSocket对象。
* 2,服务端必须对外提供一个端口,否则客户端无法连接。
* 3,获取连接过来的客户端对象。
* 4,通过客户端对象获取socket流读取客户端发来的数据
* 并打印在控制台上。
* 5,关闭资源。关客户端,关服务端。
*/
//1创建服务端对象。
ServerSocket ss = new ServerSocket(10002);
//2,获取连接过来的客户端对象。
Socket s = ss.accept();
String ip = s.getInetAddress().getHostAddress();
//3,通过socket对象获取输入流,要读取客户端发来的数据
InputStream in = s.getInputStream();
byte[] buf = new byte[1024];
int len = in.read(buf);
String text = new String(buf,0,len);
System.out.println(ip+":"+text);
//使用客户端socket对象的输出流给客户端返回数据
OutputStream out = s.getOutputStream();
out.write("收到".getBytes());
s.close();
ss.close();
}
}
【常见客户端和服务端】
最常见的客户端
IE
最常见的服务端
Tomcat
能将服务器里面所对外提供的资源放在它的目录下,它可以将这些资源读取并且发给客户端
服务端的开发就是基于Tomcat处理请求以及应答,而要实现处理请求以及应答,就必须要符合
Tomcat的规则来编写代码,照着它的接口做就能实现处理请求以及应答,它对外提供的接口就是interface Servlet
为了了解其原理:
1.
定义服务端,
使用已有的客户端IE,了解一下客户端给服务端发了什么请求?
public class MyTomcat {
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
ServerSocket ss = new ServerSocket(9090);
Socket s = ss.accept();
System.out.println(s.getInetAddress().getHostAddress()+".....connected");
InputStream in = s.getInputStream();
byte[] buf = new byte[1024];
int len = in.read(buf);
String text = new String(buf,0,len);
System.out.println(text);
//给客户端一个反馈信息。
PrintWriter out = new PrintWriter(s.getOutputStream(),true);
out.println("<font color='red' size='7'>欢迎光临</font>");
s.close();
ss.close();
}
}
发送的请求是
GET / HTTP/1.1 请求行 请求方式 /myweb/1.html 请求的资源路径 http协议版本。
请求消息头 . 属性名:属性值
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, /******支持的东西*******/
application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*
Accept: */*
Accept-Language: zh-cn,zu;q=0.5/******客户端支持的语言*******/
Accept-Encoding: gzip, deflate /******客户端支持的压缩方式*******/
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; InfoPath.2)
Host: 192.168.1.100:9090
//Host: www.huyouni.com:9090
Connection: Keep-Alive 连接是否保存
//空行
//请求体。
【http】
超文本传输协议。(它里面涉及的语言是html,为什么我们要用这种协议呢?其实是我们想要在外网进行超文本语言的数据传输)
这个是应用层给我们提供的一种通讯协议,它定义了一种web端,web浏览器和服务端之间的一种通讯规则
为什么要有这个协议呢?
因为web端,web浏览器要想和服务端进行通讯,那么浏览器和服务端就必须遵循相同的规则,才可以。
其实浏览器本身就内置了http的解析程序。称之为解析引擎。
我们用的UDP和TCP并没有直接去操作协议,我们都是用的封装这些协议的对象,这些都是底层做的,不是我们做的。
像这种协议有很多比如说FTP,操作文件的,用于文件上传下载。
所以当我们在浏览器里面输入网址的时候,浏览器都是按http协议的方式封装好然后再发送到服务器的。
比如:http\\:www.sina.com.cn/index.html
www.sina.com,会通过域名解析器得到IP地址,index.html请求的资源路径。
然后就封装成:
GET /index.html HTTP/1.1 请求行 请求方式 /index.html 请求的资源路径 http协议版本。
请求消息头 . 属性名:属性值
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, /******支持的东西*******/
application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*
Accept: */*
Accept-Language: zh-cn,zu;q=0.5/******支持的语言*******/
Accept-Encoding: gzip, deflate /******支持的压缩方式*******/
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; InfoPath.2)
Host: www.sina.com.cn
Connection: Keep-Alive
//空行
//请求体。
就发送到服务端了,服务端拿到这个数据之后,就进行解析,然后根据发送过来的这些数据做相应的处理。
所以我们的软件向Tomcat请求的时候也需要像浏览器一样封装这些请求头
public class MyBrowser {
/**
* @param args
* @throws IOException
* @throws UnknownHostException
*/
public static void main(String[] args) throws UnknownHostException, IOException {
Socket s = new Socket("192.168.1.100",8080);
//模拟浏览器,给tomcat服务端发送符合http协议的请求消息。
PrintWriter out = new PrintWriter(s.getOutputStream(),true);
out.println("GET /myweb/1.html HTTP/1.1");
out.println("Accept: */*");
out.println("Host: 192.168.1.100:8080");
out.println("Connection: close");
out.println();
out.println();
InputStream in = s.getInputStream();
byte[] buf = new byte[1024];
int len = in.read(buf);
String str =new String(buf,0,len);
System.out.println(str);
s.close();
//http://192.168.1.100:8080/myweb/1.html
}
}
//服务端发回应答消息。
HTTP/1.1 200 OK //应答行,http的协议版本 应答状态码 应答状态描述信息
应答消息属性信息。 属性名:属性值
Server: Apache-Coyote/1.1
ETag: W/"199-1323480176984"
Last-Modified: Sat, 10 Dec 2011 01:22:56 GMT
Content-Type: text/html
Content-Length: 199
Date: Fri, 11 May 2012 07:51:39 GMT
Connection: close
//空行
//应答体。
<html>
<head>
<title>这是我的网页</title>
</head>
<body>
<h1>欢迎光临</h1>
<font size='5' color="red">这是一个tomcat服务器中的资源。是一个html网页。</font>
</body>
</html>