写点什么

终于有人把 TCP 协议与 UDP 协议给搞明白了

用户头像
编程菌
关注
发布于: 3 小时前
终于有人把TCP协议与UDP协议给搞明白了

网络编程有三个要素,分别是 IP 地址、端口号和通信协议,那本文主要讲述的是 TCP 与 UDP 这两种通信协议,以及编程的实现。

首先,我们需要了解一下 IP 地址、端口号、通信协议的相关知识。

一、IP 地址

网络中的计算机使用 IP 地址来进行唯一标识,IP 地址有 IPv4 和 IPv6 两种类型。IPv4 采用十进制或二进制表示形式,十进制是一种比较常用的表示形式,如 192.168.1.131,IPv6 采用十六进制表示形式,一般不常用。

如何查看 IP 地址相关信息:

在 Windows 系统下,打开 cmd,输入命令 ipconfig,按回车即可查看。在 Linux 或 Mac 系统下,打开终端,使用 ifconfig 命令,按回车即可查看。

二、端口号

端口号是计算机中的应用程序的一个整数数字标号,用来区分不同的应用程序。

0 ~ 1024 未被系统使用或保留的端口号,0 ~ 65535 为有效的端口号,也就是说我们要对一些程序定义端口号的时候,要选择 1024 ~ 65535 范围内的整数数字。

比如,以前学过的 MySQL 的端口号是 3306,SQLServer 的端口号是 1433,查了一下 Oracle 的端口号是 1521。

一定要把这些数据库对应的端口号,藏在深深的脑海里,以后在连接数据库的时候,会使用到端口号。

三、通信协议

说得通俗一点,通信协议就是网络通信中的规则,分为 TCP 协议和 UDP 协议两种。

第一种:TCP 协议

英文名:Transmission Control Protocol 中文名:传输控制协议 协议说明:TCP 是一种面向连接的、可靠的、基于字节流的传输层通信协议。

举例:打电话,需要双方都接通,才能进行对话

特点:效率低,数据传输比较安全

第二种:UDP 协议

英文名:User Datagram Protocol 中文名:数据报协议 协议说明:UDP 是一种面向无连接的传输层通信协议。

举例:发短信,不需要双方建立连接,But,数据报的大小应限制在 64k 以内

特点:效率高,数据传输不安全,容易丢包

四、三要素关系图与网络模型图

1、网络编程三要素关系图


注:图中端口号、IP 地址为演示,并非真实

2、OSI 参考模型与 TCP/IP 参考模型


五、TCP 编程

TCP 是基于字节流的传输层通信协议,所以 TCP 编程是基于 IO 流编程。

对于客户端,我们需要使用 Socket 类来创建对象。对于服务器端,我们需要使用 ServerSocket 来创建对象,通过对象调用 accept()方法来进行监听是否有客户端访问。

客户端与服务器端图解:


客户端与服务器端实现步骤:

前提:创建一个项目,在项目中创建两个模块(model),一个模块用来放客户端相关代码,一个模块用来放服务器端相关代码。

目录结构如下图


客户端

1、创建 Socket 对象,并指定服务器端应用程序的端口号和服务器端主机的 IP 地址。

2、使用 Socket 的对象调用 getOutputStream()方法来获取字节输出流对象。

3、调用字节输出流的 write(byte[] buf)或者 write(int b)向服务器发送指定数据。

4、记得关闭流。

服务器端

1、创建 ServerSocket 对象,并指定该应用程序的端口号,端口号必须和客户端指定的端口号一样。

2、使用 ServerSocket 对象的 accept()方法来监听客户端发送过来的请求,返回值为 Socket 对象。

3、调用 Socket 对象的 getInputStream()方法获取字节输入流对象

4、调用字节输入流对象的 read(byte[] buf)或 read()方法获取数据。

5、记得关闭流。

实例

客户端向服务器端发送信息,并显示在服务器端。

Client 类(客户端)

