TCP和UDP可以使用同一个端口号吗?

TCP和UDP可以使用同一个端口号吗?

首先说答案:可以。怎么理解呢?

我想这个问题要从计算机网络通信谈起,学过计算机网络的同学,可能都还记得7层或者4层网络模型,TCP/UDP属于其中的传输层协议,在传输层之下是网络层,网络层主要通过IP协议来进行通信,这也是我们日常程序开发中能够接触到的最底层了,再往下的数据链路层和物理层就不是我们这些普通程序员需要关心的了。

IP

我们先具体看下网络层。在IP网路层,发送者向接收者传输数据的时候,首先需要知道接收者的IP地址,IP地址可以在网络中唯一标识一台计算机,然后数据就可以根据IP协议抵达接收者所在的计算机,但是接收者所在的计算机上运行了几十个程序,计算机应该把这个数据交给哪个程序呢?

端口号

这就像快递员到达了一栋大楼,下一步它怎么把快递送到对应的用户手中呢?聪明的你一定想到了,那就是门牌号。

在计算机中,端口号就是门牌号。计算机的操作系统可以为不同的程序绑定不同的端口号,这样发送者发送数据时不仅要设置接收者的IP,还要加上接收者的端口号,如此接收者所在的计算机就能把数据转发给正确的程序了。

TCP/UDP

那么TCP和UDP能不能使用同一个端口号呢?其实在查找端口号之前还有一个传输层协议的处理过程,操作系统收到数据后,会先查看数据包使用的是TCP协议还是UDP协议,然后再根据协议进行不同的解析处理,提取到数据后,再转发到拥有对应端口的程序。

所以TCP和UDP是可以使用相同的端口号的,这在现实中也是常见的。比如 DNS(域名系统)可能需要同时支持 TCP 和 UDP 查询,这两种查询就都可以通过53这个标准端口来进行接收和响应。

但是在同一个传输协议下,端口号就不能相同了。如果相同,操作系统的协议栈就不知道该把这个数据包转给哪个程序了,这种设计会增加很多麻烦。

有的同学可能会观察到一个现象,那就是同一个计算机上的多个网站可以共享80或者443端口,这其实是应用层的能力,这些网站都寄宿在同一个Web服务器程序上,这个Web服务器程序绑定了80端口,Web服务器收到数据后再根据HTTP协议中的主机头(可以理解成域名)转发给不同的网站程序。

还有,如果你的电脑上有多个IP,那就更没有问题了。不同的IP代表不同的网络接口,即使都使用TCP协议,只要IP不同,端口号一样也完全不会冲突。

“IP+传输层协议+端口号”就是我们常说的套接字,它能确保数据从一个网络程序传递到另一个网络程序。大家如果直接使用TCP和UDP编程,就需要手动为套接字设置这几个参数。

示例

口说无凭,再给大家写个demo,使用go语言,简单易懂:

下边的程序会启动一个TCP服务器和一个UDP服务器,它们绑定相同的IP和端口号。这里为了方便测试,使用了127.0.0.1这个本机IP,你也可以换成局域网或者公网IP。

package mainimport ("fmt""net""os"
)func main() {// 定义监听的端口port := "127.0.0.1:12345"// 启动TCP服务器go startTCPServer(port)// 启动UDP服务器startUDPServer(port)
}func startTCPServer(port string) {// 通过TCP协议监听端口l, err := net.Listen("tcp", port)if err != nil {fmt.Println("Error listening:", err.Error())os.Exit(1)}defer l.Close()fmt.Println("TCP Server Listening on " + port)// 持续接收TCP数据for {conn, err := l.Accept()if err != nil {fmt.Println("Error accepting: ", err.Error())os.Exit(1)}fmt.Println("Received TCP connection")conn.Close()}
}func startUDPServer(port string) {// 通过UDP协议监听端口addr, err := net.ResolveUDPAddr("udp", port)if err != nil {fmt.Println("Error resolving: ", err.Error())os.Exit(1)}conn, err := net.ListenUDP("udp", addr)if err != nil {fmt.Println("Error listening: ", err.Error())os.Exit(1)}defer conn.Close()fmt.Println("UDP Server Listening on " + port)buffer := make([]byte, 1024)// 持续接收UDP数据for {n, _, err := conn.ReadFromUDP(buffer)if err != nil {fmt.Println("Error reading: ", err.Error())continue}fmt.Printf("Received UDP packet: %s\n", string(buffer[:n]))}
}

然后再创建两个客户端,一个是TCP客户端:

