关于网络编程的3个问题

news2024/11/24 0:00:31

一、TCP 和 UDP 可以同时绑定相同的端口吗?

答案:可以的

在数据链路层中,通过 MAC 地址来寻找局域网中的主机。在网络层中,通过 IP 地址来寻找网络中互连的主机或路由器。在传输层中,需要通过端口进行寻址,来识别同一计算机中同时通信的不同应用程序

所以,传输层的「端口号」的作用,是为了区分同一个主机上不同应用程序的数据包。

传输层有两个传输协议分别是 TCP 和 UDP,在内核中是两个完全独立的软件模块。

当主机收到数据包后,可以在 IP 包头的「协议号」字段知道该数据包是 TCP/UDP,所以可以根据这个信息确定送给哪个模块(TCP/UDP)处理,送给 TCP/UDP 模块的报文根据「端口号」确定送给哪个应用程序处理。

可以看到,数据的传输是一个五元组(源地址,目标地址,源端口号,目标端口号,数据传输协议),所以说可以同时监听一个端口号。

因此, TCP/UDP 各自的端口号也相互独立,如 TCP 有一个 80 号端口,UDP 也可以有一个 80 号端口,二者并不冲突。

二、多个 TCP 服务进程可以绑定同一个端口吗?

可以,需要在创建socket时,设置SO_REUSEADDR

还是以前面的 TCP 服务端程序作为例子,启动两个同时绑定同一个端口的 TCP 服务进程。

运行第一个 TCP 服务进程之后,netstat 命令可以查看,8888 端口已经被一个 TCP 服务进程绑定并监听了,如下图:

接着,运行第二个 TCP 服务进程的时候,就报错了“Address already in use”。

我上面的测试案例是两个 TCP 服务进程同时绑定地址和端口是:0.0.0.0 地址和8888端口,所以才出现的错误。

如果两个 TCP 服务进程绑定的 IP 地址不同,而端口相同的话,也是可以绑定成功的。

所以,默认情况下,针对「多个 TCP 服务进程可以绑定同一个端口吗?」这个问题的答案是:如果两个 TCP 服务进程同时绑定的 IP 地址和端口都相同,那么执行 bind() 时候就会出错,错误是“Address already in use”。

注意,如果 TCP 服务进程 A 绑定的地址是 0.0.0.0 和端口 8888,而如果 TCP 服务进程 B 绑定的地址是 192.168.1.100 地址(或者其他地址)和端口 8888,那么执行 bind() 时候也会出错。

这是因为 0.0.0.0 地址比较特殊,代表任意地址,意味着绑定了 0.0.0.0 地址,相当于把主机上的所有 IP 地址都绑定了。

重启 TCP 服务进程时,为什么会有“Address in use”的报错信息?

TCP 服务进程需要绑定一个 IP 地址和一个端口,然后就监听在这个地址和端口上,等待客户端连接的到来。然而在实践中,我们可能会经常碰到一个问题,当 TCP 服务进程重启之后,总是碰到“Address in use”的报错信息,TCP 服务进程不能很快地重启,而是要过一会才能重启成功。

这是为什么呢?

当我们重启 TCP 服务进程的时候,意味着通过服务器端发起了关闭连接操作,于是就会经过四次挥手,而对于主动关闭方,会在 TIME_WAIT 这个状态里停留一段时间,这个时间大约为 2MSL。

当 TCP 服务进程重启时,服务端会出现 TIME_WAIT 状态的连接,TIME_WAIT 状态的连接使用的 IP+PORT 仍然被认为是一个有效的 IP+PORT 组合,相同机器上不能够在该 IP+PORT 组合上进行绑定,那么执行 bind() 函数的时候,就会返回了 Address already in use 的错误

而等 TIME_WAIT 状态的连接结束后,重启 TCP 服务进程就能成功。

重启 TCP 服务进程时,如何避免“Address in use”的报错信息?

我们可以在调用 bind 前,对 socket 设置 SO_REUSEADDR 属性,可以解决这个问题。

int on = 1;

setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));

因为 SO_REUSEADDR 作用是:如果当前启动进程绑定的 IP+PORT 与处于TIME_WAIT 状态的连接占用的 IP+PORT 存在冲突,但是新启动的进程使用了 SO_REUSEADDR 选项,那么该进程就可以绑定成功。

举个例子,服务端有个监听 0.0.0.0 地址和 8888 端口的 TCP 服务进程。‍

有个客户端(IP地址:192.168.1.100)已经和服务端(IP 地址:172.19.11.200)建立了 TCP 连接,那么在 TCP 服务进程重启时,服务端会与客户端经历四次挥手,服务端的 TCP 连接会短暂处于 TIME_WAIT 状态:

客户端地址:端口           服务端地址:端口        TCP 连接状态

192.168.1.100:37272          172.19.11.200:8888    TIME_WAIT

如果 TCP 服务进程没有对 socket 设置 SO_REUSEADDR 属性,那么在重启时,由于存在一个和绑定 IP+PORT 一样的 TIME_WAIT 状态的连接,那么在执行 bind() 函数的时候,就会返回了 Address already in use 的错误。

