OSI : 为了促进计算机网络的发展,国际标准化组织ISO于1977年成立了一个委员会,在现有网络的基础上,提出了不基于具体机型、操作系统或公司的网络体系结构,称为开放系统互连参考模型,即OSI/RM (Open System Interconnection Reference Model)。OSI模型把网络通信的工作分为7层,分别是物理层、数据链路层、网络层、传输层、会话层、表示层和应用层。
TCP/IP,即Transmission Control Protocol/Internet Protocol的简写,中译名为传输控制协议/因特网互联协议,是Internet最基本的协议、Internet国际互联网络的基础。TCP/IP参考模型采用4层的层级结构,每一层都呼叫它的下一层所提供的协议来完成自己的需求,这4个层次分别是:网络接口层、互联网层(IP层)、传输层(TCP层)、应用层。
IP地址(Internet Protocol):唯一标识网络上的每一台计算机
IP地址的组成:32位,由4个8位二进制数组成
IP地址 = 网络地址(标识计算机或网络设备所在的网段) +主机地址(标识特定主机或网络设备)
下面这张图可以看出TCP/IP协议簇中不同的层次中有着很多不同的网络协议,下面主要介绍传输层的TCP、UDP协议和应用层的HTTP协议。
TCP(Transmission Control Protocol ,传输控制协议)是面向连接的传输层协议。TCP层是位于IP层之上,应用层之下的中间层。不同主机的应用层之间经常需要可靠的、像管道一样的连接,但是IP层不提供这样的流机制,而是提供不可靠的包交换。TCP协议采用字节流传输数据。
TCP报文段包括协议首部和数据两部分,协议首部的固定部分有20个字节,首部的固定部分后面是选项部分。
下面是报文段首部各个字段的含义:
源端口号以及目的端口号,各占2个字节,端口是传输层和应用层的服务接口,用于寻找发送端和接收端的进程,一般来讲,通过端口号和IP地址,可以唯一确定一个TCP连接,在网络编程中,通常被称为一个socket接口。
序号,占4字节,用来标识从TCP发送端向TCP接收端发送的数据字节流。
确认序号,占4字节,包含发送确认的一端所期望收到的下一个序号,因此,确认序号应该是上次已经成功收到数据字节序号加1.
数据偏移,占4位,用于指出TCP首部长度,若不存在选项,则这个值为20字节,数据偏移的最大值为60字节。
保留字段占6位,暂时可忽略,值全为0。
标志位
URG(紧急) : 为1时表明紧急指针字段有效
ACK(确认):为1时表明确认号字段有效
PSH(推送):为1时接收方应尽快将这个报文段交给应用层
RST(复位):为1时表明TCP连接出现故障必须重建连接
SYN(同步):在连接建立时用来同步序号
FIN (终止): 为1时表明发送端数据发送完毕要求释放连接
接收窗口占2个字节,用于流量控制和拥塞控制,表示当前接收缓冲区的大小。在计算机网络中,通常是用接收方的接收能力的大小来控制发送方的数据发送量。TCP连接的一端根据缓冲区大小确定自己的接收窗口值,告诉对方,使对方可以确定发送数据的字节数。
校验和占2个字节,范围包括首部和数据两部分。
选项是可选的,默认情况是不选。
三次握手与四次挥手:
TCP是面向连接的协议,因此每个TCP连接都有3个阶段:连接建立、数据传送和连接释放。连接建立经历三个步骤,通常称为“三次握手”。
TCP三次握手过程如下:
TCP四次挥手过程如下:
由于TCP连接是全双工的,因此每个方向都必须单独进行关闭。这原则是当一方完成它的数据发送任务后就能发送一个FIN来终止这个方向的连接。收到一个 FIN只意味着这一方向上没有数据流动,一个TCP连接在收到一个FIN后仍能发送数据。首先进行关闭的一方将执行主动关闭,而另一方执行被动关闭。
UDP,用户数据报协议,英文全称是User Datagram Protocol,它是TCP/IP协议簇中无连接的运输层协议。UDP协议的格式如下图所示:
UDP协议十分简单,它由两部分组成:首部和数据。其中,首部仅有8个字节,包括源端口和目的端口,长度(UDP用于数据报的长度)、校验和。
HTTP,超文本传输协议,英文全称是Hypertext Transfer Protocol,它是互联网上应用最为广泛的一种网络协议。HTTP是一种应用层协议,它是基于TCP协议之上的请求/响应式的协议,即一个客户端与服务器建立连接后,向服务器发送一个请求;服务器接到请求后,给予相应的响应信息。HTTP协议默认的端口号为80.
HTTP协议是基于TCP协议之上的请求/响应式协议,下面主要介绍HTTP报文的格式,HTTP报文主要有请求报文和响应报文两种。首先看请求报文的格式:
HTTP请求报文由请求行、首部行和实体主体组成,由浏览器发送给服务器。上面这张图中SP表示空格,cr lf表示回车和换行。
HTTP响应报文格式:
上面这张图是HTTP响应报文,它由状态行、首部行和实体主体组成。下面两张图是在谷歌浏览器内访问服务器查看的HTTP请求和响应。
HTTP请求方法和响应状态码:
在上面的HTTP请求报文例子中,我们可以看到请求方法是GET,这表示请求读取由URL所标志的信息,除了GET,还有其它几种常用的方法。
在HTTP响应报文的例子中,我们可以看到状态码是200,表示响应成功。下表是其它状态码,总共5大类,33种。
HTTP请求的GET方法和POST方法的区别?
GET和POST是HTTP请求的两种方法,主要区别在于GET方法是请求读取由URL所标志的信息,POST是给服务器添加信息
HTTPS和HTTP的区别
HTTPS(全称:Hyper Text Transfer Protocol over Secure Socket Layer),是以安全为目标的HTTP通道,简单讲是HTTP的安全版。
HTTPS和HTTP的区别主要为以下四点:
Socket编程:Java的网络编程主要涉及到的内容是Socket编程,Socket,套接字,就是两台主机之间逻辑连接的端点。TPC/IP协议是传输层协议,主要解决数据如何在网络中传输,而HTTP是应用层协议,主要解决如何包装数据。Socket,本质上就是一组接口,是对TCP/IP协议的封装和应用(程序员层面上)。
整体流程:Socket编程主要涉及到客户端和服务器端两个方面,首先是在服务器端创建一个服务器套接字(ServerSocket),并把它附加到一个端口上,服务器从这个端口监听连接。端口号的范围是0到65536,但是0到1024是为特权服务保留的端口号,我们可以选择任意一个当前没有被其他进程使用的端口。
客户端请求与服务器进行连接的时候,根据服务器的域名或者IP地址,加上端口号,打开一个套接字。当服务器接受连接后,服务器和客户端之间的通信就像输入输出流一样进行操作。
下面是一个客户端和服务器端进行数据交互的简单例子,通过这个例子可以初步对Socket编程有个把握。
/**
* 服务器端
*/
public class Server {
public static void main(String[] args) throws IOException {
try {
//创建一个Socket,接收客户端请求,监听5000
ServerSocket serverSocket = new ServerSocket(5000);
System.out.println("服务器启动成功,等待用户接入…");
//使用accept()侦听并接收到此ServerSocket的连接
Socket socket = serverSocket.accept();//侦听到之前都是阻塞的
System.out.println("有客户端接入,客户IP:" + socket.getInetAddress());
// 从客户端生成网络输入流,用于接收来自网络的数据
InputStream is = socket.getInputStream();
// BufferedReader读取字符流
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String info;
// BufferedReader的方法可以一行一行的读
while((info = br.readLine())!=null){
System.out.println("客户端:"+info);
}
//给客户端一个响应
String reply = "欢迎登陆";
//通过输出流将响应发送回给客户端
OutputStream os = socket.getOutputStream();
os.write(reply.getBytes());
//释放相应资源
os.close();
br.close();
is.close();
socket.close();
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 客户端
*/
public class Client {
public static void main(String[] args) throws IOException {
//创建一个客户端的Socket
try {
Socket socket = new Socket("localhost",5000);
System.out.println("连接服务器成功");
//通过输出流发送请求
//直接输出数据流
String info = "用户名:张三;密码:123456";
// 从客户端生成网络输出流,用来把数据发送到网络上
OutputStream os = socket.getOutputStream();
//打散成数据数组
byte[] infos = info.getBytes();
os.write(infos);
//关闭输出流,这是一个半关闭
socket.shutdownOutput();
//通过输入流接收服务器给我的响应
InputStream is = socket.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String reply;
while((reply = br.readLine())!=null){
System.out.println("服务器:"+reply);
}
//释放资源
os.close();
socket.close();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
先启动服务器端,再启动客户端,测试代码如下图所示:
下面以一个例子介绍:实现服务器和客户端的多线程连接;并且服务器和客户端可以无限对话。
import java.io.*;
import java.net.*;
import java.util.Scanner;
/**
* 接收客户请求,基于客户一个响应:线程构造方法中去绑定客户端的Socket
*/
public class LogicThread extends Thread {
private Socket socket;
public LogicThread(Socket socket){
this.socket=socket;
}
//接收客户请求,基于客户一个响应
public void run(){
InputStream is=null;
BufferedReader br=null;
PrintWriter pw=null;
OutputStream os=null;
try{
Scanner input = new Scanner(System.in);
//获得输入流,获得用户的请求
while(true){
is= socket.getInputStream();
br = new BufferedReader(new InputStreamReader(is));
System.out.println(socket.getInetAddress()+"说:"+br.readLine());
//给客户端一个响应
//通过输出流将响应发送回给客户端
String reply =input.next();
os = socket.getOutputStream();
pw = new PrintWriter(os);
pw.println(reply);
pw.flush();
}
//释放相应资源
}catch (IOException e) {
e.printStackTrace();
}finally {
try{
pw.close();
os.close();
br.close();
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
import java.io.*;
import java.net.*;
/**
* 监听客户请求:一旦监听到有客户请求,立即创建一个线程,开启线程
*/
public class LogicServicer {
public static void main(String[] args) {
try {
//接收客户端请求
//创建一个Socket
ServerSocket serverSocket = new ServerSocket(8848);
System.out.println("服务器已启动...");
//使用accept()侦听并接收到此ServerSocket的连接
//一直监听客户请求
while(true){
Socket socket = serverSocket.accept();//侦听到之前都是阻塞的
System.out.println("已连接");
//创建一个和该客户端响应的线程
LogicThread logicThread = new LogicThread(socket);
logicThread.start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
import java.io.*;
import java.net.*;
import java.util.Scanner;
/**
* 客户端:发送请求到服务器,接收服务器的响应
*/
public class LogicClient {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
OutputStream os=null;
PrintWriter pw=null;
InputStream is=null;
BufferedReader br=null;
//创建一个客户端的Socket
try {
Socket socket = new Socket("localhost",8848);
System.out.println("客户端已启动");
//通过输出流发送请求
while(true){
String info =input.next();
os = socket.getOutputStream();
pw = new PrintWriter(os);
pw.println(info);
pw.flush();
//通过输入流接收服务器给我的响应
is = socket.getInputStream();
br = new BufferedReader(new InputStreamReader(is));
System.out.println("服务器:"+br.readLine());
}
//释放资源
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally{
try {
os.close();
pw.close();
br.close();
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}