package mainimport ("fmt""net""os"
)func main() {// 连接到服务器conn, err := net.Dial("tcp", "localhost:12345")if err != nil {fmt.Println("Error connecting:", err.Error())os.Exit(1)}defer conn.Close()// 发送数据_, err = conn.Write([]byte("Hello TCP Server!"))if err != nil {fmt.Println("Error sending data:", err.Error())return}fmt.Println("Message sent to TCP server")
}

另一个是UDP客户端:

package mainimport ("fmt""net""os"
)func main() {ServerAddr, err := net.ResolveUDPAddr("udp", "localhost:12345")if err != nil {fmt.Println("Error resolving: ", err.Error())os.Exit(1)}conn, err := net.DialUDP("udp", nil, ServerAddr)if err != nil {fmt.Println("Error dialing: ", err.Error())os.Exit(1)}defer conn.Close()// 发送数据_, err = conn.Write([]byte("Hello UDP Server!"))if err != nil {fmt.Println("Error sending data:", err.Error())return}fmt.Println("Message sent to UDP server")
}

我们可以看到,客户端发起请求的时候都使用了 localhost:12345 这个目标地址,其中的localhost 实际上是个域名,它会被本地计算机解析为 127.0.0.1。这块不清楚的可以看我之前写的这篇:

实际运行效果如下:


最后总结下:在网络通信中,同一台计算机中,TCP和UDP协议可以使用相同的端口号。每个网络进程中的套接字地址都是唯一的,由三元组(IP地址,传输层协议,端口号)标识。操作系统会根据数据包中的传输层协议(TCP或UDP)以及端口号,将接收到的数据正确地交付给相应的应用程序。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/725006.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

浅析扩散模型与图像生成【应用篇】(七)——Prompt-to-Prpmpt

7. Prompt-to-Prompt Image Editing with Cross Attention Control 本文提出一种利用交叉注意力机制实现文本驱动的图像编辑方法,可以对生成图像中的对象进行替换,整体改变图像的风格,或改变某个词对生成图像的影响程度,如下图所示…

《程序员的职业迷宫:选择你的职业赛道》

程序员如何选择职业赛道? 大家好,我是小明,一名在编程迷宫中探索的程序员。作为这个庞大迷宫的探险者,我深知选择适合自己的职业赛道有多么重要。今天,我将分享一些关于如何选择职业赛道的心得,希望能够帮…

代码随想录算法训练营第一天|704.二分查找、27.移除元素

题目 704. 二分查找 相关企业 给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。 示例 1: 输入: nums [-1,0,3,5,9,12], tar…

标准C库函数之perror()、strerror(),以及他们之间各种的优缺点(打印错误信息)

标准C库函数之perror()、strerror(),以及他们之间各种的优缺点(打印错误信息) 前言 如果,想要深入的学习标准C库中perror、strerror函数,还是需要去自己阅读Linux系统中的帮助文档。 具体输入命令: man 3…

网络编程作业day6

数据库操作的增、删、改完成 #include <myhead.h>//查询的回调函数 int callback(void* data,int count,char** argv, char** columnName) {//count是字段数//argv是字段内容//columnName是字段名称for(int i0;i<count;i) {printf("%s%s\n", columnName[…

2024全国水科技大会暨新能源及电子行业废水论坛(十一)

一、会议背景 为深入学习贯彻《中共中央、国务院关于全面推进美丽中国建设的意见》&#xff0c;全面贯彻实施《固体废物污染环境防治法》、《“十四五”全国城市基础设施建设规划》&#xff0c;推进我国污泥处理工程建设&#xff0c;提高处理产物资源化利用水平&#xff0c;促进…

堆排序实现

在了解堆的一些性质后&#xff0c;我们可以根据这些性质来实现一个较优的算法&#xff0c;也就是堆排序。 堆排序&#xff0c;顾名思义就是排序&#xff0c;其运用到堆的各种性质。首先我们要创建一个堆&#xff0c;在原有数组上进行向上或者向下调整使其变成一个堆。那么这时…

typedef的详细理解

目录 1.typedef对整型指针进行重命名 2.typedef对数组指针进行重命名 3.typedef对函数指针进行重命名 总结&#xff1a;所有重新命名的函数名必须写在*号旁边。 1.typedef对整型指针进行重命名 代码如下&#xff1a; typedef int* pint; int main() {int* p NULL;pint p…

Python内置模块

目录 什么是模块 模块分类 通过模块创建者分类 系统内置模块 第三方模块 在线安装 离线安装 模块导入 math和random模块介绍 math模块 random模块 什么是模块 在我们编写程序时&#xff0c;需要导入包。例如随机数的产生&#xff0c;需要import random。import XXX&…

