当前位置:首页 > bind
  • 浅谈从Linux源码分析bind系统调用

    浅谈从Linux源码分析bind系统调用

    作者一直认为,从应用程序到框架再到系统,使用每一个代码是一回事理解。使用“今天,作者将研究服务器端套接字的功能。准确地说,它是bind(基于linux3.10)。 一个最简单的Server端例子 众所周知,一个Server端Socket的建立,需要socket、bind、listen、accept四个步骤。  代码如下: 首先我们通过socket系统调用创建了一个socket,其中指定了SOCK_STREAM,而且最后一个参数为0,也就是建立了一个通常所有的TCP Socket。在这里,我们直接给出TCP Socket所对应的ops也就是操作函数。  如果你想知道上图中的结构是怎么来的,可以看下笔者以前的博客:   bind系统调用 bind将一个本地协议地址(protocol:ip:port)赋予一个套接字。例如32位的ipv4地址或128位的ipv6地址+16位的TCP活UDP端口号。 好了,我们直接进入Linux源码调用栈吧。 inet_bind inet_bind这个函数主要做了两个操作,一是检测是否允许bind,而是获取可用的端口号。这边值得注意的是。如果我们设置需要bind的端口号为0,那么Kernel会帮我们随机选择一个可用的端口号来进行bind! 让我们看下inet_bind的流程  值得注意的是,由于对于sk_prot->get_port) inet_csk_get_port 第一段,如果bind port为0,随机搜索可用端口号 直接上源码,第一段代码为端口号为0的搜索过程 由于,我们在使用bind的时候很少随机端口号(在TCP服务器来说尤其如此),这段代码笔者就注释一下。一般只有一些特殊的远程过程调用(RPC)中会使用随机Server端随机端口号。 第二段,找到端口号或已经指定 判断端口号是否冲突 在上述源码中,判断端口号时否冲突的代码为 上面代码的逻辑如下图所示:  SO_REUSEADDR和SO_REUSEPORT 上面的代码有点绕,笔者就讲一下,对于我们日常开发要关心什么。 我们在上面的bind里面经常见到sk_reuse和sk_reuseport这两个socket的Flag。这两个Flag能够决定是否能够bind(绑定)成功。这两个Flag的设置在C语言里面如下代码所示: 在原生JAVA中 在Netty(Netty版本 >= 4.0.16且Linux内核版本>=3.9以上)中,可以使用SO_REUSEPORT。 SO_REUSEADDR 在之前的源码里面,我们看到判断bind是否冲突的时候,有这么一个分支 如果sk2(即已bind的socket)是TCP_LISTEN状态或者,sk2和新sk两者都没有设置_REUSEADDR的时候,可以判断为冲突。 我们可以得出,如果原sock和新sock都设置了SO_REUSEADDR的时候,只要原sock不是Listen状态,都可以绑定成功,甚至ESTABLISHED状态也可以!  这个在我们平常工作中,最常见的就是原sock处于TIME_WAIT状态,这通常在我们关闭Server的时候出现,如果不设置SO_REUSEADDR,则会绑定失败,进而启动不来服务。而设置了SO_REUSEADDR,由于不是TCP_LISTEN,所以可以成功。  这个特性在紧急重启以及线下调试的非常有用,建议开启。 SO_REUSEPORT SO_REUSEPORT是Linux在3.9版本引入的新功能。 我们看下一般的Reactor线程模型,  明显的其单线程listen/accept会存在瓶颈(如果采用多线程epoll accept,则会惊群,加WQ_FLAG_EXCLUSIVE可以解决一部分),尤其是在采用短链接的情况下。 鉴于此,Linux增加了SO_REUSEPORT,而之前bind中判断是否冲突的下面代码也是为这个参数而添加的逻辑: 这段代码让我们在多次bind的时候,如果设置了SO_REUSEPORT的时候不会报错,也就是让我们有个多线程(进程)bind/listen的能力。如下图所示:  而开启了SO_REUSEPORT后,代码栈如下: 直接在内核层面做负载均衡,将accept的任务分散到不同的线程的不同socket上(Sharding),毫无疑问可以多核能力,大幅提升连接成功后的socket分发能力。 Nginx已经采用SO_REUSEPORT Nginx在1.9.1版本的时候引入了SO_REUSEPORT,配置如下:   总结 Linux有一个非常复杂的内核源代码,希望能对读者有所帮助。

    时间:2020-10-17 关键词: Linux bind server

  • C++11新特性之七:bind和function

    一.std::bindbind是这样一种机制,它可以将参数绑定于可调用对象,产生一个新的可调用实体,这种机制在函数回调时颇为有用。C++98中,有两个函数bind1st和bind2nd,它们分别用来绑定functor的第一个和第二个参数,都只能绑定一个参数。C++98提供的这些特性已经由于C++11的到来而过时,由于各种限制,我们经常使用bind而非bind1st和bind2nd。在C++11标准库中,它们均在functional头文件中。而C++STL很大一部分由Boost库扩充,STL中的shared_ptr等智能指针,bind及function都是由Boost库引入。在写代码过程中,要养成使用bind,function,lambda和智能指针的习惯,它们非常强大简洁实用。1.过时的bind1st和bind2ndbind1st(op, arg) :op(arg, param) bind2nd(op, arg) :op(param, arg)vectorcoll {1, 2, 3, 4, 5, 11, 22, 5, 12}; // 查找第一个元素值大于10的元素 std::find_if(coll.begin(), coll.end(), // 范围              std::bind2nd(std::greater(), 10));// 将10绑定到第二个参数,也就是 ......大于10 // 查找元素值大于10的元素的个数 int _count = count_if(coll.begin(), coll.end(), // 范围               std::bind1st(less(), 10));// 将10绑定到第一个参数,也就是10小于......2. C++11中的std::bind//function object内部调用plus<>(也就是operator+),以占位符(placeholders)_1为第一个参数, //以10为第二个参数,占位符_1表示实际传入此表达式的第一实参,返回“实参+10”的结果值 auto plus10 = std::bind(std::plus(), std::placeholders::_1, 10); std::cout << plus10(7) << std::endl;// 输出17// (x + 10)*2,下面的代码中x=7 std::bind(std::multiplies(),            std::bind(std::plus(), std::placeholders::_1, 10),// i+10           2)(7);注意:上面所用的less

    时间:2018-10-16 关键词: function c++11 bind

发布文章

技术子站

更多

项目外包