分布式架构基础

本文深入探讨了TCP和UDP两种网络通信协议,包括它们的特点、连接建立与断开的过程。此外,还提供了详细的Java Socket编程实例,展示了如何实现服务器端和客户端的通信,包括发送和接收当前时间戳并计算时间差。通过实例,读者可以更好地理解TCP的三次握手和四次挥手过程。
摘要由CSDN通过智能技术生成

分布式架构基础

网络通信技术

socket编程

非常好的学习链接:

Socket学习网络基础准备

Java 网络编程

基本流程及注意事项(建立TCP连接)
  • 服务器实例化一个 ServerSocket 对象,表示通过服务器上的端口通信。
  • 服务器调用 ServerSocket 类的 accept() 方法,该方法将一直等待,直到客户端连接到服务器上给定的端口。
  • 服务器正在等待时,一个客户端实例化一个 Socket 对象,指定服务器名称和端口号来请求连接。
  • Socket 类的构造函数试图将客户端连接到指定的服务器和端口号。如果通信被建立,则在客户端创建一个 Socket 对象能够与服务器进行通信。
  • 在服务器端,accept() 方法返回服务器上一个新的 socket 引用,该 socket 连接到客户端的 socket。

连接建立后,通过使用 I/O 流在进行通信

每一个socket都有一个输出流和一个输入流

客户端的输出流连接到服务器端的输入流,而客户端的输入流连接到服务器端的输出流。

TCP 是一个双向的通信协议,因此数据可以通过两个数据流在同一时间发送

要求:编写一个socket服务器端和socket客户端

实现功能:

  1. socket服务器端监听于8888端口
  2. socket客户端连接到服务器端,发送一串当前时间的字符串:yyyy-MM-dd HH:mm:ss.ffff
  3. socket服务器端接收到消息后,获取当前服务器端时间,返回当前服务器端时间和接收到客户端发送过来时间串的时间间隔,返回此间隔的数值(单位:ms)
  4. socket客户端把返回的间隔数值显示出来,退出程序
Socket服务端实例
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @Author Fiya
 * @Date 2021/6/1 2:10
 */
