首页 > 其他分享 >TCP和UDP可以使用同一个端口号吗?

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

时间:2024-03-05 13:48:05浏览次数:25  
标签:UDP err fmt TCP Error 端口号

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 main

import (
    "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 main

import (
	"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 main

import (
	"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)以及端口号,将接收到的数据正确地交付给相应的应用程序。

标签:UDP,err,fmt,TCP,Error,端口号
From: https://www.cnblogs.com/bossma/p/18053847

相关文章

  • Win10电脑端口号怎么查看_Win10查看电脑端口号
    有些Win10用户想查看电脑端口号,但是不知道怎么查看,这篇文章是本站给大家带来的Win10电脑端口号查看方法。1、首先,按键盘上的【Win+X】组合键,或右键点击左下角的【开始菜单】,在打开的右键菜单项中,选择【运行】2、运行窗口,输入【cmd】命令,按【确定或回车】打开命令提示符窗口......
  • Qt 解决PLC与QModbusTcpClient通信自动断开
    项目场景:提示:这里简述项目相关背景:例如:项目场景:QModbusTcpClient通信问题描述提示:这里描述项目中遇到的问题:QModbusTcpClient连接后,稍微停一段时间,就会出现QModbusDevice::UnconnectedState原因分析:提示:这里填写问题的分析:1.网络原因2.服务器原因......
  • WIFI&蓝牙(ESP32)转CAN总线&串口TTL模块-B1-设备作为TCP客户端连接TCP服务器,实现RS48
    <p><iframename="ifd"src="https://mnifdv.cn/resource/cnblogs/ESP32_CAN"frameborder="0"scrolling="auto"width="100%"height="1500"></iframe></p>说明这节测试的是让设备连接路由器,然后设备以......
  • modbusTCP协议和TCP协议
    TCP最主要的特点TCP是面向连接的运输层协议。应用程序在使用TCP协议之前,必须先建立TCP连接。在传送数据完毕后,必须释放已经建立的TCP连接每一条TCP连接只能有两个端点,每一条TCP连接只能是点对点的(一对一)TCP提供可靠交付的服务。通过TCP连接传送的数据,无差错......
  • 什么是TCP/IP模型?
    什么是TCP/IP模型? TCP/IP 是传输控制协议/互联网协议的首字母缩写。我们刚才看到的OSI模型只是一个逻辑/参考模型。它的创建是为了通过将通信过程分解为更小、更易于管理的组件来定义通信系统的功能。但是,基于标准协议的TCP/IP概念是由国防部(DoD)在1960年代设计和开发......
  • unhide 是一款强大的取证工具,主要用于查找和发现被隐藏的进程、TCP/UDP端口以及其他隐
    unhide是一款强大的取证工具,主要用于查找和发现被隐藏的进程、TCP/UDP端口以及其他隐藏技术。其基本技术原理如下:ROOTKIT和LKM:ROOTKIT(RootKit)是一种恶意软件,常用于隐藏恶意活动和进程。它通过修改操作系统的核心组件和内核模块(LinuxKernelModule,LKM)来实现对系统的隐匿。u......
  • GNS3打开工程报错 --Dynamips error xxx:unable to create UDP NIO 解决方法
    GNS3打开工程报错--Dynamipserrorwhenrunningcommandxxx:unabletocreateUDPNIO报错原因:GNS3(v2.2)serverUDP连接端口号使用了10000-20000,NvidiaGeForceExperience也使用了相同的UDP端口号,发生冲突。解决方法:方法一:卸载NvidiaGeForceExperience,此过程不会......
  • Modbus和Modbus/TCP协议
    一.概述Modbus是MODICON公司与1979年开发的一种通讯协议,是一种工业现场总线协议标准。1996年施耐德公司推出了基于以太网TCP/IP的Modbus协议------ModbusTCP。Modbus协议是一项应用层报文传输协议,包括ASCII、RTU、TCP三种报文类型,协议本身并没有定义物理层,只是定义了控制器......
  • TCP握手与重发机制
    TCP通信时序 TCP三次握手1.客户端发送一个带SYN标志的TCP报文到服务器。这是三次握手过程中的段1。客户端发出段1,SYN位表示连接请求。序号是1000,这个序号在网络通讯中用作临时的地址,每发一个数据字节,这个序号要加1,这样在接收端可以根据序号排出数据包的正确顺序,也可以发现......
  • Qt QModbus相关类实现ModbusTcpServer总结
    在疫情环境下催生出了很多的无人或者减少人员接触的项目,比如无人智慧餐厅项目中的无人送餐项目,主要是由送餐小车和一个中控屏和部分协助发餐的设备组成,由于餐厅一般的范围不会很大,考虑到Wi-Fi通信可能比较麻烦,我们前期组网协议使用的是zigbee,这样的话小车可以无网络运行且待......