网络------总结

传输层 (TCP协议)

TCP协议的定义:

即传输控制协议,规定了发送与接受方应该以一种什么样的方式传输数据。TCP 保障了两个应用程序之间的可靠通信,通常用于互联网协议,被称 TCP / IP。TCP提供双全工服务,即数据可在同一时间双向传输,每一个TCP都有发送缓存和接受缓存,用来临时存储数据。

TCP协议的作用:

TCP协议位于传输层,作用是提供可靠的字节流服务,为了准确无误地将数据送达目的地

TCP协议特点:

(1)基于流的方式;

(2)面向连接;

(3)可靠通信方式;

(4)在网络状况不佳的时候尽量降低系统由于重传带来的带宽开销;

(5)通信连接维护是面向通信的两个端点的,而不考虑中间网段和节点。

TCP协议的三次握手

TCP的三次握手的作用:

所谓三次握手即建立TCP连接,为了对每次发送的数据量进行跟踪与协商,确保数据段的发送和接收同步,根据所接收到的数据量而确认数据发送、接收完毕后何时撤消联系,并建立虚连接。

TCP三次握手的过程(个人理解):

首先在服务器上打开端口监听,端口从关闭状态变化为Listening(监听)状态。

报文就是一组客户端和服务端都认可的信息数据

第一步:客户端发送一个SYN请求连接报文,端口状态变为SYN_SENT状态,其中报文中包含seq序列号,由发送端随机生成,作用是使客户端与服务器的序列号对齐。

第二步:当服务器收到报文时,发出应答,服务器的端口状态变为SYN_RECV状态。服务端回复客户端一个SYN和ACK报文。

第三步:当客户端接收到服务器的报文以后,服务器向客户端发送ACK报文,与此同时客户端的端口状态变为ESTABLISHED状态。在服务器接收到客户端发来的报文后,服务器的端口状态变为ESTABLISHED状态。

在Socket编程中,这一过程由客户端执行connect来触发

图解如下:

 

LISTENING状态,处于侦听(LISTENING)状态,就是说该端口是开放的,等待连接,但还没有被连接。

SYN_SENT状态,表示请求连接。

SYN(synchronize):表示连接请求报文,同步序列编号

seq:发送数据的序列号

SYN_RECV是指,在收到和发送一个连接请求后,等待对方对连接请求的确认。

ACK(acknowledge):确认标志位,作用是返回给客户端,一个已收到消息的通知。

ACK中的seq里面是下一个希望收到的序列号且代表之前序列号传输的数据已经被正确的收到。

ESTABLISHED状态,表示连接成功。

TCP协议的四次挥手

终止TCP连接,就是指断开一个TCP连接时,需要客户端和服务端总共发送4个包以确认连接的断开。

  • 在Socket编程中,这一过程由客户端或服务端任一方执行close来触发

  • 图解如下

第一次挥手:客户端准备断开连接, 客户端向服务器发送FIN报文,表示请求与服务器断开连接。同时客户端的端口状态变为FIN_WAIT_1

第一次挥手:客户端准备断开连接, 客户端向服务器发送FIN报文,表示请求与服务器断开连接。同时客户端的端口状态变为FIN_WAIT_1 第二次挥手:服务器收到收到客户端发来的断开连接请求的FIN报文,服务器后对其进行响应,返回ACK报文,作用是告诉给客户端服务器收到客户端断开连接的请求。 第三次挥手:服务器发送FIN报文,请求关闭连接。(服务器收到客户端断开连接的请求,且已经没有数据需要发送给客户端的时候,服务器就会向客户端发起断开连接请求) 第四次挥手:客户端向服务器发送ACK报文。( 客户端收到服务器发来的断开连接请求后对其进行响应,对服务器发送ACK报文,服务器收到后直接关闭,客户端再等待2MSL后关闭)

  • 注:当客户端收到FIN包后,会等待2MSL时间,如果在2MSL时间内,没有再次收到FIN包就会关闭客户端。

  • FIN: 终止数据传输标志位---->当FIN为1的时候代表此数据为终止断开连接的请求

  • MSL( Maxium Segement Lifetime),指的是报文最大生存时间。当客户端收到FIN包后,会等待2MSL时间,如果在2MSL时间内,没有再次收到FIN包就会关闭客户端。

三次握手和四次挥手的时序图,如下:

 

SYN洪流攻击

