七层网络协议模型
为了数据安全可靠地传递到对方,ISO(国际标准委员会组织)将数据的传递从逻辑上划分为以下七层:
应用层、表示层、会话层、传输层、网络层、数据链路层、物理层。
当发送数据时需要按照上述七层协议一层层进行加包再发送出去。
当接收数据时需要按照上述七层协议相反的次序一层层进行拆分再显示出来。
常用的协议
协议 - 本质上就是一种规则/约定,规定了通信双方统一的语言规则。
http协议 - 超文本传输协议,浏览网页的功能需要使用该协议。
ftp协议 - 文件传输控制,当上传和下载文件时需要使用该协议。
tcp协议 - 传输控制协议,当进行网络通信时需要使用该协议。
udp协议 - 用户数据报协议,当进行网络通信时需要使用该协议。
ip协议 - 互联网协议,是上述协议的底层协议。
IP地址(重点)
192.168.1.1 - 是绝大多数路由器的登录地址。
IP地址就是互联网中的唯一标识,本质上是由32位二进制组成的整数,叫做ipv4,也有128位二进制组成的整数,叫做ipv6,目前主流使用的是ipv4。
日常生活中采用【点分十进制】表示法来进行IP地址的描述,也就是将每个字节的二进制转换为一个十进制整数,不同的十进制整数之间采用.分隔。
如:0x01020304 => 1.2.3.4
查看IP地址的方式:
在windows系统的dos窗口中使用命令 ipconfig 即可查看IP地址。
在linux系统的终端窗口中使用命令 ifconfig 即可查看IP地址。
端口号(重点)
IP地址 - 可以定位到具体某一台设备中。
端口号 - 可以定位到设备中的具体某一个进程。
端口号本质上就是由16位二进制组成的整数,范围是:0 ~ 65535,其中0 ~ 1024之间的端口号通常被系统占用,因此编程时从1025开始使用。
网络编程中需要提供:IP地址 + 端口号。
基于TCP协议的编程模型(重点)
基本概念
C/S架构 - Client(客户端)/Server(服务器).
B/S架构 - Browser(浏览器)/Server(服务器).
Socket - 本意为“插座”,在网络编程中主要指用于通信的载体/通信点。
编程模型
服务器:
(1)创建ServerSocket对象,并提供端口号。
(2)等待客户端的连接请求,使用accept()方法。
(3)得到Socket对象与客户端使用输入输出流进行通信。
(4)关闭Socket并释放有关的资源。
客户端:
(1)创建Socket对象,并提供服务器的IP地址和端口号。
(2)使用输入输出流进行通信。
(3)关闭Socket并释放有关的资源。
相关类和方法的解析
(1)ServerSocket类
java.net.ServerSocket类用于准备服务器端的套接字,也就是插座。
ServerSocket(int port) - 用于创建绑定到参数指定端口的套接字。
Socket accept() - 用于监听并接收到此套接字的连接请求。
void close() - 用于关闭套接字。
(2)Socket类
java.net.Socket类用于实现客户端套接字,是两台设备之间通信的端点。
Socket(String host, int port) - 用于创建套接字并连接到指定主机的指定端口上
InputStream getInputStream() - 用于返回套接字的输入流。
OutputStream getOutputStream() - 用于返回套接字的输出流。
void close() - 用于关闭套接字。
代码实现:
(1)要求实现服务器向客户端发送字符串内容"I received!".
(2)要求实现客户端发送的内容由用户手动输入,使用BufferedReader实现。
(3)要求实现客户端和服务器不断地通信,直到客户端发来"bye"时结束。
(4)要求服务器可以同时和多个客户端通信,采用多线程技术。
服务器:
public class TestServerString {
public static void main(String[] args)
try{
//1.创建ServerSocket类型的对象,并指定端口号
ServerSocket ss = new ServerSocket(8888);
//2.等待客户端的连接请求,调用accept()方法
while(true){
System.out.println("等待客户端的连接请求...");
//监听并等待客户端的连接请求,若没有客户端连接则阻塞在这里
Socket s = ss.accept();
//接收一下客户端的通信地址并记录起来
InetAddress ia = s.getInetAddress();
System.out.println("客户端" + ia + "连接成功!");
new ServerThread(s).start();
}
//ss.close();
}catch(Exception e){
e.printStackTrace();
}
}
}
客户端:
public class TestClientString {
public static void main(String[] args) {
try{
//1.创建Socket类型的对象,并准备服务器的IP地址和端口号
Socket s = new Socket("192.168.102.234", 8888);
//2.使用输入输出流进行通信
BufferedReader bri = new BufferedReader(
new InputStreamReader(System.in));
PrintStream ps = new PrintStream(s.getOutputStream());
BufferedReader br = new BufferedReader(
new InputStreamReader(s.getInputStream()));
while(true){
//提示用户输入要发送的内容并使用变量记录下来
System.out.println("请输入要发送的内容:");
String msg = bri.readLine();
//让客户端给服务器发送消息,发送的内容为"hello"
//使用BufferedReader类和PrintStream类处理字符串
//Thread.sleep(10000);
//ps.println("hello");
ps.println(msg);
System.out.println("成功发送数据到服务器!");
//判断向服务器发送的消息是否为"bye",若是则结束循环
if("bye".equalsIgnoreCase(msg)) break;
//接收服务器发来的消息,并打印出来
String str = br.readLine();
System.out.println("服务器发来的内容是:" + str);
}
//3.关闭Socket并释放有关的资源
bri.close();
br.close();
s.close();
}catch(Exception e){
e.printStackTrace();
}
}
}
多线程
public class ServerThread extends Thread {
private Socket s;
public ServerThread(Socket s){
this.s = s;
}
@Override
public void run(){
try{
//3.得到Socket类型的对象,并使用输入输出流进行通信
BufferedReader br = new BufferedReader(
new InputStreamReader(s.getInputStream()));
PrintStream ps = new PrintStream(s.getOutputStream());
InetAddress ia = s.getInetAddress();
while(true){
//使用BufferedReader类接收客户端发来的消息
String str = br.readLine();
System.out.println("客户端" + ia + "发来的内容是:" + str);
//判断客户端发来的内容是否为"bye",若是则结束通信
if("bye".equalsIgnoreCase(str)){
System.out.println("客户端" + ia + "已下线!");
break;
}
//服务器接收到客户端发来的消息之后,向客户端回发消息
ps.println("I received!");
System.out.println("成功发送数据到客户端!");
}
//4.关闭Socket并使用有关的资源
ps.close();
s.close();
}catch(Exception e){
e.printStackTrace();
}
}
}
基于udp协议的编程模型(重点)
编程模型
主机A(接收方):
(1)创建DatagramSocket类型的对象,并准备端口号。
(2)创建DatagramPacket类型的对象,并准备缓冲区。
(3)接收数据内容,调用receive()方法。
(4)关闭Socket并释放有关的资源。
主机B(发送方)
(1)创建DatagramSocket类型的对象。
(2)创建DatagramPacket类型的对象,并准备数据和收件人信息。
(3)发送数据内容,调用send()方法。
(4)关闭Socket并释放有关的资源。
相关类和方法的解析
(1)DatagramSocket类 Datagram:数据报 Socket:插座
java.net.DatagramSocket类用于描述发送和接收数据报的套接字,相当于码头。
DatagramSocket() - 创建对象并绑定到任何可用的端口号上。
DatagramSocket(int port) - 创建对象并绑定到参数指定的端口上。
void receive(DatagramPacket p) - 用于接收数据报存放到参数指定的对象中。
void send(DatagramPacket p) - 用于将参数指定的对象发送出去。
void close()
(2)DatagramPacket类
java.net.DatagramPacket类用于描述数据报信息的包裹,相当于集装箱。
DatagramPacket(byte[] buf, int length)
- 构造对象,用于接收长度为length的数据到buf数组中保存起来。
DatagramPacket(byte[] buf, int length, InetAddress address, int port)
- 构造对象,用于将长度为length的数据发送到address主机上的port端口。
int getLength() - 用于获取发送/接收的数据长度。
InetAddress getAddress() - 用于获取发送方/接收方的IP地址信息。
int getPort() - 用于获取发送方/接收方的端口号信息。
(3)InetAddress类
java.net.InetAddress类用于描述IP地址等信息。
static InetAddress getLocalHost() - 用于返回本地主机的通信地址。
static InetAddress getByName(String host) - 用于根据参数指定的主机名来获取该主机的通信地址信息。
代码实现
1.发送方
public class TestSend {
public static void main(String[] args) {
try{
//1.构造DatagramSocket类型的对象
DatagramSocket ds = new DatagramSocket();
//2.构造DatagramPacket类型的对象,并指定数据内容和收件人信息
byte[] data = "hello".getBytes();
DatagramPacket dp = new DatagramPacket(data,
data.length, InetAddress.getLocalHost(), 8888);
//3.发送数据出去,调用send()方法
ds.send(dp);
System.out.println("成功发送数据到接收方!");
//接收回发的消息
byte[] data2 = new byte[1024];
DatagramPacket dp2 = new DatagramPacket(data2, data2.length);
ds.receive(dp2);
System.out.println("接收到的数据是:" + new String(data2, 0, dp2.getLength()));
//4.关闭Socket并使用有关的资源
ds.close();
}catch(Exception e){
e.printStackTrace();
}
}
}
2.接收方
public class TestReceive {
public static void main(String[] args) {
try{
//1.创建DatagramSocket类型的对象,并提供端口号
DatagramSocket ds = new DatagramSocket(8888);
//2.创建DatagramPacket类型的对象,用于接收数据内容
byte[] data = new byte[1024];
DatagramPacket dp = new DatagramPacket(data, data.length);
//3.接收数据并存放到数据报中,使用receive()方法
System.out.println("等待数据的到来...");
ds.receive(dp);
System.out.println("接收到的数据内容是:"
+ new String(data, 0, dp.getLength()) + "!");
//当接收方接收到消息之后,向发送方回发消息"I received!"
byte[] data2 = "I received!".getBytes();
//dp.getAddress()方法是用于获取发送方的IP地址信息,getPort()获取端口号
DatagramPacket dp2 = new DatagramPacket(data2,
data2.length, dp.getAddress(), dp.getPort());
ds.send(dp2);
//4.关闭套接字(关闭Socket并释放有关的资源)
ds.close();
}catch(Exception e){
e.printStackTrace();
}
}
}
tcp协议和udp协议的比较(笔试题)
tcp协议 - 传输控制协议,是一种面向连接的协议,类似于打电话。
- 建立连接 => 进行通信 => 断开连接
- 在通信的整个过程中全程保持连接。
- 保证了数据传输的可靠性和有序性。
- 是一种全双工的字节流通信方式。
- 服务器压力比较大,资源消耗比较多,发送数据的效率相对比较低。1
udp协议 - 用户数据报协议,是一种非面向连接的协议,类似于写信。
- 在通信的整个过程中不保持全程连接。
- 不保证数据传输的可靠性和有序性。
- 是一种全双工的数据报通信方式。
- 服务器压力比较小,资源消耗比较少,发送数据的效率相对比较高。