我是靠谱客的博主 重要台灯,最近开发中收集的这篇文章主要介绍【TCPIP协议】lipp_chan学习笔记一、原理二、应用,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

一、原理

在这里插入图片描述
在这里插入图片描述

1.IP协议(Internet protocol)

IP协议的作用在于把各种数据包准备无误的传递给对方,其中两个重要的条件是IP地址和MAC地址。由于IP地址是稀有资源,不可能每个人都拥有一个IP地址,所以我们通常的IP地址是路由器给我们生成的IP地址,路由器里面会记录我们的MAC地址。而MAC地址是全球唯一的。举例,IP地址就如同是我们居住小区的地址,而MAC地址就是我们住的那栋楼那个房间那个人。IP地址采用的IPv4格式,目前正在向IPv6过渡。
其中IP地址分为网络地址和主机地址,每个机器可能有相同的主机地址,但是网络地址取决你接入组织的IP地址,通过NAT你可以将主机地址转换成网络地址

例子:

// 获得本地主机IP地址对象
        InetAddress inet01 = InetAddress.getLocalHost();
        // 主机名/ip地址字符串
        System.out.println(inet01);
        // 根据IP地址字符串或主机名获得对应的IP地址对象
        InetAddress inet02 = InetAddress.getByName("www.baidu.com");
        System.out.println(inet02);
        // 获得主机名
        String hostName = inet01.getHostName();
        System.out.println(hostName);
        // 获得IP地址字符串
        String hostAddress = inet01.getHostAddress();
        System.out.println(hostName);
        System.out.println(hostAddress);
value:
LTCN001705/10.225.114.108
www.baidu.com/180.101.49.11
LTCN001705
LTCN001705
10.225.114.108

2.TCP协议(Transmission Control Protocol)

TCP(传输控制协议)是面向连接的传输层协议。TCP层是位于IP层之上,应用层之下的中间层。不同主机的应用层之间经常需要可靠的、像管道一样的连接,但是IP层不提供这样的流机制,而是提供不可靠的包交换。TCP协议采用字节流传输数据。
  传输层起着承上启下的作用,涉及源端节点到目的端节点之间可靠的信息传输。传输层需要解决跨越网络连接的建立和释放,对底层不可靠的网络,建立连接时需要三次握手,释放连接时需要四次挥手。 
在这里插入图片描述
源端口:两个字节。端口用于寻找发送端和接收端的进程,通过端口号和IP地址,可以确立唯一一个TCP链接。
序号:SEq序号,用于标识TCP发送端到TCP接收端发送的数据字节流。
确认序号:认序号应该是上次已经成功收到数据字节序号加1,即Ack=Seq + 1。
SYN(同步):在连接建立时用来同步序号
ACK(确认):为1时表明确认号字段有效
PSH(推送):为1时接收方应尽快将这个报文段交给应用层
RST(复位):为1时表明TCP连接出现故障必须重建连接
FIN(终止):为1时表明发送端数据发送完毕要求释放连接

3.TCP三次握手和四次挥手

在这里插入图片描述
连接建立–>数据传送–>连接释放
tcp连接采用cs方式
第一次握手(客户端发送请求)
客户机发送连接请求报文段到服务器,并进入SYN_SENT状态,等待服务器确认。发送连接请求报文段内容:SYN=1,seq=x;SYN=1意思是一个TCP的SYN标志位置为1的包,指明客户端打算连接的服务器的端口;seq=x表示客户端初始序号x,保存在包头的序列号(Sequence Number)字段里。
第二次握手(服务端回传确认)

服务器收到客户端连接请求报文,如果同意建立连接,向客户机发回确认报文段(ACK)应答,并为该TCP连接分配TCP缓存和变量。服务器发回确认报文段内容:SYN=1,ACK=1,seq=y,ack=x+1;SYN标志位和ACK标志位均为1,同时将确认序号(Acknowledgement Number)设置为客户的ISN加1,即x+1;seq=y为服务端初始序号y。

第三次握手(客户端回传确认)