如果 TCP 服务进程对 socket 设置 SO_REUSEADDR 属性了,那么在重启时,即使存在一个和绑定 IP+PORT 一样的 TIME_WAIT 状态的连接,依然可以正常绑定成功,因此可以正常重启成功。

因此,在所有 TCP 服务器程序中,调用 bind 之前最好对 socket 设置 SO_REUSEADDR 属性,这不会产生危害,相反,它会帮助我们在很快时间内重启服务端程序。‍

前面我提到过这个问题:如果 TCP 服务进程 A 绑定的地址是 0.0.0.0 和端口 8888,而如果 TCP 服务进程 B 绑定的地址是 192.168.1.100 地址(或者其他地址)和端口 8888,那么执行 bind() 时候也会出错。

这个问题也可以由 SO_REUSEADDR 解决,因为它的另外一个作用是:绑定的 IP地址 + 端口时,只要 IP 地址不是正好(exactly)相同,那么允许绑定。

比如,0.0.0.0:8888 和192.168.1.100:8888,虽然逻辑意义上前者包含了后者,但是 0.0.0.0 泛指所有本地 IP,而 192.168.1.100 特指某一IP,两者并不是完全相同,所以在对 socket 设置 SO_REUSEADDR 属性后,那么执行 bind() 时候就会绑定成功。

PS:如果想多个进程绑定相同的 IP 地址和端口,也是有办法的,就是对 socket 设置 SO_REUSEPORT 属性(内核 3.9 版本提供的新特性),本文不对 SO_REUSEPORT 做具体介绍,感兴趣的同学自行去学习。

三、客户端的端口可以重复使用吗?

在客户端执行 connect 函数的时候,只要客户端连接的服务器不是同一个,内核允许端口重复使用。

TCP 连接是由四元组(源IP地址,源端口,目的IP地址,目的端口)唯一确认的,那么只要四元组中其中一个元素发生了变化,那么就表示不同的 TCP 连接的。

所以,如果客户端已使用端口 64992 与服务端 A 建立了连接,那么客户端要与服务端 B 建立连接,还是可以使用端口 64992 的,因为内核是通过四元祖信息来定位一个 TCP 连接的,并不会因为客户端的端口号相同,而导致连接冲突的问题。

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

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

相关文章

【DP】最长上升公共子序列

一.题目来源 272. 最长公共上升子序列 - AcWing题库 二.简要思路 这道题易知是最长上升子序列(LIS)和最长公共子序列(LCS)的综合应用。我们可以先求最长公共子序列,然后再内循环最长上升子序列即可,直接看…

【ES专题】ElasticSearch搜索进阶

目录 前言阅读导航前置知识特别提醒笔记正文一、分词器详解1.1 基本概念1.2 分词发生的时期1.3 分词器的组成1.3.1 切词器&#xff1a;Tokenizer1.3.2 词项过滤器&#xff1a;Token Filter1.3.3 字符过滤器&#xff1a;Character Filter 1.4 倒排索引的数据结构 <font color…

《基于先验未知盲反卷积技术的包络谱重复瞬态的循环平稳性提取》阅读笔记及代码整理

论文阅读笔记及代码整理 《Extracting cyclo-stationarity of repetitive transients from envelope spectrum based on prior-unknown blind deconvolution technique》 代码有优化整理过&#xff0c;需要请下载&#xff1a;https://mbd.pub/o/bread/ZZaTl5ht 贡献&#xff1…

文件如何变成下载链接?

文件如何变成下载链接&#xff1f;有时候工作需要&#xff0c;要把一些文档&#xff08;比如Word&#xff0c;Excel&#xff0c;PPT&#xff0c;PDF等&#xff09;转成下载链接&#xff0c;作为公众号文章的附件&#xff0c;给粉丝们下载。 把文件转成下载链接&#xff0c;有几…

vue生命周期总结

包含页面的生命周期以及路由的生命周期 页面内&#xff1a; <script> export default {name: "",data() {return {value: "路由页面",};},// 组件不具有此钩子beforeRouteEnter(to, from, next) {console.log("beforeRouteEnter",this);/…

IntelliJ IDEA 2023 最新版如何试用?IntelliJ IDEA 2023最新版试用方法及验证ja-netfilter配置成功提示

&#x1f337;&#x1f341; 博主猫头虎 带您 Go to New World.✨&#x1f341; &#x1f984; 博客首页——猫头虎的博客&#x1f390; &#x1f433;《面试题大全专栏》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &a…

Langchain-Chatchat项目:4.1-P-Tuning v2实现过程

