linux、windows 下,

linux 下的close() / windows 下的 closesocket()  操作只是使相应socket描述字的引用计数-1,只有当引用计数为0的时候,才会触发TCP客户端向服务器发送终止连接请求。

 

转: https://zhuanlan.zhihu.com/p/37278278

SO_REUSEADDR:

目前为止我见到的设置SO_REUSEADDR的使用场景:server端在调用bind函数时

setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR,(const void *)&reuse , sizeof(int));

目的:当服务端出现timewait状态的链接时,确保server能够重启成功。

注意:SO_REUSEADDR只有针对time-wait链接(linux系统time-wait连接持续时间为1min),确保server重启成功的这一个作用,至于网上有文章说:如果有socket绑定了0.0.0.0:port;设置该参数后,其他socket可以绑定本机ip:port。本人经过试验后均提示“Address already in use”错误,绑定失败。

举个例子:

server监听9980端口,由于主动关闭链接,产生了一个time-wait状态的链接:

linux 服务端热升级 备份

如果此时server重启,并且server没有设置SO_REUSEADDR参数,server重启失败,报错:“Address already in use”

如果设置SO_REUSEADDR,重启ok;

 

SO_REUSEPORT:

SO_REUSEPORT使用场景:linux kernel 3.9 引入了最新的SO_REUSEPORT选项,使得多进程或者多线程创建多个绑定同一个ip:port的监听socket,提高服务器的接收链接的并发能力,程序的扩展性更好;此时需要设置SO_REUSEPORT(注意所有进程都要设置才生效)。

setsockopt(listenfd, SOL_SOCKET, SO_REUSEPORT,(const void *)&reuse , sizeof(int));

目的:每一个进程有一个独立的监听socket,并且bind相同的ip:port,独立的listen()和accept();提高接收连接的能力。(例如nginx多进程同时监听同一个ip:port)

解决的问题:

(1)避免了应用层多线程或者进程监听同一ip:port的“惊群效应”。

(2)内核层面实现负载均衡,保证每个进程或者线程接收均衡的连接数。

(3)只有effective-user-id相同的服务器进程才能监听同一ip:port (安全性考虑)

代码示例:server_128.c

#include <stdio.h>                                                                                                               
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <errno.h>
#include <time.h>
#include <unistd.h>
#include <sys/wait.h>
void work () {
        int listenfd = socket(AF_INET, SOCK_STREAM, 0);
        if (listenfd < 0) {
                perror("listen socket");
                _exit(-1);
        }
        int ret = 0;
        int reuse = 1;
        ret = setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR,(const void *)&reuse , sizeof(int));
        if (ret < 0) {
                perror("setsockopt");
                _exit(-1);
        }
        ret = setsockopt(listenfd, SOL_SOCKET, SO_REUSEPORT,(const void *)&reuse , sizeof(int));
        if (ret < 0) {
            perror("setsockopt");
            _exit(-1);
        }
        struct sockaddr_in addr;
        memset(&addr, 0, sizeof(addr));
        addr.sin_family = AF_INET;
        //addr.sin_addr.s_addr = inet_addr("10.95.118.221");
        addr.sin_addr.s_addr = inet_addr("0.0.0.0");                                                                             
        addr.sin_port = htons(9980);
        ret = bind(listenfd, (struct sockaddr *)&addr, sizeof(addr));
        if (ret < 0) {
                perror("bind addr");
                _exit(-1);
       }
        printf("bind success\n");
        ret = listen(listenfd,10);
        if 

相关文章: