1、计算机网路 --百度百科
计算机网络是指:将地理位置不同的具有独立功能的多台计算机及其外部设备,通过通信线路连接起来,在网络操作系统,网络管理软件及网络通信协议的管理和协调下,实现资源共享和信息传递的计算机系统。
从逻辑功能上看,计算机网络是以传输信息为基础目的,用通信线路将多个计算机连接起来的计算机系统的集合,一个计算机网络组成包括传输介质和通信设备。
虽然网络类型的划分标准各种各样,但是从地理范围划分是一种大家都认可的通用网络划分标准。按这种标准可以把各种网络类型划分为局域网(LocalArea Network, LAN)、城域网(Metropolitan Area Network,MAN)、广域网(Wide Area Network,WAN)和互联网(Internet,由无数的 LAN 和 WAN 组成)四种。
2、网络编程模式
在网络通信中主要有两种模式的通信方式:客户机/服务器(Client/Server)模式,简称为C/S 模式和浏览器/服务器(Browser/Server)模式,简称 B/S 模式。
1. Client/Server 模式
客户机、服务器以及网络三者之间的关系图,使用这种模式的程序很多,例如:qq、游戏等,需要在本机上安装一个客户端,服务器运行在开发公司的机房。
使用 C/S 模式的程序,在开发时需要分别针对客户端和服务器端进行专门开发。
优点:由于客户端是专门开发的,表现力会更强。缺点:通用性差,维护压力较大。
2. Browser/Server 模式
用户使用浏览器作为客户端的这种模式叫作浏览器/服务器模式。
优点:只需开发服务器端即可,开发压力较小,不需要维护客户端。缺点:对浏览器的限制比较大,表现力不强。
3、网络协议
为了减少网络设计的复杂性,绝大多数网络采用分层设计方法。分层设计方法,就是按照信息的流动过程将网络的整体功能分解为一个个的功能层,不同机器上的同等功能层之间采用相同的协议,同一机器上的相邻功能层之间通过接口进行信息传递。
网络上的计算机之间要通信就必须有一些约定,这些约定被称为网络通信协议。不同的计算机之间必须使用相同的通信协议才能进行通信。
网络模型一般是指OSI七层参考模型和TCP/IP四层参考模型。
开放系统互连参考模型 (Open System Interconnect 简称OSI)是国际标准化组织(ISO)和国际电报电话咨询委员会(CCITT)联合制定的开放系统互连参考模型,为开放式互连信息系统提供了一种功能结构的框架。
OSI先有模型后有协议,先有标准后进行实践;而TCP/IP则相反,先有协议和应用再提出了模型,且是参照的OSI模型。
TCP/IP(Transmission Control Protocol/Internet Protocol,传输控制协议/网际协议):TCP/IP协议是一个协议集合。所以统称为TCP/IP。在 TCP/IP 中包含一系列用于处理数据通信的协议:
- TCP (传输控制协议) - 应用程序之间通信
- UDP (用户数据包协议) - 应用程序之间的简单通信
- IP (网际协议) - 计算机之间和计算机网络之间的通信
- ICMP (因特网消息控制协议) - 针对错误和状态
- DHCP (动态主机配置协议) - 针对动态寻址
1. TCP(transmission control protocol)传输控制协议协议:
TCP 用于应用程序之间的通信。当应用程序通过TCP与另一个应用程序通信时,它会发送一个通信请求。这个请求必须被送到一个确切的地址。在双方“三次握手”之后,TCP 将在两个应用程序之间建立一个全双工 (full-duplex) 的通信。
这个全双工的通信将占用两个计算机之间的通信线路,直到它被一方或双方关闭为止,关闭时会经历四次挥手。
(1)TCP三次握手
所谓三次握手(Three-Way Handshake)即建立TCP连接,就是指建立一个TCP连接时,需要客户端和服务端总共发送3个包以确认连接的建立。
在socket编程中,这一过程由客户端执行connect来触发,整个流程如下图所示:
- SYN:同步标志。表明同步序列编号栏有效。
- ACK:确认标志。确认值(Acknowledgement),为1便是确认连接。
- ack:确认编号(Acknowledgement Number),即接收到的上一次远端主机传来的seq然后+1,再发送给远端主机。提示远端主机已经成功接收上一次所有数据。
- FIN:结束标志。
1)第一次握手:Client将标志位SYN置为1,随机产生一个值seq=J,并将该数据包发送给Server,Client进入SYN_SENT状态,等待Server确认。
2)第二次握手:Server收到数据包后由标志位SYN=1知道Client请求建立连接,Server将标志位SYN和ACK都置为1,ack=J+1,随机产生一个值seq=K,并将该数据包发送给Client以确认连接请求,Server进入SYN_RCVD状态。
3)第三次握手:Client收到确认后,检查ack是否为J+1,ACK是否为1,如果正确则将标志位ACK置为1,ack=K+1,并将该数据包发送给Server,Server检查ack是否为K+1,ACK是否为1,如果正确则连接建立成功,Client和Server进入ESTABLISHED状态。
完成三次握手,随后Client与Server之间可以开始传输数据了。
(2)TCP四次挥手
四次挥手(Four-Way Wavehand)即终止TCP连接,就是指断开一个TCP连接时,需要客户端和服务端总共发送4个包以确认连接的断开。
在socket编程中,这一过程由客户端或服务端任一方执行close来触发,整个流程如下图所示:
由于TCP连接时全双工的,因此,每个方向都必须要单独进行关闭,这一原则是当一方完成数据发送任务后,发送一个FIN来终止这一方向的连接,收到一个FIN只是意味着这一方向上没有数据流动了,即不会再收到数据了,但是在这个TCP连接上仍然能够发送数据,直到这一方向也发送了FIN。首先进行关闭的一方将执行主动关闭,而另一方则执行被动关闭,如上图。
1)第一次挥手:Client发送一个FIN,用来关闭Client到Server的数据传送,Client进入FIN_WAIT_1状态。
2)第二次挥手:Server收到FIN后,发送一个ACK给Client,确认序号为收到序号+1(与SYN相同,一个FIN占用一个序号),Server进入CLOSE_WAIT状态。
3)第三次挥手:Server发送一个FIN,用来关闭Server到Client的数据传送,Server进入LAST_ACK状态。
4)第四次挥手:Client收到FIN后,Client进入TIME_WAIT状态,接着发送一个ACK给Server,确认序号为收到序号+1,Server进入CLOSED状态,完成四次挥手。
(3)为什么建立连接是三次握手,而关闭连接却是四次挥手呢?
建立连接时,服务端收到客户端建立连接请求的SYN报文后,把ACK和SYN放在一个报文里发送给客户端。
关闭连接时,当收到对方的FIN报文时,仅仅表示对方不再发送数据了但是还能接收数据,己方也未必全部数据都发送给对方了,所以己方可以立即close,也可以发送一些数据给对方后,再发送FIN报文给对方来表示同意现在关闭连接,因此,己方ACK和FIN一般都会分开发送。
2. UDP(user data protocol)用户数据报协议:
Internet 协议集支持一个无连接的传输协议,该协议称为用户数据报协议(UDP,User Datagram Protocol)。
UDP 为应用程序提供了一种无需建立连接就可以发送封装的 IP 数据包的方法。
3. UDP与TCP区别:
TCP :面向连接(经历三次握手)、传输可靠(保证数据正确性,保证数据顺序)、用于传输大量数据(流模式)、速度慢,建立连接需要开销较多(时间,系统资源)。
UDP:面向非连接、传输不可靠(丢包[数据丢失])、用于传输少量数据(数据报包模式)、速度快。发送端和接收端
4. IP(Internet Protocol)协议
IP协议又称网际协议,是TCP/IP协议的核心。
它负责Internet上网络之间的通信,并规定了将数据报从一个网络传输到另一个网络所应遵循的规则。
IP协议不但定义了数据传输时的基本单元和格式,还定义了数据报的递交方法和路由选择。
此外,在TCP/IP网络中,主机之间进行通信所必需的地址,也是通过IP协议来实现的。
(1)IP地址
是指分配给用户上网使用的网际协议(英语:InternetProtocol,IP)的设备的数字标签。
IP地址是IP协议提供的一种统一的地址格式,它为互联网上的每一个网络和每一台主机分配一个逻辑地址,以此来屏蔽物理地址的差异。
在TCP/IP协议中,这个标识号就是IP地址,它可以唯一标识一台计算机,
目前,IP地址广泛使用的版本是IPv4,它是由4个字节大小的二进制数来表示,由于二进制形式表示的IP地址非常不便记忆和处理,因此通常会将IP地址写成十进制的形式,每个字节用一个十进制数字(0-255)表示,数字间用符号“.”分开,如 “192.168.1.100”。
随着计算机网络规模的不断扩大,对IP地址的需求也越来越多,IPV4这种用4个字节表示的IP地址面临枯竭,因此IPv6 便应运而生了,IPv6使用16个字节表示IP地址,它所拥有的地址容量是IPv4的接近8×10^28倍,达到2^128-1个(全零的不能用),这样就解决了网络地址资源数量不够的问题。
(2)端口号
通过IP地址可以连接到指定计算机,但如果想访问目标计算机中的某个应用程序,还需要指定端口号。
在计算机中,不同的应用程序是通过端口号区分的。
端口号是用两个字节(16位的二进制数)表示的,它的取值范围是0~65535,其中,0~1023之间的端口号用于一些知名的网络服务和应用,用户的普通应用程序需要使用1024以上的端口号,从而避免端口号被另外一个应用或服务所占用。
二、Java网络编程基础概念
网络编程的目的:就是直接或间接地通过网络协议与其他计算机进行通信。即通过使用套接字来达到进程间通信目的。
Java为网络编程提供了支持包 java.net,该包下提供了InetAddress、ULRDecoder、URLEncoder、URL和URLConnection等等很多工具类,这些类可以让我们通过编程的形式访问Web服务器或者其他的服务器。
Java的网络编程主要涉及到的内容是Socket编程,倒不如说是Java的I/O编程,因为整个过程中关于服务端和客户端的socket创建也就那么两三行代码,其余的都是操作字节流,字符流等数据传输。
1、什么是Socket套接字呢?
实现网络通信必须将两台计算机连接起来建立一个双向的通信链路,所以,源IP地址和目的IP地址以及源端口号和目的端口号的组合称为套接字。其用于标识客户端请求的服务器和服务。简单说,Socket套接字就是两台主机之间逻辑连接的端点。
套接字(Socket)是一个抽象出来的概念代表在端上的通信链路。
TPC/IP协议是传输层协议,主要解决数据如何在网络中传输,而HTTP是应用层协议,主要解决如何包装数据。Socket,本质上就是一组接口,是对TCP/IP协议的封装和应用(程序员层面上)。 .
2、网络编程三要素
IP地址、端口和协议(数据传递/交互的规则)
1. IP地址
在Java中,使用 java.net.InetAddress 类来表示IP地址
//方法等
public static void main(String[] args) throws IOException {
/**
* static InetAddress getLocalHost()
* 返回本地主机。
*/
InetAddress inetAddress = InetAddress.getLocalHost();
System.out.println(inetAddress); // administrator/192.68.69.10
/**
* String getHostName()
* 获取此IP地址的主机名。
*/
System.out.println(inetAddress.getHostName()); //administrator
/**
* String getHostAddress()
* 返回文本显示中的IP地址字符串。
*/
System.out.println(inetAddress.getHostAddress()); //192.68.69.10
/**
* byte[] getAddress()
* 返回此 InetAddress对象的原始IP地址。
*/
System.out.println(inetAddress.getAddress());
/**
* static InetAddress getByName(String host)
* 在给定主机名的情况下确定主机名称的IP地址。
*/
inetAddress = InetAddress.getByName("www.baidu.com");
System.out.println(inetAddress); //www.baidu.com/180.101.49.11
/**
* boolean isReachable(int timeout)
* 测试该地址是否可达。
*/
System.out.println(inetAddress.isReachable(3000)); //true
}
2. 端口(port)
在Java中,使用 java.net.InetSocketAddress 类来表示
//方法等
public static void main(String[] args) throws IOException {
/** 构造器
* InetSocketAddress(InetAddress addr, int port)
* 从IP地址和端口号创建套接字地址。
* InetSocketAddress(String hostname, int port)
* 从主机名和端口号创建套接字地址。
*/
//InetSocketAddress inetSocketAddress = new InetSocketAddress("127.0.0.1", 10000);
InetSocketAddress inetSocketAddress = new InetSocketAddress(InetAddress.getByName("www.baidu.com"), 10000);
/**
* String getHostName()
* 获得 hostname 。
*/
System.out.println(inetSocketAddress.getHostName()); //www.baidu.com
/**
* String getHostString()
* 如果没有主机名(使用文字创建),则返回主机名或地址的String形式。
*/
System.out.println(inetSocketAddress.getHostString()); //www.baidu.com
/**
* int getPort()
* 获取端口号。
*/
System.out.println(inetSocketAddress.getPort()); //10000
/**
* InetAddress getAddress()
* 获得 InetAddress 。
*/
System.out.println(inetSocketAddress.getAddress()); // www.baidu.com/180.101.49.12
}
3. 协议 (protocol)
协议(Protocol):网络协议的简称,是对数据格式和计算机之间交换数据时必须遵守的规则的正式描述。
在www上,每一信息资源都有统一且唯一的地址,即统一资源定位符。Uniform Resource Locator,简称URL, 如:https://localhost:8080/index.html ,有4部分组成。(协议,主机域名或IP,端口号,资源文件名)
网络三大基石:HTML,HTTP,URL
URI = URL+URN
URI:Uniform Resource Identifier ,统一资源标志符。
URL:Uniform Resource Locator,统一资源定位符。
URN:Uniform Resource Name,统一资源命名。
在Java中,使用 java.net.URL 类来表示URL
3、URLEncoder编码和URLDecoder解码
ULRDecoder和URLEncoder的主要作用是实现:普通字符串和application/x-www-form-urlencoded字符串相互转换的功能。
为什么会有这种转换呢?
网页的 URL 规定只能包含合法的字符,这可以分成两类。
URL 元字符:分号(;),逗号(’,’),斜杠(/),问号(?),冒号(:),at(@),&,等号(=), 加号(+),美元符号($),井号(#)
语义字符:a-z,A-Z,0-9,连词号(-),下划线(_),点(.),感叹号(!),波浪线(~),星号(*),单引号(‘),圆括号(())
除了以上字符,其他字符出现在 URL 之中都必须转义,规则是根据操作系统的默认编码,将每个字节转为百分号(%)加上两个大写的十六进制字母。比如,UTF-8 的操作系统上,
简单说一下乱码的场景和简单转换时的执行原理:
首先,form表单提示数据时,默认Content-type:为 application/x-www-form-urlencoded,当然也可以是:multipart/form-data ,multipart/form-data 一般用做form表单以流的形式提交数据时,则设置,enctype为该form-data形式,
不过呢,一般情况下,提交方式为application/x-www-form-urlencoded MIME编码, 当环境等等都已经配置为统一编码后,仍然出现汉字传到后台 被解码处理的情况时(也就是所谓的乱码 ),此时可以尝试,使用URLDecoder进行解码再转换,然后转换为汉字,当然在使用场景上,其实还是有很多情况下需要区分的。
普通字符串和application/x-www-form-urlencoded MIME类型字符串之间的相互转换。
public static void main(String[] args) throws IOException {
//获取平台默认的字符集
System.out.println(System.getProperty("file.encoding")); //UTF-8
String msg = "宝塔镇河妖abc";
//使用UTF-8编码
String msg1 = URLEncoder.encode(msg,"UTF-8");
System.out.println(msg1);//%E5%AE%9D%E5%A1%94%E9%95%87%E6%B2%B3%E5%A6%96abc
//使用UTF-8解码
String msg2 = URLDecoder.decode(msg1,"UTF-8");
System.out.println(msg2);//宝塔镇河妖abc
}
4、URL类和URLConnection类
1. URL类
在 java.net 包中包含专门用来处理 URL 的 URL类,可以获得 URL 的相关信息。
URL 的构造方法和常用方法:
//方法等具体查看API
public static void main(String[] args) throws IOException {
URL url = new URL("https://www.baidu.com");
//获取此的授权部分 URL 。
System.out.println(url.getAuthority());
//获取此 URL的文件名。
System.out.println(url.getFile());
//获取端口
System.out.println(url.getPort());
//获取主机
System.out.println(url.getHost());
//获得默认端口
System.out.println(url.getDefaultPort());
//获得路径
System.out.println(url.getPath());
//获取该 URL的userInfo部分。
System.out.println(url.getUserInfo());
}
2. URLConnection 类
在 java.net 包中,定义了专门的 URLConnection 类来表示与 URL 建立的通信连接。
URLConnection 类的对象使用 URL 类的 openConnection() 方法获得。
注意:我们在应用程序和URL链接的时候,使用URLConnection类。
当我们HTTP和URL连接的时候,使用URLConnection类的子类HttpURLConnection。
URLConnection 类的主要方法:
三、基于Socket的java网络编程
网络上的两个程序通过一个双向的通讯连接实现数据的交换,这个双向链路的一端称为一个Socket。Socket通常用来实现客户方和服务方的连接。Socket是TCP/IP协议的一个十分流行的编程界面,但是,Socket所支持的协议种类也不光TCP/IP一种,因此两者之间是没有必然联系的。
一个Socket由一个IP地址和一个端口号唯一确定。
Socket编程通信主要涉及到客户端和服务器端两个方面,首先是在服务器端创建一个服务器套接字(ServerSocket),并把它附加到一个端口上,服务器从这个端口监听连接。
客户端请求与服务器进行连接的时候,根据服务器的域名或者IP地址,加上端口号,打开一个套接字。当服务器接受连接后,服务器和客户端之间的通信就像输入输出流一样进行操作。
在Java环境下,Socket编程主要是指基于TCP/IP协议的网络编程。
1、简单的Client/Server程序
需求: 客户端连接服务端时,服务端向客户端发送消息
public class Server {
public static void main(String[] args) throws IOException {
// 1、创建服务器,指定端口 ServerSocket(int port)
ServerSocket serverSocket = new ServerSocket(10001);
// 2、接受连接该服务端的客户端对象,阻塞式
Socket client = serverSocket.accept();
System.out.println("一个客户端建立连接,IP:" + client.getInetAddress());
// 3、IO 操作
// 获取到客户端的输出流对象给客户端输出数据
boolean accept = true;
while (accept) {
String data = "服务器-->:" + client.getInetAddress() + "你来了";
PrintStream out = new PrintStream(client.getOutputStream());
out.print(data);
out.close();
}
// 4、关闭此套接字。
//serverSocket.close();
}
}
public class Client {
public static void main(String[] args) throws IOException {
// 1、创建客户端必须指定服务器的IP+端口,此时就在连接
Socket client = new Socket("127.0.0.1",10001);
// 2、IO操作,自动关闭流
// 获取客户端的输入流对象
Scanner sc = new Scanner(client.getInputStream());
while (sc.hasNextLine()) {
String str = sc.nextLine();
System.out.println(str);
}
sc.close();
// 3、关闭此套接字。
client.close();
}
}
参考文章:
Java - 网络编程完全总结
成为高手前必懂的TCP干货
计算机网络漫谈:OSI七层模型与TCP/IP四层(参考)模型
一文搞懂TCP与UDP的区别
Java Socket示例 发文件
ends~