常见参数高效微调方法(Parameter-Efficient Fine-Tuning&#xff0c;PEFT)有哪些呢&#xff1f;主要是Prompt系列和LoRA系列。本文主要介绍P-Tuning v2微调方法。如下所示&#xff1a; Prompt系列比如&#xff0c;Prefix Tuning(2021.01-Stanford)、Prompt Tuning(2021.09-Goo…

OpenGL_Learn04

我这边并不是教程&#xff0c;只是学习记录&#xff0c;方便后面回顾&#xff0c;代码均是100%可以运行成功的。 1. 渐变三角形 #include <glad/glad.h> #include <GLFW/glfw3.h>#include <iostream> #include <cmath>void framebuffer_size_callba…

科学计数法 [极客大挑战 2019]BuyFlag1

打开题目 注意中说&#xff0c;我们需要买flag&#xff0c;首先必须是cuit的学生&#xff0c;其次必须输对正确的密码 查看源代码得到 代码审计 首先&#xff0c;检查是否存在名为 password 的POST请求。 如果 password 存在&#xff0c;将其存储在变量 $password 中。 然后…

你没有见过的 git log 风格

背景 git大家都不陌生&#xff0c;git log 也是大家经常用的指令&#xff0c;今天分享三种 git log的美化格式&#xff0c;大家看看哪种更易读。 git log -15 --graph --decorate --oneline 带有 pretty 格式的git log 风格 log --color --graph --prettyformat:‘%Cred%h%C…

【音视频 | Ogg】RFC3533 :Ogg封装格式版本 0(The Ogg Encapsulation Format Version 0)

&#x1f601;博客主页&#x1f601;&#xff1a;&#x1f680;https://blog.csdn.net/wkd_007&#x1f680; &#x1f911;博客内容&#x1f911;&#xff1a;&#x1f36d;嵌入式开发、Linux、C语言、C、数据结构、音视频&#x1f36d; &#x1f923;本文内容&#x1f923;&a…

Vue3入门指南:零基础小白也能轻松理解的学习笔记

文章目录 创建项目开发环境项目目录模板语法属性绑定条件渲染列表渲染事件处理内联事件处理器方法事件处理器&#xff08;常用&#xff09; 事件参数获取 event 事件事件传参 事件修饰符阻止默认事件阻止事件冒泡 数组变化侦测变更方法替换一个数组 计算属性class 绑定单对象绑…

汽车标定技术(一):XCP概述

目录 1.汽车标定概述 2.XCP协议由来及版本介绍 3.XCP技术通览 3.1 XCP上下机通信模型 3.2 XCP指令集 3.2.1 XCP帧结构定义 3.2.2 标准指令集 3.2.3 标定指令集 3.2.4 页切换指令集 3.2.5 数据采集指令集 3.2.6 刷写指令集 3.3 ECU描述文件(A2L)概述 3.3.1 标定上位…

无限上下文,多级内存管理!突破ChatGPT等大语言模型上下文限制

目前&#xff0c;ChatGPT、Llama 2、文心一言等主流大语言模型&#xff0c;因技术架构的问题上下文输入一直受到限制&#xff0c;即便是Claude 最多只支持10万token输入&#xff0c;这对于解读上百页报告、书籍、论文来说非常不方便。 为了解决这一难题&#xff0c;加州伯克利…

物联网AI MicroPython传感器学习 之 QMC5883指南针罗盘传感器

学物联网&#xff0c;来万物简单IoT物联网&#xff01;&#xff01; 一、产品简介 QMC5883是一款表面贴装的集成了信号处理电路的三轴磁性传感器&#xff0c;应用场景主要包括罗盘、导航、无人机、机器人和手持设备等一些高精度的场合。 引脚定义 VCC&#xff1a;3V3&#…

【Java 进阶篇】Java ServletContext详解:获取MIME类型

MIME&#xff08;Multipurpose Internet Mail Extensions&#xff09;类型是一种标识文件类型的文本标签&#xff0c;通常用于指示浏览器如何处理Web服务器返回的文件。在Java Web应用程序中&#xff0c;ServletContext对象提供了一种方便的方法来获取文件的MIME类型。本篇博客…

【实战Flask API项目指南】之五 RESTful API设计

实战Flask API项目指南之 RESTful API设计 本系列文章将带你深入探索实战Flask API项目指南&#xff0c;通过跟随小菜的学习之旅&#xff0c;你将逐步掌握 Flask 在实际项目中的应用。让我们一起踏上这个精彩的学习之旅吧&#xff01; 前言 当小菜踏入Flask后端开发的世界时…

Redis-命令操作Redis

&#x1f3ac; 艳艳耶✌️&#xff1a;个人主页 &#x1f525; 个人专栏 &#xff1a;《Spring与Mybatis集成整合》《Vue.js使用》 ⛺️ 越努力 &#xff0c;越幸运。 1.Redis简介 1.1.什么是Redis Redis是一个开源&#xff08;BSD许可&#xff09;&#xff0c;内存存储的数据…

费用预算管理系统

费用预算管理系统 1. 模块概述 《费用管理》以企业费用管理为核心&#xff0c;围绕费用支出审批流程&#xff0c;从费用发生前的事前申请&#xff0c;报销单据审批、付款单据审批&#xff0c;再到出纳付款、会计记账等所有工作流程都在系统中全员、协同完成&#xff1b;并且能…

el-table中的el-input标签修改值,但界面未更新,解决方法

el-table中的el-input标签修改值&#xff0c;界面未更新 在el-table中的el-input里面写的change事件根本不触发&#xff0c;都不打印&#xff0c;试了网络上各种方法都没用 然后换成input事件&#xff0c;input事件会触发&#xff0c;但界面也未更新。我在触发事件的时候&…