如何正确使用SO_REUSEADDR?守护进程端口绑定场景解析
问题解析与解决方案
1. 先明确TIME_WAIT的触发条件
TIME_WAIT是TCP连接完全建立后关闭才会进入的状态,只执行bind()但没调用listen()或accept()的socket,关闭后不会进入TIME_WAIT——内核会直接释放端口绑定,所以is_me_here()执行完close()后,不会留下端口占用的隐患。
2. SO_REUSEADDR的正确设置位置
绝对不能在#1(is_me_here())设置:
is_me_here()的核心作用是通过bind()是否失败,检测端口是否被已有守护进程占用。如果加了SO_REUSEADDR,即使已有进程在监听该端口,当前进程也能bind()成功,直接导致守护进程多实例运行的检测逻辑完全失效。必须在#2(foo())设置:
当守护进程重启时,之前的进程可能遗留处于TIME_WAIT状态的客户端连接(比如已处理完的连接还没走完TIME_WAIT周期),此时新进程的bind()会因端口被TIME_WAIT连接占用而失败。SO_REUSEADDR的作用就是允许绑定到处于TIME_WAIT状态的端口,确保守护进程重启时能正常绑定监听端口。
3. 关于子进程的socket持有问题
你的代码逻辑是正确的:fork操作在foo()之前执行,此时foo()里的监听socket还未创建,子进程不会继承到绑定的socket,不用担心子进程持有端口绑定导致主进程重启失败。
总结修改建议
将setsockopt(sck,SOL_SOCKET,SO_REUSEADDR,&temp,sizeof(int));这行代码移到#2位置(foo()中socket创建后、bind()之前),并删除#1位置的注释代码。
内容的提问来源于stack exchange,提问作者Rainbow
相关产品推荐
相关产品推荐

