本文主要讲述关于网络编程的一些基本知识。每篇文章都在认真完成,如果文中有出错的地方还请各位及时指出,在下感激不尽。
概述
既然要说网络编程,那么什么是网络呢?简单点说,两台或者两台以上计算机就组成了网络。比如说我想通过 QQ 和你聊天,那么就会涉及到两个问题:第一,如何在众多电脑中找到你?;第二,找到你之后如何找到你的 QQ,然后和你聊天?
要解决这两个问题就需要两个东西:IP 地址和端口号。每台电脑都会有自己的 IP 地址,通过它来找到指定的电脑;每个程序又有自己的端口号,通过 IP 找到指定的电脑之后再通过端口号找到该电脑上指定的程序。
那么聊天过程中底层就会进行数据传输,数据传输肯定是有一定的规范、协议的,不能胡来吧,常见的协议有 TCP、UDP协议。
底层的数据传输的简图如下图所示:
表面上看是在两台电脑间直接传输,实际过程如红线,经历了底层的实际数据传输过程。
那么底层的实际数据传输过程是怎样的呢?如下图所示:
上图中的 ISO/OSI 参考模型又叫七层协议,只是理论理解,实际并没有得到应用。比如说电脑 1 的数据传输从上到下依次经过七层,数据到达电脑 2 之后又从下到上依次经过七层(如图数据传输)。
但是实际应用主要是左边的模型。每层都有自己的规则,传输层有 UDP、TCP 协议,网络层有 IP 协议,这是最主要的几个协议,所以这个模型又叫 TCP/IP 协议。这篇文章主要讲的就是传输层的 UDP、TCP 协议。
UDP、TCP 协议如下图:
- TCP 协议:如上图所示,比如说两个人打电话,电话1 要把数据传输给电话 2,那么数据可以选择不同的道路然后到达电话 2,也就是说条条大路通罗马。 有人把 TCP 协议称为三次握手,就是说,首先电话 1 把数据传给电话 2 (第一次握手),然后电话 2 再传数据给电话 1 告诉电话 1 我收到你的数据了(第二次握手),然后电话 1 再给电话 2 传数据告诉电话 2 我收到你反馈的数据了(第三次握手)。
- UDP协议:比如说发短信,短信也是一条数据,UDP 协议就是说可以将数据分割成多份,每份独自进行传递,最后在目的地将分割的数据再收集起来。但是,UDP 有一个风险,就是分割之后的数据可能会存在走丢的情况,那么你发送的短信就存在对方收不到的风险。
TCP 协议 | UDP 协议 | |
---|---|---|
优点 | 安全可靠 | 可靠性低 |
缺点 | 消耗资源,效率低 | 简单,开销小 |
1. InetAddress,InetSocketAddress
先讲两个类 InetAddress 和 InetSocketAddress。
InetAddress 封装的是 IP,先上代码:
InetAddress 是一个类,如代码第 5 行所示,你如果想通过这种方式直接创建对象的话会有错误,The constructor InetAddress() is not visible,就是这个类根本就没有构造器。所以可以通过第 8 行的方式,调用 getByName() 方法,传进一个 IP 地址,然后这个方法会返回一个 InetAddress 类型的对象。getByName() 方法中可以传 IP 地址、计算机名、和 localhost(相当于传入本机的 IP 地址),然后通过产生的对象调用不同的方法得到相对应计算机的计算机名、IP 地址。
InetSocketAddress 可以传入 IP 地址和端口,代码如下:
InetSocketAddress 类可以直接创建对象然后传入 IP 地址和计算机名。
2. socket 套接字原理
如下图所示:
原理(TCP 协议单向传递数据):
客户端:
- 首先会根据 Socket 类创建 Socket 对象,该对象指定服务器端的 IP 和端口号。
- 然后应用层通过创建的 Socket 对象的输出流向对应的服务器端传递数据(因为已经给了 IP 地址和端口号)。传输层指定用什么协议传递 。
服务端:
- 会根据 ServerSocket 类创建 ServerSocket 对象,并给该对象传入一个端口号,这个端口号必须和客户端指定的端口号一致。
- 然后该对象等待接收传递来的信息,接收成功以后会返回一个 Socket 类型的对象(相当于成功接收信息之后创建了一个 Socket 类型的对象)。
- 然后服务器端通过该对象的输入流读取传递过来的数据。
这就是我个人理解的原理,理解了原理之后再写程序应该就没什么问题了。
3. 基于 TCP 的网络编程
注意:TCP的时候,必须先启动服务端,再启动客户端!!
3.1 单向通信
注意:本文中的代码实现的是用自己的电脑模拟两台计算机。
代码如下:
客户端:
服务端:
通过上面讲述的原理,然后再理解这两段代码应该没什么问题。如果有不理解的地方,对照着原理看代码,在此就不再赘述了。
3.2 双向通信
双向通信和单向通信本质上没什么区别,无非就是服务器端不仅能接收数据,还可以给客户端反馈数据;客户端不仅能发送数据,还能接收服务器端反馈回来的数据。
代码如下:
客户端:
对比单向通信的客户端会发现,就多了一段接收服务器反馈数据的代码。而接收反馈的数据还是要用 Socket 对象的输入流来接收,然后再结合其他的 IO 流来读取数据。
服务端:
同样的,对比单向通信中服务端代码可知,多了一段给客户端反馈数据的代码。而反馈数据同样是利用 Socket 对象的输出流,然后再结合其他的 IO 流来输出反馈信息。
3.3 对象流传送
功能:客户端发送用户名和密码给服务端,服务端判断对错之后给客户端进行反馈。
先上代码,如下:
客户端:
代码第 9 行到第 13 行实现键盘录入的功能。第 14 行通过对象流把对象传递给服务器端。第 16 行到第 18 行接收服务器端的反馈信息。
服务端:
代码第 10 行向下转型,将 Object 类型转化为 Person 类型的数据。第 15 行到第 19 行是对传进来的 Person 对象进行校验并给客户端反馈信息。
4. 基于 UDP 的网络编程
注意啦:
- TCP 的时候,必须先启动服务器,再启动客户端。但是在 UDP 中并不是这样。
- UDP 没有客户端和服务器的概念,只有发送方和接收方。
- UDP通信机制:通过数据包(又称数据报)来传递数据。
- 两个最重要的类:(1)DatagramSocket 此类用来发送和接收数据包的套接字;(2)DatagramPacket 此类表示数据包。
另外,
UDP 中不涉及 IO 流!
UDP 中不涉及 IO 流!
UDP 中不涉及 IO 流!
重要的事情说三遍。
原理(UDP 协议单向传递数据):
发送方:
- 创建套接字DatagramSocket(DatagramSocket ds=new DatagramSocket(xxxx);
),然后给套接字对象传入一个端口号,这个端口号是发送方的端口号! - 创建数据包:封装要发送的信息,IP,端口(接收方的端口)等(详见后面代码);
- 通过套接字将数据包传出去。
- 关闭套接字。
接收方:
- 创建套接字 DatagramSocket (DatagramSocket ds=new DatagramSocket(xxxx);),给套接字对象传入接收方的端口号。
- 创建数据包;
- 套接字对象将发送方传过来的东西接收到这个空的数据包中;
- 关闭套接字。
另外需要说的地方就是,与 TCP 不同,在UDP中可以先启动发送方,但是可能会出现丢包现象,就是一部分数据可能会丢失。
4.1 单向通信
代码如下:
发送方:
接收方:
|
|
参考上面的原理来理解这两段代码,其实都是按照上面说的步骤来的,没什么好讲解的地方吧。
4.2 双向通信
双向通信和单向通信本质上也没什么区别,无非就是接收方不仅能接收数据,还可以给发送方反馈数据;发送方不仅能发送数据,还能接收接收方端反馈回来的数据。
发送方:
与单向通信相比,多了第 16 行到第 19 行代码,创建数据包,套接字对象将接收方传过来的东西接收到这个空的数据包中,使发送方具备了接收的功能。
接收方:
代码第 14 行至第 16 行是程序具备了键盘录入的功能,不属于新知识点。第 17 行至第 19 行创建数据包封装要反馈的信息,IP,端口(发送方的端口)等(第 18 行),然后通过套接字将数据包传出去(第 19 行)。
网络编程就先写到这儿,欢迎补充。