Socket中SO_REUSEADDR详解
1、一般来说,一个端口释放后会等待两分钟之后才能再被使用,SO_REUSEADDR是让端口释放后立即就可以被再次使用。
SO_REUSEADDR用于对TCP套接字处于TIME_WAIT状态下的socket,才可以重复绑定使用。server程序总是应该在调用bind()之前设置SO_REUSEADDR套接字选项。TCP,先调用close()的一方会进入TIME_WAIT状态
2、SO_REUSEADDR和SO_REUSEPORT
SO_REUSEADDR提供如下四个功能:
SO_REUSEADDR允许启动一个监听服务器并捆绑其众所周知端口,即使以前建立的将此端口用做他们的本地端口的连接仍存在。这通常是重启监听服务器时出现,若不设置此选项,则bind时将出错。
SO_REUSEADDR允许在同一端口上启动同一服务器的多个实例,只要每个实例捆绑一个不同的本地IP地址即可。对于TCP,我们根本不可能启动捆绑相同IP地址和相同端口号的多个服务器。
SO_REUSEADDR允许单个进程捆绑同一端口到多个套接口上,只要每个捆绑指定不同的本地IP地址即可。这一般不用于TCP服务器。
SO_REUSEADDR允许完全重复的捆绑:当一个IP地址和端口绑定到某个套接口上时,还允许此IP地址和端口捆绑到另一个套接口上。一般来说,这个特性仅在支持多播的系统上才有,而且只对UDP套接口而言(TCP不支持多播)。
SO_REUSEPORT选项有如下语义:
此选项允许完全重复捆绑,但仅在想捆绑相同IP地址和端口的套接口都指定了此套接口选项才行。
如果被捆绑的IP地址是一个多播地址,则SO_REUSEADDR和SO_REUSEPORT等效。
使用这两个套接口选项的建议:
在所有TCP服务器中,在调用bind之前设置SO_REUSEADDR套接口选项;
当编写一个同一时刻在同一主机上可运行多次的多播应用程序时,设置SO_REUSEADDR选项,并将本组的多播地址作为本地IP地址捆绑。
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
(const void *)&nOptval , sizeof(int)) < 0) ...
编写 TCP/SOCK_STREAM 服务程序时,SO_REUSEADDR到底什么意思?
这个套接字选项通知内核,如果端口忙,但TCP状态位于 TIME_WAIT ,可以重用端口。如果端口忙,而TCP状态位于其他状态,重用端口时依旧得到一个错误信息,
指明"地址已经使用中"。如果你的服务程序停止后想立即重启,而新套接字依旧使用同一端口,此时SO_REUSEADDR 选项非常有用。必须意识到,此时任何非期望数据到达,
都可能导致服务程序反应混乱,不过这只是一种可能,事实上很不可能。
一个套接字由相关五元组构成,协议、本地地址、本地端口、远程地址、远程端口。SO_REUSEADDR 仅仅表示可以重用本地本地地址、本地端口,整个相关五元组还是唯一确定的。所以,重启后的服务程序有可能收到非期望数据。必须慎重使用SO_REUSEADDR 选项。
我们假设是客户执行主动关闭并进入 TIME_WAIT ,这是正常的情况,因为服务器通常执行被动关闭,不会进入 TIME_WAIT 状态。这暗示如果我们终止一个客户程序,并立即重新启动这个客户程序,则这个新客户程序将不能重用相同的本地端口。这不会带来什么问题,因为客户使用本地端口,而并不关心这个端口号是什么。然而,对于服务器,情况就有所不同,因为服务器使用周知端口。如果我们终止一个已经建立连接的服务器程序,并试图立即重新启动这个服务器程序,服务器程序将不能把它的这个周知端口赋值给它的端点,因为那个端口是处于 2MSL 连接的一部分。在重新启动服务器程序前,它需要在 1~4 分钟。这就是很多网络服务器程序被杀死后不能够马上重新启动的原因(错误提示为“ Address already in use ”)。
int Net::tcp_listen(unsigned short port)
{
int fd, one = 1;
struct sockaddr_in sa_in;
if ((fd = socket(PF_INET, SOCK_STREAM, 0)) < 0)
return -1;
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) < 0) {
close(fd);
return -1;
}
set_nonblocking(fd, 0);
bzero(&sa_in, sizeof(sa_in));
sa_in.sin_family = AF_INET;
sa_in.sin_port = htons(port);
sa_in.sin_addr.s_addr = INADDR_ANY;
bind(fd, (struct sockaddr *)&sa_in, sizeof(sa_in));
listen(fd, 1024);
global->PRINTF("Listen on port:%d, fd:%d\n", port, fd);
return fd;
}
设置SO_REUSEADDR选项
在第11章,"并发客户端服务器"的第一部分中,提供并测试了一个使用fork系统调用设计的服务器。图12.1显示了在一个telnet命令与服务器建立连接之后的三个步骤。
这些步骤如下:
1 启动服务器进程(PID 926)。他监听客户端连接。
2 启动客户端进程(telnet命令),并且连接到服务器进程(PID 926)。
3 通过fork调用创建服务器子进程,这会保留的原始的父进程(PID 926)并且创建一个新的子进程(PID 927)。
4 连接的客户端套接口由服务器父进程(PID 926)关闭,仅在子进程(PID 927)中保持连接的客户端套接口处理打开状态。
5 telnet命令与服务器子进程(PID 927)随意交互,而独立于父进程(PID 926)。
在步骤5,有两个套接口活动:
服务器(PID 926)监听192.168.0.1:9099
客户端由套接口192.168.0.1:9099进行服务(PID 927),他连接到客户端地址192.168.0.2:1035
客户端由进程ID 927进行服务。这意味着我们可以杀掉进程ID 926,而客户端仍可以继续被服务。然而,却不会有新的连接连接到服务器,因为并没有服务器监听新的连接(监听服务器PID 926已被杀死)
现 在如果我们重启服务器来监听新的连接,就会出现问题。当新的服务器进程试着绑定IP地址192.168.0.1:9099时,bind函数就会返回 EADDRINUSE的错误代码。这个错误代码表明IP已经在9099端口上使用。这是因为进程PID 927仍然在忙于服务一个客户端。地址192.168.0.1:9099仍为这个进程所使用。
这个问题的解决办法就是杀掉进程927,这个关闭套接口并且释放IP地址和端口。然而,如果正在被服务的客户是我们所在公司的CEO,这样的做法似乎不是一个选择。同时,其他的部门也会抱怨我们为什么要重新启动服务器。
这个问题的一个好的解决办法就是使用SO_REUSEADDR套接口选项。所有的服务器都应使用这个选项,除非有一个更好的理由不使用。为了有效的使用这个选项,我们应在监听连接的服务器中执行下面的操作:
1 使用通常的socket函数创建一个监听套接口
2 调用setsockopt函数设置SO_REUSEADDR为TRUE
3 调用bind函数
套接口现在被标记为可重用。如果监听服务器进程因为任何原因终止,我们可以重新启动这个服务器。当一个客户正为另一个服务器进程使用同一个IP和端口号进行服务时尤其如此。
为了有效的使用SO_REUSEADDR选项,需要考虑下面的情况:
在监听模式下并没有同样的IP地址和端口号的其他套接口
所有的同一个IP地址和端口号的套接口必须将SO_REUSEADDR选项设置为TRUE
这就意味着一个指定的IP地址和端口号对上只可以用一个监听器。如果这样的套接口已经存在,那么设置这样的选项将不会达到我们的目的。
只有所有存在的同一个地址和端口号的套接口有这个选项设置,将SO_REUSEADDR设置为TRUE才会有效。如果存在的套接口没有这个选项设置,那么bind函数就会继续并且会返回一个错误号。
下面的代码显示如何将这个选项设置为TRUE:
#define TRUE 1
#define FALSE 0
int z;
int s;
int so_reuseaddr = TRUE;
z = setsockopt(s,SOL_SOCKET,SO_REUSEADDR,
&so_reuseaddr,
sizeof(so_reuseaddr));
如果需要SO_REUSEADDR选项可以由getsockopt函数进行查询。
转载自:https://blog.csdn.net/fz835304205/article/details/16980163
Socket中SO_REUSEADDR详解的更多相关文章
- Socket中SO_REUSEADDR简介
SO_REUSEADDR:字面意思重复使用地址 一般来说,一个端口释放后会等待两分钟之后才能再次被使用,SO_REUSEADDR是让端口释放后立即就可以被再次使用. SO_REUSEADDR用于对TC ...
- 网络编程socket基本API详解(转)
网络编程socket基本API详解 socket socket是在应用层和传输层之间的一个抽象层,它把TCP/IP层复杂的操作抽象为几个简单的接口供应用层调用已实现进程在网络中通信. socket ...
- Java语言Socket接口用法详解
Socket接口用法详解 在Java中,基于TCP协议实现网络通信的类有两个,在客户端的Socket类和在服务器端的ServerSocket类,ServerSocket类的功能是建立一个Serve ...
- winxp计算机管理中服务详解
winxp计算机管理中服务详解01 http://blog.sina.com.cn/s/blog_60f923b50100efy9.html http://blog.sina.com.cn/s/blo ...
- cocos2dx常见的46中+22中动作详解
cocos2dx常见的46中+22中动作详解 分类: iOS2013-10-16 00:44 1429人阅读 评论(0) 收藏 举报 bool HelloWorld::init(){ ///// ...
- Android中Context详解 ---- 你所不知道的Context
转自:http://blog.csdn.net/qinjuning/article/details/7310620Android中Context详解 ---- 你所不知道的Context 大家好, ...
- iOS中-Qutarz2D详解及使用
在iOS中Qutarz2D 详解及使用 (一)初识 介绍 Quartz 2D是二维绘图引擎. 能完成的工作有: 绘制图形 : 线条\三角形\矩形\圆\弧等 绘制文字 绘制\生成图片(图像) 读取\生成 ...
- 【转】declare-styleable的使用(自定义控件) 以及declare-styleable中format详解
原文网址:http://www.cnblogs.com/622698abc/p/3348692.html declare-styleable是给自定义控件添加自定义属性用的 1.首先,先写attrs. ...
- Python中dict详解
from:http://www.cnblogs.com/yangyongzhi/archive/2012/09/17/2688326.html Python中dict详解 python3.0以上,pr ...
随机推荐
- 深入浅出--UNIX多进程编程之fork()函数
0前言 上周都在看都在学习unix环境高级编程的第八章--进程控制.也就是这一章中.让我理解了unix中一些进程的原理.以下我就主要依照进程中最重要的三个函数来进行解说.让大家通过阅读这一篇文章彻底明 ...
- Cartographer源码阅读(9):图优化的前端——闭环检测
约束计算 闭环检测的策略:搜索闭环,通过匹配检测是否是闭环,采用了分支定界法. 前已经述及PoseGraph的内容,此处继续.位姿图类定义了pose_graph::ConstraintBuilder ...
- 160A
#include <stdio.h> int main() { int n; int sum1=0, sum2=0, sum3=0; int x, y, z; scanf("%d ...
- PHP多维数组转一维
目录 1. array_column函数 2. array_walk函数 3. array_map函数 4. foreach循环 5. array_map变种 参考:https://www.awaim ...
- Windows平台搭建Kafka
1. 安装JDK 1.1 安装文件:http://www.oracle.com/technetwork/java/javase/downloads/jre8-downloads-2133155.htm ...
- redis----------windows下安装redis以及PHP的redis扩展
1.redis简介 redis是一个key-value存储系统.和Memcached类似,它支持存储的value类型相对更多,包括string(字符串).list(链表).set(集合).zset(s ...
- 微信小程序scroll-view不能实现下拉刷新
一般在列表展示页面,会使用到上拉加载和下拉刷新功能,在scroll-view中有bindscrolltolower事件,可以实现上拉加载功能,但是却没法实现下拉刷新. 如需同时使用两种功能,解决步骤如 ...
- AES,BigInteger,MD5加密
http://tool.oschina.net/apidocs/apidoc?api=jdk-zh package cn.com.gome.cashier.web; import java.lang. ...
- nodejs笔记之初识node
1.安装node; node -v //检测node是否安装成功 node可以做什么: 搭建服务器: 读写文件: 连接数据库: 爬虫: node的模块系统: 原生模块(如http,fs); 自定义模 ...
- 微信小程序一些demo链接地址
校园小情书小程序前端+后端源码 https://www.douban.com/group/topic/116974400/ 小程序源码疯狂猜成语小程序源码UI美观 https://www.douban ...