计算机基础专升本笔记-汇总笔记(三)常用文件格式

计算机基础专升本笔记-汇总笔记&#xff08;三&#xff09;常用文件格式 一、文本文件格式 扩展名&#xff08;后缀名&#xff09;文件类型docxWord2010文档dotxWord2010模版xlsxExcel2010文档xltxExcel2010模版pptxPower Point 演示文稿potxPower Point 2010模版ppsxPower P…

XGboost的整理

XGboost&#xff08;extreme gradient boosting&#xff09;:高效实现了GBDT算法并进行了算法和工程上的许多改进。 XGboost的思路&#xff1a; 目标&#xff1a;建立k个回归树&#xff0c;使得树群的预测尽量接近真实值&#xff08;准确率&#xff09;而且有尽量大的泛化能力…

Java项目:39 springboot008房屋租赁系统

作者主页&#xff1a;舒克日记 简介&#xff1a;Java领域优质创作者、Java项目、学习资料、技术互助 文中获取源码 项目介绍 房屋租赁系统的设计基于现有的网络平台&#xff0c;主要有管理员、房东、用户三个角色 管理员可以在线查看系统已有的人中心、房屋类型管理、房屋信息…

在 Android 中使用 Kotlin 调用动态库

在 Android 开发中&#xff0c;有时候需要使用原生代码来执行一些特定的任务&#xff0c;比如高性能计算、访问硬件或者使用现有的 C/C 库。通常&#xff0c;这样的原生代码会被编译成动态库&#xff08;.so 文件&#xff09;&#xff0c;然后在应用中被调用。 本篇博客将介绍…

创建java项目

文章目录 一、安装idea二、创建一个java项目1.设置名称 项目路径 安装JDK&#xff08;自己选择一个位置存放JDK&#xff09;2.创建完成之后 在src文件夹下创package包 再在包下创建Class类3. hellojava类创建完成设置打印语句 输出HelloJava 一、安装idea 官网地址 二、创建一…

不买后悔的阿里云服务器租用价格表_优惠活动整理_2024新版

2024阿里云服务器优惠活动政策整理&#xff0c;阿里云99计划ECS云服务器2核2G3M带宽99元一年、2核4G5M优惠价格199元一年&#xff0c;轻量应用服务器2核2G3M服务器61元一年、2核4G4M带宽165元1年&#xff0c;云服务器4核16G10M带宽26元1个月、149元半年&#xff0c;云服务器8核…

面试经典150题(105-107)

leetcode 150道题 计划花两个月时候刷完之未完成后转&#xff0c;今天&#xff08;第2天&#xff09;完成了3道(105-107)150 105.&#xff08;191. 位1的个数&#xff09;题目描述&#xff1a; 编写一个函数&#xff0c;输入是一个无符号整数&#xff08;以二进制串的形式&am…

simplex算法的代码实现

def pivot(N, B, A, b, c, v, l, e):N对应非基本元变量下标,B对应基本元变量下标,A对应非基本元在约束方程组中的系数相反数形成的矩阵,b对应约束条件中小于等于号右边的数值集合,c对应目标函数中变量系数形成的集合,v对应当前目标函数的取值,l对应转出变量下标在B中的位置,e…

使用Http请求下载文件带来的问题

java.io.IOException: Broken pipe 当使用http请求的方式将文件作为响应内容给浏览器&#xff0c;这个时候如果浏览器未开启自动下载(浏览器可能会终止这个tcp连接)&#xff0c;文件不会下载成功&#xff0c;但是这个时候请求已经到达服务器&#xff0c;如果这个时候&#xff0…

Dynamo初学常识梳理(四)——Revit图元

希望想学 Dynamo 的小伙伴坚持住&#xff0c;每天积累一点点知识&#xff0c;Dynamo 你很快就能上手的&#xff01;Dynamo 并不是你想的那样难学哦&#xff01; 今天要讲的是如何从 Dynamo 中获取 Revit 的图元&#xff0c;这些节点很常用&#xff0c;不需要全背下来&#xff0…

指针运算笔试题解析

题目1&#xff1a; int main() { int a[5] { 1, 2, 3, 4, 5 }; int* ptr (int*)(&a 1); printf("%d %d", *(a 1), *(ptr - 1)); return 0; } ptr中存放了整个数组的地址&#xff0c;ptr是int*类型&#xff0c;&a1跳到5的地址后又被强制类…