设为首页 加入收藏

TOP

C 中级 - SO_REUSEPORT 和 SO_REUSEADDR(一)
2018-10-21 14:12:45 】 浏览:64
Tags:中级 SO_REUSEPORT SO_REUSEADDR

引言 - 问题由来

  刚开始学习网络编程时候, 常听到一个词, 先开启 "端口复用 SO_REUSEADDR". 那时很一知半解,

就知道该那么写了. 心里一直有些奇怪, 语义不通呀为啥这么翻译.  后面随着相声听多了, 就明白了些

道理. 

  倒排索引为啥叫倒排索引?  https://www.zhihu.com/question/23202010

  (这个梗告诉 wo, 索引和反向索引要比正排索引和倒排索引容易理解好多, 信达雅 : )

 随后逛网络帖子恰好看见布道师陈硕介绍 SO_REUSEPORT 时候, 他说的实用起来应该很爽.

  Linux 4.5/4.6 中对 SO_REUSEPORT 的改进  https://zhuanlan.zhihu.com/p/25533528

文章简单的通过数据结构来表明  SO_REUSEPORT 开启后, 会将 sock 结构放入  port 为 key 的

hash 结构中. 一联想, 就发现到 epoll 多线程解决方案,  通过 epoll + thread + listen fd  epoll 搞.

是不是很有意思. 

  后面开始搜集 SO_REUSEPORT 资料, 看到这个

  浅析套接字中SO_REUSEPORT和SO_REUSEADDR的区别  https://blog.csdn.net/Yaokai_AssultMaster/article/details/68951150

从中提炼几个简单信息. 我们以 linux 行为为基准, 顺带引述 winds 行为. 

linux -:

  1) . 端口复用 SO_REUSEPORT, 可以顶地址复用 SO_REUSEADDR.

  2) . 都有 userID 安全检查

winds -:

  1). 只有 SO_REUSEADDR, 轻微像 SO_REUSEPORT 支持多端口绑定.

       但只有最后一个绑定的 socket 能够接收数据.  最后一个 closesocket 后, 最后"第二个"顶. 

     (猜测采用的是 list 结构, 每次 add 到 head, del 到 head. ) 

  2). 没有 userID 安全检查, 依赖它独有安全的选项 SO_EXCLUSIVEADDRUSE

通过上面信息, 不妨写个通用的复用代码 socket_set_reuse 用起来会很舒服.

// socket_set_reuse - 开启端口和地址复用
inline int socket_set_enable(socket_t s, int optname) {
    int ov = 1;
    return setsockopt(s, SOL_SOCKET, optname, (void *)&ov, sizeof ov);
}

inline int socket_set_reuse(socket_t s) {
    return socket_set_enable(s, SO_REUSEPORT);
}

其中 winds 平台构造了如下定义 

#ifdef _MSC_VER

#define SO_REUSEPORT            SO_REUSEADDR

typedef SOCKET socket_t;#endif

上面翻译文章中提供链接挺好

  stackoverflow SO_REUSEADDR 和 SO_REUSEPORT differ 回答很有水准

  https://stackoverflow.com/questions/14388706/socket-options-so-reuseaddr-and-so-reuseport-how-do-they-differ-do-they-mean-t/14388707#14388707  

扯了这么多, 后面会构造代码来验证和表现结果.

正文 - 实验验证

  首先从 linux 入手, 写一段 SO_REUSEPORT 验证代码  port.c 

#include <time.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <pthread.h>
#include <sys/types.h>

#include <netdb.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/tcp.h>

//
// CERR - 打印错误信息
// IF   - 条件判断异常退出的辅助宏
//
#define CERR(fmt, ...)                                                   \
fprintf(stderr, "[%s:%s:%d][%d:%s]" fmt "\n",                            \
    __FILE__, __func__, __LINE__, errno, strerror(errno), ##__VA_ARGS__)

#define IF(cond)                                                         \
if ((cond)) do {                                                         \
    CERR(#cond);                                                         \
    exit(EXIT_FAILURE);                                                  \
} while(0)

// accept_example - SO_REUSEPORT accept example 
void accept_example(void);

// times_buf - 时间串缓存
char * times_buf(char buf[BUFSIZ]);

//
// SO_REUSEPORT :)
//
int main(int argc, char * argv[]) {
    // start 10 pthread run accept_example
    pthread_attr_t attr;
    pthread_attr_init(&attr);
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
    for (int i = 0; i < 10; ++i) {
        pthread_t tid;
        IF(pthread_create(&tid, &attr, (void * (*)(void *))accept_example, NULL));
    }
    pthread_attr_destroy(&attr);

    // main accept block
    accept_example();
    return 0;
}

// UINT_PORT - 监听端口
#define UINT_PORT (8088)

// socket_set_enable - 开始 socket 开关
inline static
首页 上一页 1 2 下一页 尾页 1/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇最小包围矩形 下一篇[C语言]易错知识点、小知识点复习..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目