http协议
HTTP协议的版本
HTTP/1.0、HTTP/1.1
区别:
1.0:每次响应后即刻关闭了连接。客户端与web服务器建立连接后,只能获得一个web资源。
1.1:不是每次响应后挂断,等待长时间以后没有请求会挂断。允许客户端与web服务器建立连接后,在一个连接上获取多个web资源。
请求部分
请求行
提交方式
提交方式有很多,常用的GET和POST;
GET和POST的区别:
GET的提交的参数会显示到地址栏上,而POST不显示.
GET往往是有大小限制的,而POST没有大小的限制.
GET没有请求体,而POST有请求体.
提交路径
协议版本
请求头
都是键值对的形式显示的.一般一个key对应一个value,也有个别的是一个key对应多个value。
HTTP请求中的常用消息头:
User-Agent:代表浏览器的类型。 --文件下载:下载中文文件,IE使用URLEncodor进行编码,而Firefox使用Base64编码。
accept:浏览器通过这个头告诉服务器,它所支持的数据类型
Accept-Charset: 浏览器通过这个头告诉服务器,它支持哪种字符集
Accept-Encoding:浏览器通过这个头告诉服务器,支持的压缩格式
Accept-Language:浏览器通过这个头告诉服务器,它的语言环境
Host:浏览器通过这个头告诉服务器,想访问哪台主机
If-Modified-Since:
浏览器通过这个头告诉服务器,缓存数据的时间
Referer:浏览器通过这个头告诉服务器,客户机是哪个页面来的 防盗链
Connection:浏览器通过这个头告诉服务器,请求完后是断开链接还是何持链接存
请求体
就是POST提交方式的提交的参数
响应部分
响应行
协议版本
状态码:
200 成功
302 重定向
304 查找本地缓存
404 资源不存在
500 服务器内部错误
状态码描述
响应头:键值对,一般一个key对应一个value,也有一个key对应多个value。
HTTP响应中的常用响应头(消息头)
Location:服务器通过这个头,来告诉浏览器跳到哪里
Server:服务器通过这个头,告诉浏览器服务器的型号
Content-Encoding:服务器通过这个头,告诉浏览器,数据的压缩格式
Content-Length: 服务器通过这个头,告诉浏览器回送数据的长度
Content-Language: 服务器通过这个头,告诉浏览器语言环境
Content-Type:服务器通过这个头,告诉浏览器回送数据的类型
Refresh:服务器通过这个头,告诉浏览器定时刷新
Content-Disposition:
服务器通过这个头,告诉浏览器以下载方式打数据
Transfer-Encoding:服务器通过这个头,告诉浏览器数据是以分块方式回送的
Expires: -1 控制浏览器不要缓存
Cache-Control: no-cache
Pragma: no-cache
响应体:显示浏览器的页面的内容。
在服务端设置响应头来控制客户端浏览器的行为
设置Location响应头,实现请求重定向
response.setStatus(302);//设置服务器的响应状态码
response.setHeader("Location", "/demo5-refresh/success.html ");
设置content-type响应头,指定回送数据类型
String type = this.getServletContext().getMimeType(filename);
response.setHeader("Content-Type", type);
设置refresh响应头,让浏览器定时刷新
response.setHeader("refresh", "3;url='http://www.baidu.com'");
设置content-disposition响应头,让浏览器下载文件
response.setHeader("content-disposition", "attachment;filename=xxx.jpg");
网络编程
InetAdderss类,该类用于封装一个IP地址,并提供了一系列与IP地址相关的方法。
UDP 用户数据报协议
DatagramPacket类,该类的实例对象就相当于一个集装箱,用于封装UDP通信中发送或者接收的数据。
接收端的构造方法只需要接收一个字节数组来存放接收到的数据,而发送端的构造方法不但要接收存放了发送数据的字节数组,还需要指定发送端IP地址和端口号。
DatagramPacket(byte[] buf, int length) 构造 DatagramPacket,用来接收长度为 length 的数据包。
DatagramPacket(byte[] buf, int length, InetAddress address, int port) 构造数据报包,用来将长度为 length 的包发送到指定主机上的指定端口号。
DatagramSocket类的作用就类似于码头,使用这个类的实例对象就可以发送和接收DatagramPacket数据包。
在创建发送端和接收端的DatagramSocket对象时,使用的构造方法也有所不同。
DatagramSocket() 构造数据报套接字并将其绑定到本地主机上任何可用的端口。
DatagramSocket(int port) 创建数据报套接字并将其绑定到本地主机上的指定端口。
package com.boomoom; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.SocketException; /* * 使用UDP协议发送数据 */ public class SendDemo { public static void main(String[] args) throws IOException { //创建发送端Socket对象 DatagramSocket ds = new DatagramSocket(); //创建数据并打包 String s = "hello body, im a coder!"; byte[] bys = s.getBytes(); int length = bys.length; InetAddress address = InetAddress.getByName("boomoom");//发送给当前设备 int port = 8888; DatagramPacket dp = new DatagramPacket(bys,length,address,port); ds.send(dp); ds.close(); } } package com.boomoom; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; /* * 使用UDP协议接收数据 */ public class ReceiveDemo { public static void main(String[] args) throws IOException { //创建接收端Socket对象 DatagramSocket ds = new DatagramSocket(8888); //接收数据 //DatagramPacket(byte[] buf, int length) byte[] bys = new byte[1024]; DatagramPacket dp = new DatagramPacket(bys,bys.length); System.out.println(1); ds.receive(dp);//阻塞 System.out.println(2); //解析数据 InetAddress address = dp.getAddress(); // 获取发送端的IP对象 int length = dp.getLength(); System.out.println("sender ---> " + address.getHostAddress()); System.out.println(new String(bys,0,length)); ds.close(); } }
TCP 传输控制协议
UDP 中只有发送端和接收端,不区分客户端与服务器端,计算机之间可以任意地发送数据。而 TCP 通信是严格区分客户端与服务器端的,在通信时,必须先由客户端去连接服务器端才能实现通信,服务器端不可以主动连接客户端,并且服务器端程序需要事先启动,等待客户端的连接。在 JDK 中提供了两个类用于实现 TCP 程序,一个是 ServerSocket 类,用于表示服务器端,一个是 Socket 类,用于表示客户端。
ServerSocket类,的实例对象可以实现一个服务器端的程序。
Socket类,用于实现TCP客户端程序。
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.Socket; public class ClientTest { public static void main(String[] args) throws IOException { //创建客户端Socket对象 Socket s = new Socket("janden-pc",8888); //获取用户名和密码 BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); System.out.println("请输入用户名:"); String username = br.readLine(); System.out.println("请输入密码:"); String password = br.readLine(); //获取输出流对象 PrintWriter out = new PrintWriter(s.getOutputStream(),true); //写出数据 out.println(username); out.println(password); //获取输入流对象 BufferedReader serverBr = new BufferedReader(new InputStreamReader(s.getInputStream())); //获取服务器返回的数据 String result = serverBr.readLine(); System.out.println(result); //释放资源 s.close(); } } import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; import java.util.List; public class ServerTest { public static void main(String[] args) throws IOException { //创建服务器端Socket对象 ServerSocket ss = new ServerSocket(8888); //监听 Socket s = ss.accept(); //获取输入流对象 BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream())); String username = br.readLine(); String password = br.readLine(); boolean flag = false; List<User> users = UserDB.getUsers(); User user = new User(username,password); if(users.contains(user)) { flag = true; } //获取输出流对象 PrintWriter out = new PrintWriter(s.getOutputStream(),true); //返回判断信息 if(flag) { out.println("登陆成功"); } else { out.println("登陆失败"); } //释放资源 s.close(); //ss.close();//服务器一般不关闭 } } import java.util.ArrayList; import java.util.List; public class UserDB { private static List<User> users = new ArrayList<User>(); static { users.add(new User("张三","123")); users.add(new User("赵四","1234")); users.add(new User("阿Q","12345")); users.add(new User("尼古拉斯","123456")); } public static List<User> getUsers() { return users; } } import java.util.Objects; public class User { private String username; private String password; public User() { super(); } public User(String username, String password) { this.username = username; this.password = password; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; User user = (User) o; return Objects.equals(username, user.username) && Objects.equals(password, user.password); } }
在应用层写入的数据经由表示层格式化编码,再由会话层标记发送顺序后才被发送出去。
会话层只对何时建立连接、何时发送数据等问题进行管理。
传输层建立连接或断开连接,创建逻辑上的通信连接。为保证数据传输的可靠性,它会在通信两端之间进行确认,并负责重发。
网络层将数据传输给对端。
数据链路层的作用是还在传输介质互联的设备间进行数据处理。
物理层将数据转为电压或脉冲光传输给物理的传输介质。
发一封邮件为例
应用层的首部 标明收件人邮件主题内容。
表示层的首部 编码格式识别信息。
会话层的首部 记录数据传送顺序。
传输层的首部 用以识别传输层。
网络层的首部 两端IP地址、协议等。
数据链路层的首部 帧定界符合长度上限。
物理层的首部 含有MAC地址。