当前位置: 首页 > news >正文

东莞物流网站建设网络营销的相关知识

东莞物流网站建设,网络营销的相关知识,视频网站的防盗链是怎么做的,wordpress分类下文章置顶从Linux源码看Socket(TCP)的accept前言笔者一直以为若是能知道从应用到框架再到操做系统的每一处代码#xff0c;是一件Exciting的事情。 今天笔者就从Linux源码的角度看下Server端的Socket在进行Accept的时候到底作了哪些事情(基于Linux 3.10内核)。html一个最简单的Server端…从Linux源码看Socket(TCP)的accept前言笔者一直以为若是能知道从应用到框架再到操做系统的每一处代码是一件Exciting的事情。 今天笔者就从Linux源码的角度看下Server端的Socket在进行Accept的时候到底作了哪些事情(基于Linux 3.10内核)。html一个最简单的Server端例子众所周知一个Server端Socket的创建须要socket、bind、listen、accept四个步骤。今天笔者就聚焦于accept。代码以下:reactvoid start_server(){// server fdint sockfd_server;// accept fdint sockfd;int call_err;struct sockaddr_in sock_addr;......call_errbind(sockfd_server,(struct sockaddr*)(sock_addr),sizeof(sock_addr));......call_errlisten(sockfd_server,MAX_BACK_LOG);......while(1){struct sockaddr_in* s_addr_client mem_alloc(sizeof(struct sockaddr_in));int client_length sizeof(*s_addr_client);// 这边就是咱们今天的聚焦点acceptsockfd accept(sockfd_server,(struct sockaddr_ *)(s_addr_client),(socklen_t *)(client_length));if(sockfd -1){printf(Accept error!\n);continue;}process_connection(sockfd,(struct sockaddr_in*)(s_addr_client));}}首先咱们经过socket系统调用建立了一个Socket其中指定了SOCK_STREAM,并且最后一个参数为0也就是创建了一个一般全部的TCP Socket。在这里咱们直接给出TCP Socket所对应的ops也就是操做函数。linux accept系统调用好了咱们直接进入accept系统调用吧。多线程#include // 成功返回表明新链接的描述符错误返回-1,同时错误码设置在errnoint accept(int sockfd,struct sockaddr* addr,socklen_t *addrlen);// 注意,实际上Linux还有个accept扩展accept4:// 额外添加的flags参数能够为新链接描述符设置O_NONBLOCK|O_CLOEXEC(执行exec后关闭)这两个标记int accept4(int sockfd, struct sockaddr *addr,socklen_t *addrlen, int flags);注意这边的accept调用是被glibc用SYSCALL_CANCEL包了一层其将返回值修正为只有0和-1这两个选择同时将错误码的绝对值设置在errno内。因为glibc对于系统调用的封装过于复杂就不在这里细讲了。若是要寻找具体的逻辑用负载均衡// 注意accept和(之间要有空格否则搜索不到accept (int在整个glibc代码中搜索便可。理解accept的关键点是它会建立一个新的Socket,这个新的Socket来与对端运行connect()的对等Socket进行链接以下图所示:接下来咱们就进入Linux内核源码栈吧框架accept|-SYSCALL_CANCEL(accept......)......|-SYSCALL_DEFINE3(accept// 最终调用了sys_accept4|-sys_accept4/* 检测监听描述符fd是否存在不存在返回-BADF|-sockfd_lookup_light|-sock_alloc /*新建Socket*/|-get_unused_fd_flags /*获取一个未用的fd*/|-sock-ops-accept(sock...) /*调用核心*/上述流程以下面所示:由此得知核心函数在sock-ops-accept上因为咱们关注的是TCP,那么其实现即为inet_stream_ops-accept也即inet_accept再次跟踪下调用栈:socketsock-ops-accept|-inet_steam_ops-accept(inet_accept)/* 由一开始的sock图可知sk_prottcp_prot|-sk1-sk_prot-accept|-inet_csk_accept好了穿过了层层包装终于到具体逻辑部分了。上代码:tcpstruct sock *inet_csk_accept(struct sock *sk, int flags, int *err){struct inet_connection_sock *icsk inet_csk(sk);/* 获取当前监听sock的accept队列*/struct request_sock_queue *queue icsk-icsk_accept_queue;....../* 若是监听Socket状态非TCP_LISEN,返回错误 */if (sk-sk_state ! TCP_LISTEN)goto out_err/* 若是当前accept队列为空 */if (reqsk_queue_empty(queue)) {long timeo sock_rcvtimeo(sk, flags O_NONBLOCK);/* 若是是非阻塞模式直接返回-EAGAIN */error -EAGAIN;if (!timeo)goto out_err;/* 若是是阻塞模式切超时时间不为0,则等待新链接进入队列 */error inet_csk_wait_for_connect(sk, timeo);if (error)goto out_err;}/* 到这里accept queue不为空,从queue中获取一个链接 */req reqsk_queue_remove(queue);newsk req-sk;/* fastopen 判断逻辑 */....../* 返回新的sock,也就是accept派生出的和client端对等的那个sock */return newsk}上面流程以下图所示:咱们关注下inet_csk_wait_for_connect,即accept的超时逻辑:函数static int inet_csk_wait_for_connect(struct sock *sk, long timeo){for (;;) {/* 经过增长EXCLUSIVE标志使得在BIO中调用accept中不会产生惊群效应 */prepare_to_wait_exclusive(sk_sleep(sk), wait,TASK_INTERRUPTIBLE);if (reqsk_queue_empty(icsk-icsk_accept_queue))timeo schedule_timeout(timeo);.......err -EAGAIN;/* 这边accept超时返回的是-EAGAIN */if (!timeo)break;}finish_wait(sk_sleep(sk), wait);return err;}经过exclusice标志使得咱们在BIO中调用accept(不用epoll/select等)时不会惊群。由代码得知在accept超时时候返回(errno)的是EAGAIN而不是ETIMEOUT。操作系统EPOLL(在accept时候)惊群因为在EPOLL LT(水平触发模式下),一次accept事件可能会唤醒多个等待在此listen fd上的(epoll_wait)线程,而最终可能只有一个能成功的获取到新链接(newfd),其它的都是-EGAIN也即有一些没必要要的线程被唤醒了作了无用功。关于epoll的原理能够看下笔者以前的博客《从linux源码看epoll》:https://www.cnblogs.com/alchemystar/p/13161781.html在这里描述一下缘由,核心就是epoll_wait在水平触发下会在这个fd仍有未处理事件的时候从新塞回ready_list并在此唤醒另外一个等待在epoll上的进程因此咱们看到虽然epoll_wait的时候给本身加了exclusive不会在有中断事件触发的时候惊群可是水平触发这个机制确也形成了相似惊群的现象由上面的讨论看出fd1仍旧有事件是形成额外唤醒的缘由这个也很好理解毕竟这个事件是另外一个线程处理的那个线程估摸着还没来得及运行天然也来不及处理咱们看下在accept事件中怎么断定这个fd(listen sock的fd)还有未处理事件的。// 经过f_op-poll断定epi-ffd.file-f_op-poll|-tcp_poll/* 若是sock是listen状态则由下面函数负责 */|-inet_csk_listen_poll/* 经过accept_queue队列是否为空判断监听sock是否有未处理事件*/static inline unsigned int inet_csk_listen_poll(const struct sock *sk){return !reqsk_queue_empty(inet_csk(sk)-icsk_accept_queue) ?(POLLIN | POLLRDNORM) : 0;}那么咱们就能够根据逻辑画出时序图了。其实不只仅是accept,要是多线程epoll_wait同一个fd的read/write也是一样的惊群只不过应该不会有人这么作吧。正是因为这种惊群效应的存在因此咱们常常采用单开一个线程去专门accept的形式例如reactor模式便是如此。可是若是一瞬间有大量链接涌进来单线程处理仍是有瓶颈的,没法充分利用多核的优点,在海量短链接场景下就显得稍显无力了。这也是有解决方式的采用so_reuseport解决惊群前面讲过因为咱们是在同一个fd上多线程去运行epoll_wait才会有此问题那么其实咱们多开几个fd就解决了。首先想到的方案是多开几个端口号人为分开监听fd但这个明显带来了额外的复杂性。为了解决这一问题Linux提供了so_reuseport这个参数其原理以下图所示:多个fd监听同一个端口号在内核中作负载均衡(Sharding),将accept的任务分散到不一样的线程的不一样Socket上(Sharding)毫无疑问能够利用多核能力大幅提高链接成功后的Socket分发能力。那么咱们的线程模型也能够改成用多线程accept了以下图所示:accept_queue全链接队列在前面的讨论中,accept_queue是accept系统调用中的核心成员那么这个accept_queue是怎么被填充(add)的呢?以下图所示:图中展现了client和server在三次交互中accept_queue(全链接队列)和syn_table半链接hash表的变迁状况。在accept_queue被填充后由用户线程经过accept系统调用从队列中获取对应的fd值得注意的是当用户线程来不及处理的时候内核会drop掉三次握手成功的链接致使一些诡异的现象具体能够看笔者的另外一篇博客《解Bug之路-dubbo流量上线时的非平滑问题》:https://www.cnblogs.com/alchemystar/p/13473999.html另外对于accept_queue具体的填充机制以及源码能够见笔者另外一篇博客的详细分析《从Linux源码看Socket(TCP)的listen及链接队列》https://www.cnblogs.com/alchemystar/p/13845081.html总结Linux内核源码博大精深每次扎进去探索时候都会废寝忘食其间能够看到各类优雅的设计在此分享出来但愿对读者有所帮助。欢迎你们关注我公众号里面有各类干货还有大礼包相送哦!
http://www.pierceye.com/news/869934/

