Java学习第十九天 网络编程—TCP

本文详细介绍了网络通信的七层模型,包括应用层、表示层、会话层、传输层、网络层、数据链路层和物理层。同时,深入探讨了TCP/IP协议族中的常见协议如HTTP、FTP、TCP、UDP和IP的功能与作用,以及端口号和Socket在通信中的重要性。通过案例展示了如何使用Java进行TCP通信,包括服务器端和客户端的建立连接、数据传输和多线程处理。
七层协议

IOS(国际标准委员会组织)将数据的传递从逻辑上划分了以下七层
应用层、表示层、会话层、传输层、网络层、数据链据层、物理层

当发送消息时,需要按照上述从前往后的次序对发送的内容进行层层加包,最后发送出去
当接收消息时,需要按照上述相反的次序对发送的内容进行层层拆包,最后解析出来

常见协议

协议:就是一种约定/规则,是通信双方需要遵循的一种机制

http:超文本传输协议,浏览网站时使用该协议
ftp:文件传输协议,上传下载文件时候使用该协议
tcp:传输控制协议,是一种面向连接的协议
udp:用户数据报协议,是一种非面向连接的协议
ip:互联网协议,是上述协议的底层协议

端口号

IP地址可以定位到具体的一台设备
端口号可以定位到设备上具体的进程
在网络编程中需要提供:IP地址,端口号

端口号:本质上是由16位二进制组成的整数,范围是:065535,其中01024之间的端口以及被系统占用,因此编程端口号从1025开始

Socket

Socket套接字:
网络上具有唯一标识的IP地址和端口号组合在一起才能构成唯一能识别的标识符套接字

Socket原理机制:
通信的两端都有Socket
网络通信其实就是Socket间的通信
数据在两个Socket间通过IO传输

InetAddress

在JDK中提供了一个与IP地址相关的InetAddress类,该类用于封装一个IP地址,并提供了一系列与IP地址相关的方法

在这里插入图片描述
其中,前两个方法用于获得该类的实例对象,第一个方法用于获得表示指定主机的InetAddress对象,第2个方法用于获得表示本地的InetAddress对象。通过InetAddress对象便可获取指定主机名、IP地址等。

接下来通过一个案例来演示InetAddress常用方法的使用

import java.net.InetAddress;
public class Example01 {
	public static void main(String[] args) throws Exception {
		InetAddress host = InetAddress.getLocalHost();
		InetAddress byName = InetAddress.getByName("www.baidu.com");
		System.out.println("本机的IP地址:"+host.getHostAddress());
		System.out.println("百度的IP地址:"+byName.getHostAddress());
		System.out.println("3秒内是否可达:"+byName.isReachable(3000));
		System.out.println("本机的主机名是:"+host.getHostName());
		System.out.println("百度的主机名是:"+byName.getHostName());
	}
}
TCP通信

面向连接、安全可靠,效率稍低,通过三次握手建立连接

在JDK中提供了两个用于实现TCP程序的类,一个是ServerSocket类,用于表示服务器端,一个Socket类,用于表示客户端。通信时,首先要创建代表服务器端ServerSocket对象,创建该对象相当于开启了一个服务,此服务会等待客户端的连接;然后创建代表客户端的Socket对象,使用该对象向服务器端发出连接请求,服务器端响应请求后,两者才建立连接,开始通信。

ServerSocket(int port)
使用该构造方法在创建Serversocket对象时,可以将其绑定到一个指定的端口号上(参数port就是端口号)。端口号可以指定为0,此时系统就会分配一个还没被其他网络程序所使用的的端口号。由于客户端需要指定的端口号来访问服务器端程序,因此端口号随机分配的情况并不常用,通常都会让服务器端程序监听一个指定的端口号。
在这里插入图片描述
ServerSocket对象负责监听某台计算机的某个端口号,在创建ServerSocket对象后,需要继续调用该对象的accept()方法,接收来自客户端的请求。当执行了accept()方法之后,服务器端程序会发生阻塞,直到客户端发出连接请求时,accept()方法才会返回一个Socket对象,用于和客户端实现通信

Socket(InetAddress address,int port)
参数address用于接收一个InetAddress 类型的对象,该对象用于封装一个IP地址
在这里插入图片描述