TCP拥塞控制的四种算法:

  • 慢开始

    指一开始向网络中注入的报文段少,并不是指拥塞控制窗口cwnd增长速度慢。cwnd值每一轮都是前一轮的二倍,直到当前拥塞窗口的值已经等于慢开始门限值,之后改用拥塞避免算法。

  • 拥塞避免

    指在拥塞避免阶段将拥塞窗口控制为按现性规律增长,使网络比较不容易出现拥塞。cwnd的值只能线性加1,直到发生重传,发送方判断可能出现拥塞,更改cwnd和ssthresh,cwnd改为1,ssthresh改为发生拥塞时的cwnd的一半。

  • 快重传

    所谓快重传,就是发送方尽快进行重传,而不是等超时重传计时器超时时在重传。 要求接收方不会等待自己发送数据时才进行捎带确认,而是要立即发送确认; 即使收到了失序的报文段也要立即发出对已收到的报文段的重复确认。 发送方一旦收到三个连续的重复确认,就将相应的报文段立即重传,而不是等待该报文段的超时重传计时器超时在重传。 对于个别丢失的报文段,发送方不会出现超时重传,也就不会误认为出现了拥塞(进而降低拥塞窗口cwnd为1)。使用快重传可以使整个网络的吞吐量提高约20%。

  • 快恢复

    发送方一旦收到3个重复确认,就知道现在只是丢失了个别的报文段。于是不启动慢开始算法,而执行快恢复算法。将慢开始门限sstresh和拥塞窗口cwnd都设置为当前拥塞窗口的一半,然后执行拥塞避免算法

相关的基本概念:

  1. 在某段时间,若对网络中的某一资源的需求超过了该资源所能提供的可用部分,网络性能就要被破坏,这种情况就叫做拥塞
  2. 在计算机网络中的链路容量(即带宽)、交换结点中的缓存和处理机等,都是网络的资源

TCP拥塞控制的作用:

若出现拥塞而不进行控制,整个网络的吞吐量将随着负荷的增大而下降



ServerSocket和Socket

图解:

 

Socket类:

TCP socket分两种,监听socket和传输socket两种

监听socket:负责处理网络上来的连接请求,客户端的syn包到达便是连接请求来了

传输socket:负责在网络上的两个端点之间传输TCP数据。

Socket的定义

Socket被翻译为套接字,是网络数据处理的基本工具,负责网络数据的出入口,Socket通常用来实现客户方和服务方的连接。在Java环境下,Socket编程主要是指基于TCP/IP协议的网络编程。

Socket的常用方法:

getInetAddress();      远程服务端的IP地址

getPort();          远程服务端的端口

getLocalAddress()      本地客户端的IP地址

getLocalPort()        本地客户端的端口

getInputStream();     获得输入流

getOutStream();      获得输出流

值得注意的是,在这些方法里面,最重要的就是getInputStream()和getOutputStream()了。

Java中提供的Socket类中的核心功能:

//创建流套接字并将其连接到指定的IP地址的指定端口号
 Socket skt=new Socket("127.0.0.1",10086);
//发送数据
 OutputStream os=skt.getOutputStream();
//接收数据
 InputStream is=skt.getInputStream();

当Client程序需要从Server端获取信息及其他服务时,应创建一个Socket对象:

    Socket MySocket=new Socket(“ServerComputerName”,600);

Socket类的构造函数有两个参数,第一个参数是欲连接到的Server计算机的主机地址,第二个参数是该Server机上提供服务的端口号。
Socket对象建立成功之后,就可以在Client和Server之间建立一个连接,并通过这个连接在两个端点之间传递数据。利用Socket类的方法getOutputStream()和getInputStream()分别获得向Socket读写数据的输入/输出流,最后将从Server端读取的数据重新返还到Server端。
当Server和Client端的通信结束时,可以调用Socket类的close()方法关闭Socket,拆除连接。

ServerSocket 一般仅用于设置端口号和监听,真正进行通信的是服务器端的Socket与客户端的Socket,在ServerSocket 进行accept之后,就将主动权转让了。

ServerSocket类:

ServerSocket是JAVA提供的,基于BIO网络服务器套接字,在java.net包中

     创建一个ServerSocket类,同时在运行该语句的计算机的指定端口处建立一个监听服务,如:
    ServerSocket MyListener=new ServerSocket(600);

这里指定提供监听服务的端口是600,一台计算机可以同时提供多个服务,这些不同的服务之间通过端口号来区别,不同的端口号上提供不同的服务。