相关文章:

  • 上小学网站建设WordPress底部添加运行时间
  • 学校网站信息化建设工作心得网络营销现状分析
  • 藁城专业网站建设班级同学录网站建设
  • 北京手机网站开发公司wordpress用户列表
  • 上海 企业网站制成都营销型网站建设熊掌号
  • 无锡网站优化哪家好北京注册公司地址可以是住宅吗
  • 中国十大热门网站深圳哪做网站
  • 木渎网站建设聚美优品网站建设情况
  • 企业形象网站用什么语言开发网站优化要做哪些工作
  • 中国建设银行官网站电话号码wordpress关键词排名
  • 南通网站建设机构博物馆网站建设的根本意义
  • 食品企业网站建设中信建设有限责任公司陈晓佳
  • 中国网站服务器哪个好店名注册查询
  • 网站设计制作案例软件定制开发的发展前景
  • 中国联通网站备案小程序是什么原理
  • 企业网站建设御彩云dz做电影网站
  • 做网站需要的东西网站改版是什么
  • 网站需要哪些北京正规网站建设比较
  • 建设公共网站的手续成都公司网站制作
  • 怎么用安卓机顶盒做网站服务器怎样建立微信公众号平台
  • 专业的集团网站开发开发平面设计软件哪个好用
  • 天津模板建站代理咖啡厅网站开发目标
  • 电子商务网站运营 需要确立如何自己做网页
  • 邯郸市魏县建设局网站个人免费网站申请
  • 建设网站需要备案wordpress文章管理插件
  • 企业网站源码程序多少钱?桓台网站建设
  • vps服务器购买网站自己做的网站可以买东西吗
  • 必应网站建设深圳设计大厦
  • 如何禁止ip访问网站常州网站建设公司推荐
  • 大型论坛网站建设设计公司