Socket类的常用方法,其中,getInputStream()和getOutputStream()方法分别用于获取输入流和输出流。当客户端和服务端建立连接后,数据是以IO流的形式进行交互的,从而实现通信。

接下来通过一张图来描述服务器端和客户端的数据传输
在这里插入图片描述简单的TCP网络程序
通过前面两个小节了解到ServerSocket、Socket类的基本用法。为了让初学者更好地掌握这两个类的使用,接下来通过一个TCP通信的案例来进一步学习这两个类的用法

要实现TCP通信需要创建一个服务器端程序和一个客户端程序,为了保证数据传输的安全,首先需要实现服务端程序。

建立TCP服务端的思路

1. 创建ServerSocket类的想,并提供端口号
2. 等待客户端连接,使用accept()方法
3. 等Socket对象,并使用输入输出流进行通信
4. 关闭相互资源
public class Server {
	private static final int PORT=8888;		//定义一个端口号
	public static void main(String[] args) throws Exception {
		//创建ServerSocket对象
		ServerSocket ss = new ServerSocket(PORT);  
		//调用accpet()等待客户端的连接
		Socket s = ss.accept();		
		//获取客户端的输出流
		BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));  
		System.out.println("开始与客户端交互数据");	
		//当客户端接入后,向客户端输出数据
		bw.write("我是服务器,你好客户端!"); 
		//模拟置信其他功能占用的时间
		Thread.sleep(5000); 		
		System.out.println("结束与客户端交互数据");
		bw.flush();
		s.close();
		bw.close();
	}
}

在创建ServerSocket对象时指定了端口号,并调用该对象的accept()方法。从运行结果可以看出,控制台中的光标一直在闪动,这是因为accept()方法发生阻塞,程序暂时停止运行,直到客户端来访问时才会结束这种阻塞状态。这时该方法会返回一个Socket类型的对象用于表示客户端,通过该对象获取与客户端关联的输出流,并向客户端发送消息。最后调用Socket对象的close()方法将通信关闭。

建立TCP客户端的思路

1. 创建Socket类型的对象,并制定服务器的IP地址和端口号
2. 使用输入输出流进行通信
3. 关闭相互资源

接下来编写与客户端的程序。

public class Client {
	private static final int PORT=8888;		//定义一个端口号
	public static void main(String[] args) throws Exception {
		//创建一个Socket并连接到给出的地址和端口号的计算机
		Socket s = new Socket("192.168.96.1", PORT);
		//得到接收数据的流
		BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
		//读取数据
		String r = br.readLine();
		//打印读取到的数据
		System.out.println(r);
		//关闭资源
		br.close();
	}
}

在客户端创建Socket对象与服务器端建立连接后,通过Socket对象获得输入流读取服务端发来的数据,并打印结果,结束本次通信。

多线程的TCP网络程序
实际上,很多服务器端程序都是允许被多个应用程序访问的。例如门户网站可以被多个用户访问,因此服务器都是多线程的。下面通过一个图例来表示多个用户访问同一个服务器。

在这里插入图片描述
图中代表的是多个客户端访问同一个服务器端,服务器端为每个客户端创建一个对象的Socket,并且开启一个新的线程使两个Socket建立专线进行通信,接下来对TCP通信的服务端进行改进。

public class Server {
	private static final int PORT=8888;		//定义一个端口号
	public static void main(String[] args) throws Exception{
		//创建ServerSocket对象
		ServerSocket ss = new ServerSocket(PORT);  
		//使用while()循环不停的接收客户端发送的请求
		while(true) {
			//调用accpet()等待客户端的连接
			Socket s = ss.accept();		
			//下面用代码开启一个新线程
			new Thread() {
				public void run() {
					try {
						//获取客户端的输出流
						BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));  
						System.out.println("开始与客户端交互数据");	
						//当客户端接入后,向客户端输出数据
						bw.write("我是服务器,你好客户端!"); 
						//模拟置信其他功能占用的时间
						Thread.sleep(5000); 		
						System.out.println("结束与客户端交互数据");
						bw.flush();
						s.close();
						bw.close();
					} catch (Exception e) { 
						e.printStackTrace();
					}
				}
			}.start();
		}
	}
}

使用多线程的方式创建了一个服务器端程序。通过在while循环中调用accept()方法,不停地接收客户端发送的请求,而主线程仍然处于等待状态。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值