TCP/IP协议


TCP/IP协议栈是一系列网络协议的总和,是构成网络通信的核心骨架,它定义了电子设备如何连入因特网,以及数据如何在它们之间进行传输。

TCP/IP协议分层模型

TCP/IP协议的分层有2个模型,分别是TCP/IP参考模型与OSI参考模型。

在TCP/IP参考模型中,是分为数据链路层、互联网IP层、传输层、应用层共4层

在OSI参考模型中分为物理层、数据链路层、网络层、传输层、会话层、表示层、应用层共7层。

TCP协议是目前使用最为广泛的协议,OSI是一个理想模型(硬件跟不上)

OSI协议模型

OSI就是一个开放的通信系统互联参考模型,也是一个定义的很好的协议规范。OSI模型有7层结构,每层都可以有几个子层。OSI的7层从下到上分别是7-应用层、6-表示层、5-会话层、4-传输层、3-网络层、2-数据链路层、1-物理层

物理层:是参考模型的最低层。该层是网络通信的数据传输介质,由连接不同结点的电缆与设备共同构成。主要跟功能是:利用传输介质为数据链路层提供物理连接,负责处理数据传输并监控数据出错率,以便数据流的透明传输。典型设备时集线器HUB

数据链路层:四参考模型的第二层。主要功能是:在物理层提供的服务基础上,在通信的实体间建立数据链路连接,传输以“帧”为单位的数据包,并采用差错控制与流量控制方法,使有差错的物理线路变成无差错的数据链路。典型设备是交换机SWITCH

网络层:是参考模型的第三层。主要功能是:为数据在节点之间传输创建逻辑链路,通过路由选择算法为分组通过通信子网选择最适当的路径,以及实现拥塞控制、网络互连等功能。

传输层:是参考模型的第四层。主要功能是:向用户提供可靠地端到端服务,处理数据包错误、数据包次序,以及其他一些关键传输问题。传输层向高层屏蔽了下层数据通信的细节。因此,它是计算机通信体系结构中关键的一层。

会话层:是参考模型的第五层。主要功能是:负责维扩两个结点之间的传输连接,以便确保点到点传输不中断,以及管理数据交换等功能。

表示层:是参考模型的第六层。主要功能是:用于处理在两个通信系统中交换信息的表示方法,主要包括数据格式变换、数据加密与解密、数据压缩与恢复等功能。

应用层:是参考模型的最高层。主要功能是:为应用软件提供了很多服务,比如文件服务器、数据库服务、电子邮件与其他网络软件服务。

TCP协议

三次握手
TCP是面向连接的协议,因此每个TCP连接都有3个阶段:连接建立、数据传送和连接释放。连接建立经历三个步骤,通常称为三次握手。可以参考网络状态切换图

第一次握手(客户端发送请求)
客户机发送连接请求报文段到服务器,并进入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。
注意:握手过程中传送的包里不包含数据,三次握手完毕后,客户端与服务器才正式开始传送数据。

计算机网络是通过传输介质、通信设施和网络通信协议,把分散在不同地点的计算机设备互连起来的,实现资源共享和数据传输的系统。网络编程就是编写程序使互联网的两个(或多个)设备(如计算机)之间进行数据传输。Java语言对网络编程提供了良好的支持。通过其提供的接口我们可以很方便地进行网络编程。

IP地址

IP协议有2个版本,分别是IPv4和IPv6,目前IPv4的地址已经耗尽

IPv4采用的是4位点分十进制的计法,例如192.168.4.36,每个位的取值范围为0-255。
由于4位点分十进制的计法很难记忆,所以因为域名 www.baidu.com对应的IP地址为220.181.38.149

Internet依靠DNS实现了机器名和IP地址之间的对应关系,DNS负责完成域名的解析

InetAddress是Java对IP地址的封装。其下有两个子类Inet4Address和Inet6Address。这个类的实例经常和UDP DatagramSockets和Socket,ServerSocket类一起使用

InetAddress 没有公开的构造方法,因此你必须通过一系列静态方法中的某一个来获取它的实例。
在这里插入图片描述
在这里插入图片描述

不仅可以通过主机名获取ia对象,也可以通过IP地址构建ia对象
在这里插入图片描述

还可以通过InetAddress中的方法获取本地机的相关信息
在这里插入图片描述

特殊方法isReachable用于测试是否可以到达该地址,防火墙和服务器配置可能阻塞请求,使得在访问时处于不可达状态

在这里插入图片描述

URL访问网上资源

URL对象代表统一资源定位器(通俗就是网址),是指向互联网资源的指针,资源可以是简单的文件或目录,也可以是对复杂对象的引用,例如对数据库或搜索引擎的查询。用协议名、主机、端口和资源组成,即满足格式:protocol://host:port/resourceName,
例如http://www.yan.com:80/index.php

http协议的标准端口为80
https=http+SSL 加密数据传输的http,标准端口为443

最重要的方法:
url.openConnection():URLConnection 可以获取输入、输出流
url.openStream():InputStream 直接获取输入流
在这里插入图片描述

下载并保存指定的页面
在这里插入图片描述

获取当前网页的所有相关的链接地址

在这里插入图片描述

获取URL对象封装的地址信息的不同部分
在这里插入图片描述

URL与URLConnection比较

URL和URLConnection的区别在于前者代表一个资源的位置,后者代表一种连接
Java语言提供了两种方法读取数据,一种是通过URL对象直接得到相关的网络信息,另一种是先得到一个URLConnection实例,再得到InputStream或OutputStream对象,然后读取数据
前者是一种简单、直接的方法,但缺乏灵活性,并且只能读取只读信息,后者提供了更加灵活有效的方法来读取网络资源

TCP

TCP传输控制协议,属于传输层协议,提供一个可靠的点到点的虚连接。

