ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

分布式学习笔记(二)——远程通信协议

2022-03-06 12:59:40  阅读:127  来源: 互联网

标签:负载 服务器端 报文 通信协议 笔记 socket 分布式 连接 客户端


远程通信原理

网络分层模型

http 协议的通信是基于 tcp/ip 协议之上的一个应用层协议,应用层协议除了 http 还有FTP、DNS、SMTP、Telnet 等。涉及到网络协议,一定需要知道 OSI 七层网络模型和 TCP/IP 四层概念模型,OSI 七层网络模型包含(应用层、表示层、会话层、传输层、网络层、数据链路层、物理层)、TCP/IP 四层概念模型包含(应用层、传输层、网络层、数据链路层)。
在这里插入图片描述

http请求原理

http协议是基于TCP/IP的,一个http请求在经过各个层时,其中每一层对收到的数据都要增加一些首部信息(有时还要增加尾部信息)
发送请求:
在这里插入图片描述
接收请求:
在这里插入图片描述

分层负载

二层负载均衡
二层负载是针对 MAC,负载均衡服务器对外依然提供一个 VIP(虚 IP),集群中不同的机器采用相同 IP 地址,但是机器的 MAC 地址不一样。当负载均衡服务器接受到请求之后,通过改写报文的目标 MAC 地址的方式将请求转发到目标机器实现负载均衡。
三层负载均衡
三层负载是针对 IP,和二层负载均衡类似,负载均衡服务器对外依然提供一个 VIP(虚 IP),但是集群中不同的机器采用不同的 IP 地址。当负载均衡服务器接受到请求之后,根据不同的负载均衡算法,通过 IP 将请求转发至不同的真实服务器。
四层负载均衡
四层负载均衡工作在 OSI 模型的传输层,由于在传输层,只有 TCP/UDP 协议,这两种协议中除了包含源 IP、目标 IP 以外,还包含源端口号及目的端口号。四层负载均衡服务器在接受到客户端请求后,以后通过修改数据包的地址信息(IP+端口号)将流量转发到应用服务器。
七层负载均衡
七层负载均衡工作在 OSI 模型的应用层,应用层协议较多,常用 http、radius、dns 等。七层负载就可以基于这些协议来负载。这些应用层协议中会包含很多有意义的内容。比如同一个Web 服务器的负载均衡,除了根据 IP 加端口进行负载外,还可根据七层的 URL、浏览器类别来决定是否要进行负载均衡。

TCP报文格式

在这里插入图片描述
其中比较重要的字段有:

(1)序号(sequence number):seq序号,占32位,用来标识从TCP源端向目的端发送的字节流,发起方发送数据时对此进行标记。

(2)确认号(acknowledgement number):ack序号,占32位,只有ACK标志位为1时,确认序号字段才有效,ack=seq+1。

(3)标志位(Flags):共6个,即URG、ACK、PSH、RST、SYN、FIN等。具体含义如下:

  • URG:紧急指针(urgent pointer)有效。
  • ACK:确认序号有效。
  • PSH:接收方应该尽快将这个报文交给应用层。
  • RST:重置连接。
  • SYN:发起一个新连接。
  • FIN:释放一个连接。

不要将确认序号Ack与标志位中的ACK搞混了。确认方ack=发起方seq+1,两端配对。

TCP的三次握手

TCP协议是可靠的协议,可靠性来自于有效的连接建立。在数据进行传输前,需要通过三次握手建立一个连接,所谓的三次握手,就是在建立 TCP 链接时,需要客户端和服务端总共发送 3 个包来确认连接的建立。在 socket 编程中,这个过程由客户端执行 connect 来触发。
在这里插入图片描述
握手之前主动打开连接的客户端结束CLOSED阶段,被动打开的服务器端也结束CLOSED阶段,并进入LISTEN阶段。随后开始“三次握手”:
1、客户端向服务器发送一段TCP报文。包含SYN=1,标识位,表示请求建立连接,seq=x,带上自己的序号。然后进入SYN-SENT状态
2、服务器接收到客户端的报文,然后回复一份报文。包含标志位SYN=1、ACK=1,表示收到客户端申请建立连接的请求;seq=y,带上自己的序号,ack=x+1(,表示在收到建立连接的请求的基础上,将客户端的序号seq加1作为确认号ack的值)。然后结束LISTEN状态,进入SYN-RCVD状态。
3、客户端收到服务器回复的报文后,结束SYN-SENT状态,然后发送最后一份报文,包含ACK=1,表示确认收到服务器端同意连接的信号,seq=x+1,表示在收到“服务器同意建立连接”信号的基础上,将确认号作为自己的序号;ack=y+1,表示在收到信号的基础上将服务器端的序号+1作为确认号,随后客户端进入ESTABLISHED阶段。