为了随时监听可能的Client请求,执行如下的语句:

    Socket LinkSocket=MyListener.accept();

该语句调用了ServerSocket对象的accept()方法,这个方法的执行将使Server端的程序处于等待状态,程序将一直阻塞直到捕捉到一个来自Client端的请求,并返回一个用于与该Client通信的Socket对象Link-Socket。此后Server程序只要向这个Socket对象读写数据,就可以实现向远端的Client读写数据。

结束监听时,关闭ServerSocket对象:
    Mylistener.close();

服务器程序设计

    在服务器端,利用ServerSocket类的构造函数ServerSocket(int port)创建一个ServerSocket类的对象,port参数传递端口,这个端口就是服务器监听连接请求的端口,如果在这时出现错误将抛出IOException异常对象,否则将创建ServerSocket对象并开始准备接收连接请求。
   服务程序从调用ServerSocket的accept()方法开始,直到连接建立。在建立连接后

accept()返回一个最近创建的Socket对象,该Socket对象绑定了客户程序的IP地址或端口号。

服务器代码如下:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
public class Server {

    //服务器的启动与逻辑
    public static void main(String[] args) {
        //本次使用TCP连接,所以服务器创建的应该是可以接受TCP连接的套接字
        //套接字:Socket,是网络数据处理的基本工具,负责网络数据的出入口。在Java环境下,Socket编程主要是指基于TCP/IP协议的网络编程。
        //服务器套接字和普通套接字是有区别的,我们实现服务器,所以用的网络工具是服务器套接字
        //ServerSocket是JAVA提供的,基于BIO网络服务器套接字,在java.net包中
        //创建对象的时候,需要指定ServerSocket中的端口号port;

        try {
//            System.out.println("准备创建ServerSocket");
            ServerSocket ss=new ServerSocket(10086);
//            System.out.println("创建了ServerSocket,并监听在10086端口号上,等待客户端连接  ");
            Socket s=ss.accept();
            InputStream is=s.getInputStream();
            BufferedReader br=new BufferedReader(new InputStreamReader(is));
            OutputStream os=s.getOutputStream();
            PrintWriter pw=new PrintWriter(os);
            Scanner scanner=new Scanner(System.in);
//            System.out.println(str);
//            System.out.println("客户端已经连接");

            while(true) {
                String str=br.readLine();
                System.out.println(str);
                if(str.equals("bye")) {
                    break;
                }
                String content=scanner.nextLine();
                pw.println(content);
                pw.flush();
                if(content.equals("bye")) {
                    break;
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

客户端程序设计

当客户程序需要与服务器程序通信时,需在客户机创建一个Socket对象。Socket类有构造函数Socket(InetAddress addr,int port)和Socket(String host,intport),两个构造函数都创建了一个基于Socket的连接服务器端流套接字的流套接字。对于第一个InetAd-dress子类对象通过addr参数获得服务器主机的IP地址,对于第二个函数host参数包被分配到InetAddress对象中,如果没有IP地址与host参数相一致,那么将抛出UnknownHostException异常对象。两个函数都通过参数port获得服务器的端口号。假设已经建立连接了,网络API将在客户端基于Socket的流套接字中捆绑客户程序的IP地址和任意一个端口号,否则两个函数都会抛出一个IOException对象。
    如果创建了一个Socket对象,那么它可通过get-InputStream()方法从服务程序获得输入流读传送来的信息,也可通过调用getOutputStream()方法获得输出流来发送消息。在读写活动完成之后,客户程序调用close()方法关闭流和流套接字。

客户端代码如下

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;

public class Client {

    //客户端的启动与逻辑
    public static void main(String[] args) {
//        127.0.0.1叫做回环地址(自己指向自己)
        try {
            Socket skt=new Socket("127.0.0.1",10086);
            OutputStream os=skt.getOutputStream();
            PrintWriter pw=new PrintWriter(os);
            InputStream is=skt.getInputStream();
            BufferedReader br=new BufferedReader(new InputStreamReader(is));
            Scanner scanner=new Scanner(System.in);

            while(true) {
                String content=scanner.nextLine();
                pw.println(content);
                pw.flush();
                if(content.equals("bye")) {
                    break;
                }
//                br.readLine();是接受对面来的内容
                String str=br.readLine();
                System.out.println(str);
                if(str.equals("bye")) {
                    break;
                }
            }

        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}e();
        }
    }

}

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值