客户机收到服务器的确认报文段后,向服务器给出确认报文段(ACK),并且也要给该连接分配缓存和变量。此包发送完毕,客户端和服务器进入ESTABLISHED(TCP连接成功)状态,完成三次握手。客户端发回确认报文段内容:ACK=1,seq=x+1,ack=y+1;ACK=1为确认报文段;seq=x+1为客户端序号加1;ack=y+1,为服务器发来的ACK的初始序号字段+1。
    注意: 握手过程中传送的包里不包含数据,三次握手完毕后,客户端与服务器才正式开始传送数据。
    TCP连接是全双工的,因此每个方向都必须单独进行关闭。这原则是当一方完成它的数据发送任务后就能发送一个FIN来终止这个方向的连接。收到一个FIN只意味着这一方向上没有数据流动,一个TCP连接在收到一个FIN后仍能发送数据。首先进行关闭的一方将执行主动关闭,而另一方执行被动关闭。
在这里插入图片描述

1. TCP客户端发送一个FIN,用来关闭客户端到服务端的数据传送,客户端进入FIN_WAIT_1状态。发送报文段内容:FIN=1,seq=u;FIN=1表示请求切断连接;seq=u为客户端请求初始序号。

2. 服务端收到这个FIN,它发回一个ACK给客户端,确认序号为收到的序号加1。和SYN一样,一个FIN将占用一个序号;服务端进入CLOSE_WAIT状态。发送报文段内容:ACK=1,seq=v,ack=u+1;ACK=1为确认报文;seq=v为服务器确认初始序号;ack=u+1为客户端初始序号加1。

3. 服务器关闭客户端的连接后,发送一个FIN给客户端,服务端进入LAST_ACK状态。发送报文段内容:FIN=1,ACK=1,seq=w,ack=u+1;FIN=1为请求切断连接,ACK=1为确认报文,seq=w为服务端请求切断初始序号。

4. 客户端收到FIN后,客户端进入TIME_WAIT状态,接着发回一个ACK报文给服务端确认,并将确认序号设置为收到序号加1,服务端进入CLOSED状态,完成四次挥手。发送报文内容:ACK=1,seq=u+1,ack=w+1;ACK=1为确认报文,seq=u+1为客户端初始序号加1,ack=w+1为服务器初始序号加1。

4.为什么是三次握手而四次挥手

多了一个FIN来告诉客户端,确认结束链接

5.UDP协议

DatagramPacket

UDP的数据包对象。

发送端:

`DatagramPacket(byte[] buf, int length, InetAddress address, int port)`
buf是要发送的内容,字节数组。
length是发送内容的长度,单位是字节。
address是接收端的IP地址对象
port是接收端的端口号。

接收端:

用于创建接收端的数据包对象

DatagramPacket(byte[] buf, int length)
buf:用来存储接收到内容。
length:能够接收内容的长度

DategramSocket

DatagramSocket()创建发送端的Socket对象,系统随机分配一个port号
DatagramSocket(int port) :创建接收端的Socket对象并指定端口号

例子

发送端代码

6.TCP与UDP的区别

  • TCP基于连接,UDP无连接。
  • TCP保证数据正确性,UDP可能丢包

7.HTTP协议

HTTP是应用层协议,基于TCP协议的请求响应协议。
http请求和响应报文都是由请求行、首部行和实体主体组成,其中分别为请求报文格式:
在这里插入图片描述
响应报文格式
在这里插入图片描述

常见状态码

在这里插入图片描述

HTTPS

安全版的HTTP,HTTPS的安全基础就是ssl,HTTP协议不适合传输一些敏感信息,比如信用开号、密码等。http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。http的连接很简单,是无状态的;https协议是有ssl+http协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。

8.为什么f12的网络信息为空。

右边设置改为默认就行

二、应用

Socket

1.原理

Socket,套接字,就是两台主机之间逻辑连接的端点。TCP、IP是传输层协议,解决数据在网络中传输问题。HTTP是应用层协议,主要解决包装数据的问题。Socker是通信的基石,包含网络通信必须的五种信息:1.连接使用的协议、2.本地主机IP地址、3.本地机型的协议端口、远程主机的IP地址、远程进程的协议端口。socket是对端口通信开发的工具,它要更底层一些。传输层的TCP是基于网络层的IP协议的,而应用层的HTTP协议又是基于传输层的TCP协议的。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.例子

一对一