package cn.tkrnet.client;
import java.io.IOException;import java.io.OutputStream;import java.net.Socket;
public class Client { public static void main(String[] args) throws IOException {
//创建Socket对象,指定要发送到服务器端的IP地址,以及服务器端应用程序接收的端口号 //localhost代表本机IP地址 Socket client = new Socket("localhost",9000);
//获取输出流,用于向服务器端发送数据 OutputStream os = client.getOutputStream();
os.write("Java is my friend !".getBytes()); System.out.println("信息已发送");
//关闭流 os.close(); client.close(); }}
复制代码

Server 类(服务器端)

package cn.tkrnet.server;
import java.io.IOException;import java.io.InputStream;import java.net.ServerSocket;import java.net.Socket;
public class Server { public static void main(String[] args) throws IOException { System.out.println("--服务器端已开启--");
//创建ServerSocket对象,这里的端口号必须与客户端的端口号相同 ServerSocket server = new ServerSocket(9000);
//调用方法accept(),用来监听客户端发来的请求 Socket socket = server.accept();
//获取输入流对象 InputStream is = socket.getInputStream();
//读取输入流中的数据 int b = 0; while ((b =is.read()) != -1){ System.out.print((char)b); } //关闭流 is.close(); socket.close(); server.close(); }}
复制代码

提示:在运行程序时,一定要先运行服务器端的程序代码,再运行客户端的程序代码。因为客户端要向服务器发送请求,前提是服务器端要处于开启状态。

Server 类(服务器端)运行结果:

--服务器端已开启--
复制代码

Client 类(客户端)运行结果:

信息已发送
复制代码

lient 类(客户端)运行后,Server 类(服务器端)收到信息,运行结果:

--服务器端已开启--Java is my friend !
复制代码

实例分析:

服务器端启动后,服务器端的 accept()方法一直处于监听状态,直到客户端连接了服务器,服务器端再从流中读取客户端发来的数据。

恕我直言,这是一个超级无敌简单的单向通信实例。

六、UDP 编程

UDP 使用数据报进行数据传输,没有客户端与服务器端之分,只有发送方与接收方,两者哪个先启动都不会报错,但是会出现数据丢包现象。发送的内容有字数限制,大小必须限制在 64k 以内。

发送方与接收方实现步骤:

前提:创建一个项目,在项目中创建两个模块(model),一个模块用来放发送方相关代码,一个模块用来放接收方相关代码。

目录结构如下图



发送方

1、创建 DatagramSocket 对象,可以指定应用程序的端口号,也可以不指定。

2、准备需要发送的数据

3、创建 DatagramPacket 对象,用来对发送的数据进行打包,需要指定发送内容、发送多少、发送到哪里和接收方的端口号四个参数。

4、调用 DatagramSocket 对象的 send()方法发送数据。

5、记得关闭流。

接收方

1、创建 DatagramSocket 对象,指定接收方的端口号,这个必须指定。

2、创建一个 byte 类型数组,用来接收发送方发送过来的数据。

3、创建 DatagramPacket 对象,准备接收数据。

4、调用 DatagramSocket 对象的 receive()方法用于接收数据。

5、使用 String 类的构造方法将 byte 类型的数组中的数据转化成 String 类型并显示。

6、记得关闭流。

实例

发送方发送信息,接收方接收信息,并显示。

Sender 类(发送方)

package cn.tkrnet.Sender;
import java.io.IOException;import java.net.*;
public class Sender { public static void main(String[] args) throws IOException {
//创建接受或发送的数据报套接字,并指定发送方的端口号为7770 DatagramSocket ds = new DatagramSocket(7770); //端口号也可以不指定 System.out.println("---发送方---");
//创建数据报对象,用来发送数据 byte[] b = "Java is my friend !".getBytes();
//8800为接收方的端口号,netAddress.getByName("localhost")是获取主机的IP地址 DatagramPacket dp = new DatagramPacket(b,b.length, InetAddress.getByName("localhost"),7788);
ds.send(dp); //发送数据报 System.out.println("数据已发送"); //关闭流 ds.close(); }}
复制代码

Receiver 类(接收方)

package cn.tkrnet.receiver;
import java.io.IOException;import java.net.DatagramPacket;import java.net.DatagramSocket;
public class Receiver { public static void main(String[] args) throws IOException { System.out.println("---接收方---");
//创建数据报套接字对象,指定的端口号要和发送方发送数据的端口号相同 // (不是发送方的端口号7770,是发送方发送数据的端口号7788) DatagramSocket ds = new DatagramSocket(7788);
//创建接收数据报的对象 byte[] b = new byte[1024]; DatagramPacket dp = new DatagramPacket(b,b.length);
//接收数据 ds.receive(dp); System.out.println(new String(b,0,dp.getLength())); //关闭流 ds.close(); }}
复制代码

提示:在运行程序时,先运行发送方程序,还是先运行接收方程序都不会报错,但是有可能会出现数据丢包,一般我们都先运行接收方的程序代码,再运行发送方的程序代码。

Receiver 类(接收方)运行结果:

---接收方---
复制代码


Sender 类(发送方)运行结果:


---发送方---数据已发送
复制代码


Sender 类(发送方)运行后,Receiver 类(接收方)接收到信息,运行结果:


---接收方---Java is my friend !
复制代码


实例分析:


只有接收方先启动运行,才会存在端口号为 7788 的程序,发送方才能发送数据到指定端口号 7788,接收方才能接收数据。


不瞒你说,这也是个超级无敌简单的单向通信实例。

面试笔记+java 实战视频+电子版本书籍+面试资料文档传送门

用户头像

编程菌

关注

还未添加个人签名 2021.07.13 加入

还未添加个人简介

评论

发布
暂无评论
终于有人把TCP协议与UDP协议给搞明白了