socket 地址复用 SO_REUSEADDR
背景
默认的情况下,如果一个网络应用程序的一个套接字 绑定了一个端口(例如888),这时候,别的套接字就无法使用这个端口( 888 )
ref : https://blog.csdn.net/tennysonsky/article/details/44062173
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int main(int argc, char *argv[])
{
int sockfd_one;
int err_log;
sockfd_one = socket(AF_INET, SOCK_DGRAM, 0); //创建UDP套接字one
if(sockfd_one < 0)
{
perror("sockfd_one");
exit(-1);
}
// 设置本地网络信息
struct sockaddr_in my_addr;
bzero(&my_addr, sizeof(my_addr));
my_addr.sin_family = AF_INET;
my_addr.sin_port = htons(8000); // 端口为8000
my_addr.sin_addr.s_addr = htonl(INADDR_ANY);
// 绑定,端口为8000
err_log = bind(sockfd_one, (struct sockaddr*)&my_addr, sizeof(my_addr));
if(err_log != 0)
{
perror("bind sockfd_one");
close(sockfd_one);
exit(-1);
}
int sockfd_two;
sockfd_two = socket(AF_INET, SOCK_DGRAM, 0); //创建UDP套接字two
if(sockfd_two < 0)
{
perror("sockfd_two");
exit(-1);
}
// 新套接字sockfd_two,继续绑定8000端口,绑定失败
// 因为8000端口已被占用,默认情况下,端口没有释放,无法绑定
err_log = bind(sockfd_two, (struct sockaddr*)&my_addr, sizeof(my_addr));
if(err_log != 0)
{
perror("bind sockfd_two");
close(sockfd_two);
exit(-1);
}
close(sockfd_one);
close(sockfd_two);
return 0;
}
那如何让sockfd_one, sockfd_two 两个套接字都能成功绑定8000端口呢?这时候就需要要到端口复用了。端口复用允许在一个应用程序可以把 n 个套接字绑在一个端口上而不出错。
同时,这 n 个套接字发送信息都正常,没有问题。但是,这些套接字并不是所有都能读取信息,只有最后一个套接字会正常接收数据。
端口复用最常用的用途应该是防止服务器重启时之前绑定的端口还未释放或者程序突然退出而系统没有释放端口。这种情况下如果设定了端口复用,则新启动的服务器进程可以直接绑定端口。如果没有设定端口复用,绑定会失败,提示ADDR已经在使用中。
SO_REUSEADDR
一般来说,一个端口释放后会等待两分钟之后才能再被使用,SO_REUSEADDR是让端口释放后立即就可以被再次使用
SO_REUSEADDR
用于对TCP套接字处于TIME_WAIT状态下的socket,才可以重复绑定使用
TCP,先调用close()的一方会进入TIME_WAIT状态
SO_REUSEADDR 提供如下四个功能:
- 允许启动一个监听服务器并捆绑其众所周知端口,即使以前建立的将此端口用做他们的本地端口的连接仍存在。这通常是重启监听服务器时出现,若不设置此选项,则bind时将出错
- 允许在同一端口上启动同一服务器的多个实例,只要每个实例捆绑一个不同的本地IP地址即可。对于TCP,我们根本不可能启动捆绑相同IP地址和相同端口号的多个服务器。
- 允许单个进程捆绑同一端口到多个套接口上,只要每个捆绑指定不同的本地IP地址即可。这一般不用于TCP服务器。
- SO_REUSEADDR允许完全重复的捆绑:
当一个IP地址和端口绑定到某个套接口上时,还允许此IP地址和端口捆绑到另一个套接口上。一般来说,这个特性仅在支持多播的系统上才有,而且只对UDP套接口而言(TCP不支持多播)。
SO_REUSEPORT选项
有如下语义:
此选项允许完全重复捆绑,但仅在想捆绑相同IP地址和端口的套接口都指定了此套接口选项才行。
如果被捆绑的IP地址是一个多播地址,则SO_REUSEADDR和SO_REUSEPORT等效。
使用这两个套接口选项的建议:
- 在所有TCP服务器中,在调用bind之前设置SO_REUSEADDR套接口选项;
- 当编写一个同一时刻在同一主机上可运行多次的多播应用程序时,设置SO_REUSEADDR选项,并将本组的多播地址作为本地IP地址捆绑
有关知识
设置端口复用函数要在绑定之前调用,而且只要绑定到同一个端口的所有套接字都得设置复用:
// sockfd_one, sockfd_two都要设置端口复用
// 在sockfd_one绑定bind之前,设置其端口复用
int opt = 1;
setsockopt( sockfd_one, SOL_SOCKET,SO_REUSEADDR, (const void *)&opt, sizeof(opt) );
err_log = bind(sockfd_one, (struct sockaddr*)&my_addr, sizeof(my_addr));
// 在sockfd_two绑定bind之前,设置其端口复用
opt = 1;
setsockopt( sockfd_two, SOL_SOCKET,SO_REUSEADDR,(const void *)&opt, sizeof(opt) );
err_log = bind(sockfd_two, (struct sockaddr*)&my_addr, sizeof(my_addr));
socket 地址复用 SO_REUSEADDR的更多相关文章
- UNIX网络编程——套接字选项(心跳检测、绑定地址复用)
/* 设置套接字选项周期性消息检测连通性 心跳包. 心博.主要用于长连接. * 参数:套接字, 1或0开启, 首次间隔时间, 两次间隔时间, 断开次数 */ void setKeepAlive( in ...
- 【 socke】C# socket端口复用-多主机头绑定
什么是端口复用: 因为在winsock的实现中,对于服务器的绑定是可以多重绑定的,在确定多重绑定使用谁的时候,根据一条原则是谁的指定最明确则将包递交给谁,而且没有权限之分.这种多重绑定便称之为端口复用 ...
- 在C#中实现Socket端口复用
转载:http://www.csharpwin.com/csharpspace/68.shtml 一.什么是端口复用: 因为在winsock的实现中,对于服务器的绑定是可以多重绑定的,在 ...
- 转载:C# socket端口复用-多主机头绑定
什么是端口复用: 因为在winsock的实现中,对于服务器的绑定是可以多重绑定的,在确定多重绑定使用谁的时候,根据一条原则是谁的指定最明确则将包递交给谁,而且没有权限之分.这种多重绑定便称之为端口复用 ...
- SOCKET 地址
地址格式: 函数bind和getsockname使用通用数据类型:struct sockaddr*来指向socket地址. #incude <sys/socket.h> struct so ...
- linux socket中的SO_REUSEADDR
Welcome to the wonderful world of portability... or rather the lack of it. Before we start analyzing ...
- Linux网络编程-----Socket地址API
(1) 通用socket地址 socket网络编程接口中表示socket地址的是结构体sockaddr,其定义如下: #include<bits/socket.h> struct sock ...
- 2. socket结构体——表示socket地址
一.两种通用socket结构体 1. sockaddr struct sockaddr { sa_family_t sa_family; // 地址族 char sa_data[14]; // 存放s ...
- 为什么DRAM采用地址复用技术?为什么SRAM不采用地址复用技术?
行列地址复用:比如你的存储器容量是16bit,那么可以将这16个比特组织成一个4*4的矩阵,为了找到某个你想要找的bit,比如第1行第2列的那个bit.你先发送二进制的01,表示要找的数据在第1行:接 ...
- socket 编程的端口和地址复用
在linux socket网络编程中,大规模并发TCP或UDP连接时,经常会用到端口复用: int opt = 1; if(setsockopt(sockfd, SOL_SOCKET,SO_R ...
随机推荐
- Angular cli 组件和服务的创建, 父传子,子传父,服务的简单使用
1:Angular cli 创建组件component ng g component components\right ng g c wave 简写 需要定位到根路径下即可创建组件 Could not ...
- .NET静态代码织入——肉夹馍(Rougamo)发布3.0
肉夹馍(https://github.com/inversionhourglass/Rougamo)通过静态代码织入方式实现AOP的组件,其主要特点是在编译时完成AOP代码织入,相比动态代理可以减少应 ...
- vue3早已具备抛弃虚拟DOM的能力了
前言 jquery时代更新视图是直接对DOM进行操作,缺点是频繁操作真实 DOM,性能差.react和vue时代引入了虚拟DOM,更新视图是对新旧虚拟DOM树进行一层层的遍历比较,然后找出需要更新的D ...
- 04.2 go-admin前后端打包为一个服务上线
目录 一.思路: 二.打包go-admin-ui为静态文件 a.修改配置文件 b.打包 c.复制dist到go-admin的static目录里 三.配置go-admin a.配置路由 b.访问页面 视 ...
- redis rdb数据持久化
面试和工作,持久人都是重点! Redis是内存数据库,如果不将内存中的数据库状态保存到磁盘,那么一旦服务器进程退出,服务器中的数据库状态也会消失.所以Redis提供了持久化功能! RDB(Redis ...
- ansible系列(26)--ansible的tags标签
目录 1. tags标签 1.1 指定执行某个tags 1.2 指定排除某个tags 1. tags标签 默认情况下, Ansible 在执行一个 playbook 时,会执行 playbook 中所 ...
- WEB服务与NGINX(9)-NGINX作为下载服务器的相关配置
目录 1. NGINX的目录索引功能 2. NGINX的限速功能 2.1 限制下载速度 2.2 限制单位时间内产生的http请求数 2.3 限制客户端同一时刻的并发连接数 1. NGINX的目录索引功 ...
- csapp-attacklab(完美解决版)
注意:必须阅读Writeup,否则根本看不懂这个lab要怎么做 实验前准备 1.在终端中输入./ctarget和./rtarget结果报错 百度后得知自学的同学需要在执行文件时加上-q参数,不发送结果 ...
- CentOS7部署Docker(联网)
一.参考地址 https://blog.csdn.net/m0_49762804/article/details/131398587 二.Docker安装 安装依赖环境,yum-utils ## 检查 ...
- 经验分享:春招零Offer,5月份还有机会吗?
先说答案:5 月份依然有拿到 Offer 的机会. 5月份春招结束了吗? 对于应届大学生来说(也就是今年暑假毕业的学生),5 月中旬春招就陆续结束了,但是 5 月份会有很多补录的机会. 对于非应届的大 ...