client
public class SocketClient {
    public static void main(String[] args) throws UnknownHostException, IOException {

        int port = 7000;
        String host = "localhost";

        // 创建一个套接字并将其连接到指定端口号
        Socket socket = new Socket(host, port);

        DataInputStream dis = new DataInputStream(
                new BufferedInputStream(socket.getInputStream()));

        DataOutputStream dos = new DataOutputStream(
                new BufferedOutputStream(socket.getOutputStream()));

        Scanner sc = new Scanner(System.in);

        boolean flag = false;

        while (!flag) {

            System.out.println("请输入正方形的边长:");
            double length = sc.nextDouble();

            dos.writeDouble(length);
            dos.flush();

            double area = dis.readDouble();

            System.out.println("服务器返回的计算面积为:" + area);

            while (true) {

                System.out.println("继续计算?(Y/N)");

                String str = sc.next();

                if (str.equalsIgnoreCase("N")) {
                    dos.writeInt(0);
                    dos.flush();
                    flag = true;
                    break;
                } else if (str.equalsIgnoreCase("Y")) {
                    dos.writeInt(1);
                    dos.flush();
                    break;
                }
            }
        }
        socket.close();
    }
}
server
package day614;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

public class SocketServer {
	public static void main(String[] args) throws IOException {
		int port = 7000;
		ServerSocket serverSocket = new ServerSocket(port);
		Socket socket = serverSocket.accept();

		DataInputStream dis = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
		DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream()));
		System.out.println("Start=================");
		do {
			double length = dis.readDouble();
			System.out.println("服务器端收到的边长数据为:" + length);
			double result = length * length;
			dos.writeDouble(result);
			dos.flush();
		} while (dis.readInt() != 0);
		System.out.println("运行结束");
		socket.close();
		serverSocket.close();
	}
}

一对多,使用多线程套在服务器上

package day614;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class SocketServerM {
	public static void main(String[] args) throws IOException {
		int port = 7000;
		int clientNo = 1;

		ServerSocket serverSocket = new ServerSocket(port);

		// 创建线程池
		ExecutorService exec = Executors.newCachedThreadPool();

		try {

			while (true) {
				Socket socket = serverSocket.accept();
				exec.execute(new SingleServer(socket, clientNo));
				clientNo++;
				System.out.println(clientNo);
			}

		} finally {
			serverSocket.close();
		}

	}

}
package day614;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;

public class SingleServer implements Runnable {
	private Socket socket;
    private int clientNo;

	@Override
	public void run() {
		// TODO Auto-generated method stub
		 try {

	            DataInputStream dis = new DataInputStream(
	                    new BufferedInputStream(socket.getInputStream()));

	            DataOutputStream dos = new DataOutputStream(
	                    new BufferedOutputStream(socket.getOutputStream()));

	            do {

	                double length = dis.readDouble();
	                System.out.println("从客户端" + clientNo + "接收到的边长数据为:" + length);
	                double result = length * length;
	                dos.writeDouble(result);
	                dos.flush();

	            } while (dis.readInt() != 0);

	        } catch (IOException e) {
	            e.printStackTrace();
	        } finally {
	            System.out.println("与客户端" + clientNo + "通信结束");
	            try {
	                socket.close();
	            } catch (IOException e) {
	                e.printStackTrace();
	            }
	        }

	}
	 public SingleServer(Socket socket, int clientNo) {
	        this.socket = socket;
	        this.clientNo = clientNo;
	    }
}

3.对象类讲解

Socket(String host, int port):根据ip地址字符串和端口号创建客户端Socket对象
OutputStream getOutputStream():获得字节输出流对象。
InputStream getInputStream():获得字节输入流对象。

ServerSocket一个该类的对象就代表一个服务器端程序。

在socket通信方式中,服务器是主动等待连接通信的到来。
利用socket进行通信时,服务器端的程序可以打开多个线程与多个客户进行通信,还可以通过服务器使各个客户之间进行通信。这种方式比较灵活,适用于一些较复杂的通信,但是服务器端的程序必须始终处于运行状态以监听端口。
利用 URL进行通信时,服务器端的程序只能与一个客户进行通信,形式比较单一。但是它不需要服务器端的CGI程序一直处于运行状态,只是在有客户申请时才被激活。所以,这种方式比较适用于客户机的浏览器与服务器之间的通信。
总之,Socket是底层实现,协议你要自己去写,不局限于http,可以是任何协议。而类似HttpClient, FtpClient,URLConnetcion之类的,是对专属协议的封装,当然由于部分实现原理,你可能无法完全控制连接操作,比如setTimeout这个参数。

最后

以上就是重要台灯为你收集整理的【TCPIP协议】lipp_chan学习笔记一、原理二、应用的全部内容,希望文章能够帮你解决【TCPIP协议】lipp_chan学习笔记一、原理二、应用所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(63)

评论列表共有 0 条评论

立即
投稿
返回
顶部