服务器收到客户端发送的确认报文,明确了从服务器到客户端的数据传输是正常的。结束SYN-SENT阶段,进入ESTABLISHED阶段。

TCP四次挥手协议

四次挥手表示 TCP 断开连接的时候,需要客户端和服务端总共发送 4 个包以确认连接的断开。在 socket 编程中,任何一方执行 close() 操作即可产生挥手操作。
在这里插入图片描述
1、首先客户端想要释放连接,向服务器端发送一段TCP报文。包含:FIN=1,为标识位,表示“请求释放连接”;seq=u,客户端序号u。然后,进入FIN-WAIT1状态,并且停止在客户端到服务器端方向上发送数据(不包括确认报文),但是客户端仍然能接收从服务器端传输过来的数据。
2、服务器收到客户端“请求释放连接”的报文,知道了客户端想释放连接,于是结束ESTABLISHED状态,进入CLOSE-WAIT状态,然后回复一份报文。包含ACK=1,标识位,表示接收到客户端发送的断开连接请求;seq=v,服务器的序号;ack=u+1,表示将客户端的序号+1作为确认号的值。然后服务器端开始准备释放这个连接,客户端收到从服务器端发出的确认报文之后,确认了服务器收到了客户端发出的释放连接请求,随后客户端结束FIN-WAIT-1状态,进入FIN-WAIT-2状态。
3、服务器做好了释放连接的准备后,再向客户端发送一份报文,包含FIN=1,ACK=1,标识位,表示“已经准备好释放连接了”,这里的ACK并不是确认收到服务器端报文的确认报文;seq=w,服务器端的序号;ack=u+1,表示将客户端的序号+1作为确认号的值。随后服务器端结束CLOSE-WAIT状态,进入LAST-ACK状态。并且停止在服务器端到客户端的方向上发送数据,但是服务器端仍然能够接收从客户端传输过来的数据。
4、客户端收到服务器端的报文,确认了服务器端已做好释放连接的准备,结束FIN-WAIT-2状态,进入TIME-WAIT状态,并向服务器端发送一段报文,包含ACK=1,表示已经接收到服务器做好释放连接的准备的信号了;seq=u+1,表示是在收到了服务器端报文的基础上,将其确认号ack值作为本段报文序号的值;ack=w+1,表示在收到了服务器端报文的基础上,将服务器的序号+1作为确认号。随后客户端开始在TIME-WAIT状态等待2MSL,然后关闭。

之所以建立连接需要三次握手,而断开连接需要四次挥手。是因为建立连接时,服务器端收到收到客户端的SYN 连接请求报文后,可以直接回复SYN+ACK报文。而释放连接时,服务器端收到FIN 报文时,可能还有消息没有处理完,所以只能先回复一个 ACK 报文,等准备好之后,才能发送FIN报文确认,所以多了一步。

使用socket完成基于TCP的通信

Server端:

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

public class SocketServer {
    public static void main(String[] args) {

        ServerSocket server = null;
        Socket socket = null;
        BufferedReader in = null;
        BufferedWriter out = null;
        try {
            server = new ServerSocket(80);
            socket = server.accept();

            in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            String s= in.readLine();  //读取时以\n字符作为结束
            System.out.println("client:"+s);

            out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
            out.write("已收到!\n"); //需要加入\n,否则使用readLine()读取时,不会结束
            out.flush();

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (server!=null){
                    server.close();
                }
                if (socket!=null){
                    socket.close();
                }
                if (in!=null){
                    in.close();
                }
                if (out!=null){
                    out.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

client端:

import java.io.*;
import java.net.Socket;

public class SocketClient {
    public static void main(String[] args) {

        Socket socket = null;
        BufferedReader in = null;
        BufferedWriter out = null;
        try {
            socket = new Socket("127.0.0.1",80);
            out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
            out.write("服务器你好!\n");
            out.flush();
            in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            System.out.println("Server:"+in.readLine());
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {

                if (socket!=null){
                    socket.close();
                }
                if (in!=null){
                    in.close();
                }
                if (out!=null){
                    out.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

socket通信原理
在这里插入图片描述

标签:负载,服务器端,报文,通信协议,笔记,socket,分布式,连接,客户端
来源: https://blog.csdn.net/qq_34609889/article/details/123253902

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有