在实际应用中TCP网络程序提供可靠的数据通信,而UDP网络程序则不保证数据的可靠性,但是协议简单、传输速度快(比如用在音视频数据传输,它们不需要很高的可靠性,偶尔丢帧是可以忍受的)

TCP是Tranfer Control Protocol的 简称,是一种面向连接的端对端的保证可靠传输的协议。

通过TCP协议传输,得到的是一个顺序的无差错的数据流。
在这里插入图片描述

Socket是什么呢?
Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。

发送方和接收方的成对的两个socket之间必须建立连接,以便在TCP协议的基础上进行通信,当一个socket(通常都是server socket)等待建立连接时,另一个socket可以要求进行连接,一旦这两个socket连接起来,它们就可以进行双向数据传输,双方都可以进行发送 或接收操作。

ServerSocket类

Java.net包中的ServerSocket类用于表示服务器套接字,其主要功能是监听客户端的请求,然后将客户端的请求连接存入队列中,默认请求队列大小是50。
构造方法主要有以下几种形式:
ServerSocket(int port):创建绑定到特定端口的服务器套接字。Port的取值范围为0-65535之间,0表示使用任意未占用端口,建议使用的端口号大于1024。如果端口已经被占用则会BindException

ServerSocket(int port,int backlog,InetAdress bindAddress):使用指定的端口、监听backlog和要绑定到本地IP地址创建服务器,适用于计算机有多个网卡、多个IP的情景
在这里插入图片描述

最可怕的中毒事件是木马程序。例如netbus,一般情况下木马会打开一些端口,供远程客户端连接。

使用ServerSocket检测当前机已经打开的端口号
在这里插入图片描述

多线程的例子

public class Test1 {
	static Set<Integer> set = Collections.synchronizedSet(new HashSet<>());  //7个线程操作同一个Set,所以需要考虑线程安全问题
	static CountDownLatch cdl=new CountDownLatch(7); //阻塞主线程,等待7个子线程执行结果
	public static void main(String[] args) throws Exception {
		for (int i = 0; i < 7; i++) {
			int begin = i * 10000 + 1;
			int end = (i + 1) * 10000;
			if (end > 65535)
				end = 65535;
			new Thread(new MyRunnable(begin, end)).start();
		}
		cdl.await();   //注册当前的主线程,等待cdl为0
		set.forEach(System.out::println);
	}

	static class MyRunnable implements Runnable {
		private int begin, end;

		public MyRunnable(int begin, int end) {
			this.begin = begin;
			this.end = end;
		}

		@Override
		public void run() {
			for (int i = begin; i <= end; i++) {
				ServerSocket ss = null;
				try {
					ss = new ServerSocket(i);
				} catch (Exception e) {
					set.add(i);
				} finally {
					try {
						if (ss != null) ss.close();
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
			}
			cdl.countDown();  //倒计算器-1
		}
	}
}

客户端Socket的构造器

Socket(String host, int prot); 在客户端构建Socket对象,如果构建成功则获取对象,否则ConnectException。参数1为链接主机的名称,也可以使用InetAddress表示IP地址;参数2为链接服务器的监听端口号,要求服务器已经打开的链接端口

需求:客户端发起一个请求【hello server】,服务器响应一个信息内容为【server:服务器系统当前时】
1、在TCP编程中Server和client地位不对等,首先需要在服务器端开启监听端口,然后阻塞主线程,等待客户端的连接请求
服务器端:
在这里插入图片描述

客户端发起连接请求
在这里插入图片描述

2、客户端和服务器分别通过各自的Socket对象获取对应的输入输出流(字节流)。服务器的输出流对应客户端的输入流,服务器的输入流对应客户端的输出流,所以在具体的操作中只是编程操作流,而无需关心数据的传输细节
在这里插入图片描述

针对字符数据直接使用字节流比较麻烦,所以可以通过过滤流操作字符
在这里插入图片描述

3、具体实现通讯细节
客户端
在这里插入图片描述

服务器
在这里插入图片描述

4、关闭相关的流和套接字对象,规则是正向打开,逆向关闭
在这里插入图片描述

具体代码:
服务器
在这里插入图片描述

客户端编码

在这里插入图片描述

启动一个服务器对多个客户端请求进行响应

具体实现:一个客户端使用一个线程进行处理,处理完毕自动关闭连接,服务器主线程一直处于监听等待状态

public class Server {

	public static void main(String[] args) throws Exception {
		ServerSocket ss = null;
		try {
			ss = new ServerSocket(9000);
			while (true) {
				Socket s = ss.accept();
				if (s != null)
					new ServerThread(s).start();
			}
		} finally {
			if (ss != null)
				ss.close();
		}
	}

}

class ServerThread extends Thread {
	private Socket socket;

	public ServerThread(Socket s) {
		this.socket = s;
	}

	@Override
	public void run() {
		try (
				// 通讯细节提前进行约定。如果客户端hello,则服务器响应当前时;如果客户端bye则服务器针对客户端的线程执行结束
				BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
				PrintStream ps = new PrintStream(socket.getOutputStream());) {
			while (true) {
				String ss = br.readLine();
				if (ss != null) {
					System.out.println("客户端" + socket.getInetAddress().getHostAddress() + "说:" + ss);
					if ("bye".equals(ss))
						break;
					if ("hello".equals(ss))
						ps.println(new Date().toString());
					else {
						ps.println("然后呢?");
					}
					ps.flush();
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

客户端:
用户键盘录入数据,用户输入bye退出

传送其它类型数据
ObjectInputStream ois=new ObjectInputStream(socket.getInputStream());
Object obj=ois.readObject();

ObjectOutputStream oos=new ObjectOutputStream(socket.getOutputStream());
oos.writeObject(obj);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值