public class Server {
    public static void main(String[] args) {
        try {
            // 创建socket链接,端口8888
            ServerSocket server = new ServerSocket(8888);

            while (true) {
                Socket socket = server.accept();
                ServerThread thread = new ServerThread(socket);
                thread.start();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

class ServerThread extends Thread {
    private Socket socket = null;
    public ServerThread(Socket socket) {this.socket = socket;}
    
    @Override
    public void run() {
        InputStream is = null;
        is = null;
        InputStreamReader isr = null;
        BufferedReader br = null;
        OutputStream os = null;
        PrintWriter pw = null;
        try {
            //输入流
            is = socket.getInputStream();
            isr = new InputStreamReader(is);
            br = new BufferedReader(isr);

            String info = null;
            SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSS");
            long recvTime;
            long nowTime;
            long diff = 0;
            while ((info = br.readLine()) != null) {
                System.out.println("接受来自客户端的信息:"+info);
                recvTime = f.parse(info).getTime();
                Date now = new Date();
                nowTime = f.parse(f.format(now)).getTime();
                diff = nowTime - recvTime;
            }
            socket.shutdownInput();
            os = socket.getOutputStream();
            pw = new PrintWriter(os);
            pw.write("响应时间"+ diff + "ms");
            pw.flush();
        } catch (Exception e) {
            e.printStackTrace();
        } finally{
            //关闭资源
            try {
                if(pw!=null)
                    pw.close();
                if(os!=null)
                    os.close();
                if(br!=null)
                    br.close();
                if(isr!=null)
                    isr.close();
                if(is!=null)
                    is.close();
                if(socket!=null)
                    socket.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

Socket客户端实例
import java.io.*;
import java.net.Socket;
import java.net.UnknownHostException;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Scanner;

/**
 * @Author Fiya
 * @Date 2021/6/1 4:35
 */
public class Client {
    public static void main(String[] args) throws Exception {
        try {
            // 创建socket
            Socket socket = new Socket("localhost", 8888);
            // 发送消息
            OutputStream os = socket.getOutputStream();
            PrintWriter pw = new PrintWriter(os);

            Date now = new Date();
            SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSS");
            pw.write(f.format(now));
            pw.flush();
            socket.shutdownOutput();

            // 接收信息
            InputStream is = socket.getInputStream();
            BufferedReader br = new BufferedReader(new InputStreamReader(is));
            String line = null;
            while ((line = br.readLine()) != null) {
                System.out.println("服务器返回:" + line);
            }
            br.close();
            is.close();
            pw.close();
            os.close();
            socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

TCP

TCP是面向连接的协议

三次握手

建立一个TCP连接时,需要客户端和服务端总共发送3个包以确认连接的建立, 在Socket编程中,这一过程由客户端执行connect来触发:

在这里插入图片描述

  • 第一次握手

    Client将标志位SYN置为1,随机产生一个值seq=J,并将该数据包发送给Server, Client进入SYN_SENT状态,等待Server确认。

  • 第二次握手

    Server收到数据包后由标志位SYN=1知道Client请求建立连接

    Server将标志位 SYN和ACK都置为1ack=J+1,随机产生一个值seq=K,并将该数据包发送给Client以确认连接请求 ,Server进入SYN_RCVD状态

  • 第三次握手

    Client收到确认后,检查ack是否为J+1ACK是否为1,如果正确则将标志位ACK 置为1,ack=K+1,并将该数据包发送给Server

    Server检查ack是否为K+1,ACK是否为1,如果正确则 连接建立成功,Client和Server进入ESTABLISHED状态,完成三次握手,随后Client与Server之间可以 开始传输数据了。

四次握手

断开一个TCP连接时,需要客户端和服务端总共发送4个包以确认连接的断开。 在Socket编程中,这一过程由客户端或服务端任一方执行close来触发

在这里插入图片描述

  • 第一次挥手

    Client发送一个FIN,用来关闭Client到Server的数据传送,Client进入 FIN_WAIT_1状态

  • 第二次挥手

    Server收到FIN后发送一个ACK给Client,确认序号为收到序号+1(与SYN相同, 一个FIN占用一个序号)

    Server进入CLOSE_WAIT状态。

  • 第三次挥手:Server发送一个FIN,用来关闭Server到Client的数据传送

    Server进入LAST_ACK 状态。

  • 第四次挥手:Client收到FIN后,Client进入TIME_WAIT状态,接着发送一个ACK给Server,确认序号为收到序号+1

    Server进入CLOSED状态,完成四次挥手。

特点
  • 面向连接

    三次握手建立可靠的连接,为数据可靠传输打下基础

  • 仅支持1对1传输

    每条TCP传输连接只能有两个端点,不支持1对多

  • 面向字节流

    以字节流方式进行传输,不保留消息边界

  • 高可靠性

    判断丢包和误码靠的是TCP的段编号及确认号。如果发送端实体在合理的往返时延(RTT)内未收到确认,那么对应的数据(假设丢失了)将会被重传

  • 提供拥塞控制

    网络拥塞时TCP能减小向网络注入数据的速率和数量,缓解拥塞

  • 全双工方式传输

UDP

UDP是一种简单的、面向数据报的无连接的协议,提供的是不一定可靠的传输服务

所谓“无连接”是指在正式通信前不必与对方先建立连接,不管对方状态如何都直接发送过去

它除了给应用程序发送数据包功能并允许它们在所需的层次上架构自己的协议之外,几乎没有做什么特别的事情。面向连接的TCP几乎做了所有的事情。

特点
  • 面向无连接

    发送数据想法就发,不对消息进行任何拆分和拼接操作

  • 有单播,多播,广播功能

  • 面向报文的

    发送方的UDP对应用程序交下来的报文,在添加首部后就向下交付IP层。UDP对应用层交下来的报文,既不合并,也不拆分,而是保留这些报文的边界。因此,应用程序必须选择合适大小的报文

  • 不可靠性

    首先不可靠性体现在无连接上,通信都不需要建立连接,想发就发,这样的情况肯定不可靠。

    并且收到什么数据就传递什么数据,并且也不会备份数据,发送数据也不会关心对方是否已经正确接收到数据了。

    再者网络环境时好时坏,但是 UDP 因为没有拥塞控制,一直会以恒定的速度发送数据。即使网络条件不好,也不会对发送速率进行调整

日志

间接通信

发布——订阅系统(生产者-消费者)

消息队列

共享内存

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

天亮又要起床Fiiii

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值