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

能够做冶金工程毕业设计的网站医药网站建设中图片

能够做冶金工程毕业设计的网站,医药网站建设中图片,我的WordPress网站,品牌设计案例分析内容目录#xff1a; 连接建立连接断开消息到达发送消息消息发送完毕其它问题参考 网络编程中的关键问题总结 总结下网络编程中关键的细节问题#xff0c;包含连接建立、连接断开、消息到达、发送消息等等#xff1b; 连接建立 包括服务端接受 (accept) 新连接和客户端成功发… 内容目录 连接建立连接断开消息到达发送消息消息发送完毕其它问题参考 网络编程中的关键问题总结 总结下网络编程中关键的细节问题包含连接建立、连接断开、消息到达、发送消息等等 连接建立 包括服务端接受 (accept) 新连接和客户端成功发起 (connect) 连接。  accept接受连接的问题在本文最后会聊到这里谈谈connect的关键点  使用非阻塞连接建立需要注意  connect/select返回后可能没有连接上需要再次确认是否成功连接 步骤为 使用异步connect直接连接一次因为使用了非阻塞函数立刻返回检查返回值为0成功连接否则加入到select/epoll中监控当有写事件时连接成功当即可读又可写时可能是有错误或者连接成功后有数据已经发过来所以此时需要用getsockopt()读取socket的错误选项二次确认是否真的连接成功: Fcntl(sockfd, F_SETFL, flags | O_NONBLOCK); error 0; if ( (n connect(sockfd, saptr, salen)) 0)if (errno ! EINPROGRESS)return(-1);/* Do whatever we want while the connect is taking place. */ if (n 0)goto done; /* connect completed immediately */if ( (n Select(sockfd1, rset, wset, NULL,nsec ? tval : NULL)) 0) {close(sockfd); /* timeout */errno ETIMEDOUT;return(-1); }if (FD_ISSET(sockfd, rset) || FD_ISSET(sockfd, wset)) {len sizeof(error);//二次确认是否真的连接成功if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, error, len) 0)return(-1); /* Solaris pending error */ } elseerr_quit(select error: sockfd not set); 连接断开 包括主动断开 (close 或 shutdown) 和被动断开 (read 返回 0)。 当打算关闭网络连接时如何能知道对方已经发送了数据自己还没有收到  在TCP层面解决主动关闭的时候只使用半关闭shutdown(), 这样服务端这边之时关闭了写端还可以正常读客户端收到关闭的信号后read返回0会再调用shutdown关闭整个连接  在应用层面解决双方通过某个标记协商在标记之后不再读写数据这样就可以完全的关闭连接了 关闭连接时需要注意的  是否还有未发送的数据需要保证应用缓冲区中的数据都发送完毕之后再关闭缓冲区  TCP缓存区不用我们考虑因为在调用shutdown或close的时候TCP的实现是会将TCP的发送缓冲区中的数据都发送出去然后再发送FIN报文(也可能是组合成一个报文发送 消息到达 消息到达是最重要的事件对它的处理决定了网络编程的风格:是阻塞还是非阻塞、分包的处理、应用层的缓冲如何设计等等 处理分包 所谓分包就是在一个个字节流消息中如何区分出一个个消息来  常见的分包方法有 固定长度特殊的结尾符比如字符串的\0或者回车换行等固定的消息头中指定后续的消息的长度然后跟上一个消息体内容使用协议本身的格式比如json格式头尾配对XML也一样 字节序转换注意字节对齐 如果传输的是二进制类型在字节流的缓存区中直接强转可能core dump因为有的系统访问地址需要字节对齐不能在任意地址上访问二进制类型如整形合理的方式是将其copy到一个本地变量中然后再做字节序的转换 int32_t peekInt32() const {assert(readableBytes() sizeof(int32_t));int32_t be32 0;::memcpy(be32,readerIndex_, sizeof(be32) );return be32toh(be32); } 应用层缓存区的实现 数据到达时处理需要注意  socket读事件来到必须一次将所有的数据都读完否则会造成一直有可读事件造成busy-loop读到的数据当然就需要有个应用层的缓冲区来存放  因为应用的缓存区是有限的可以默认设置一个大小比如2kb或者根本就不设置初始大小用多少分配多少muduo中使用的是vector 来作为缓存区可以动态增长 muduo buffer使用的技巧  buffe采用了vector自动增长的数据结构  从系统内核中调用的时候在应用层需要有足够大的缓冲区最好能一次将系统recv到的缓冲区给读空一次系统调用就搞定一切事情  而应用缓冲区考虑到有很多个并发的可能针对每个连接一次都分配较大的缓冲区浪费严重陈硕推荐使用readv一次读入到两个地址中首先将第一个地址填满如果还有更多数据就写入到临时缓冲区中然后append到应用缓冲区 读的时候使用readv局部使用一个足够大的额外空间64KB这样一次读取就足以将socket中的缓存区读空一般不会超过64Ktcp buffer如果确实要设置大的缓存区需要调整系统参数如果数据不多可能内部buffer就装下了没有额外操作否则多的数据读到了外部的缓存区再append到内部缓存区 ssize_t Buffer::readFd(int fd, int* savedErrno) {// saved an ioctl()/FIONREAD call to tell how much to readchar extrabuf[65536];struct iovec vec[2];const size_t writable writableBytes();vec[0].iov_base begin()writerIndex_;vec[0].iov_len writable;vec[1].iov_base extrabuf;vec[1].iov_len sizeof extrabuf;// when there is enough space in this buffer, dont read into extrabuf.// when extrabuf is used, we read 128k-1 bytes at most.const int iovcnt (writable sizeof extrabuf) ? 2 : 1;//只有一次系统调用这里的实现比较巧妙const ssize_t n sockets::readv(fd, vec, iovcnt);if (n 0){*savedErrno errno;}else if (implicit_castsize_t(n) writable){writerIndex_ n;}else{writerIndex_ buffer_.size();append(extrabuf, n - writable);}// if (n writable sizeof extrabuf)// {// goto line_30;// }return n; } 发送消息 网络编程中数据发送比数据接受要难处理  数据的接收只需要peek足够的数据后就可以从应用缓冲区接收出来然后处理而数据的发送还需要考虑对方接受缓慢的情况导致tcp发送缓冲区累积最终导致应用缓冲区累积 举个例子某客户端对echo服务器只发送但故意不接收  客户端如果只是发送但从不接收的话那么这边发送过去的报文首先会导致客户端的tcp接收缓冲区满然后通过ack报文告诉服务器端这边的滑动窗口为0了不能再发了后续客户端发送的报文就把服务器端TCP发送缓冲区积满然后累积应用层的发送缓冲区因为是非阻塞最终导致服务端的应用缓存区满或者内存撑爆 需要发送数据的时候优先直接调用write()发送如果发送不成功或没有全部发送完毕才加入到发送缓存区,等待可写事件到来后发送  直接调用write()发送数据时需要先将本次需要发送的数据添加到缓存区然后发送缓存区不可直接发送本次数据因为缓存区中可能有遗留的数据未发送完 void TcpConnection::handleWrite() {loop_-assertInLoopThread();if (channel_-isWriting()){//注意这里只调用了一次write,而没有反复调用write直到出现EAGAIN错误//原因是如果第一次调用没有发送完全部的数据第二次调用几乎肯定是EAGAIN错误//因此这里减少了一次系统调用这么做不影响正确性却能够降低系统时延ssize_t n sockets::write(channel_-fd(),outputBuffer_.peek(),outputBuffer_.readableBytes());if (n 0){outputBuffer_.retrieve(n);if (outputBuffer_.readableBytes() 0){//如果发送缓存区为空不再关注写事件避免 busy loop channel_-disableWriting();//如果还有写完成之后的回调加入待执行回调队列if (writeCompleteCallback_){loop_-queueInLoop(boost::bind(writeCompleteCallback_, shared_from_this()));}//如果此时正在关闭调用shutdownInLoop 继续执行关闭过程if (state_ kDisconnecting){shutdownInLoop();}}}else{LOG_SYSERR TcpConnection::handleWrite;// if (state_ kDisconnecting)// {// shutdownInLoop();// }}}else{LOG_TRACE Connection fd channel_-fd() is down, no more writing;} } 消息发送完毕 对于低流量的服务可以不必关心这个事件另外这里“发送完毕”是指将数据写入操作系统的缓冲区后续由 TCP 协议栈负责数据的发送与重传不代表对方已经收到数据。 其它问题 IO multiplexing 是否可以配合阻塞套接字使用 一般都配合非阻塞socket使用如果使用阻塞IO可能在读写事件上阻塞当前线程造成无法继续处理已经就绪的事件  初学网络编程可能都会有这个想法select返回后如果是读事件那么这时候tcp读缓冲区肯定是有数据这时即使使用阻塞套接字来read应该也不会阻塞但这样忽略了一个点缓冲区确实是有数据但是很可能到达的数据并不满足你要求读的数据大小这样read调用还是会阻塞直到有足够的数据才返回  那么对于数据读不可以对accept()总可以吧连接事件返回一般都是有新用户接入这时候阻塞的accept()应该总是能够返回但在某些情况下可能对方刚连接上就断开了并给服务端发送了一个RST请求造成服务端这边将已经就绪的连接请求又移除了这样的场景下select返回但是accept却无法获取新的连接造成阻塞直到下一个连接请求到来(这方面的例子详见《UNIX网络编程卷1套接字联网API》16.6节非阻塞accept() )  所以任何时候IO multiplexing都需要配合非阻塞IO使用 零拷贝的实现 对于内核层的实现底层调用的是系统调用sendFile()方法  zerocopy技术省去了将操作系统的read buffer拷贝到程序的buffer, 以及从程序buffer拷贝到socket buffer的步骤, 直接将 read buffer 拷贝到 socket buffer    详见http://www.cnblogs.com/zemliu/p/3695549.html 应用层上的实现对于自定义的结构一般是交换内部指针使用C11可以使用move操作来实现高效交换结构体  如果是vector等结构使用其成员函数swap()就能达到高效的交换类似C11中的move操作  例如muduo中buffer实现通过swap实现了缓存区的指针交换从而达到数据交换的目的而不用拷贝缓冲区 void swap(Buffer rhs) {buffer_.swap(rhs.buffer_); // std::vectorchar buffer_;std::swap(readerIndex_, rhs.readerIndex_);std::swap(writerIndex_, rhs.writerIndex_); } epoll使用LT epoll使用是LT而非ET原因如下 LT编程方便select的经验都可同样适用读的时候只需要一次系统调用而ET必须读到EAGAIN错误减少一次系统调用降低时延 一般认为 edge-trigger 模式的优势在于能够减少 epoll 相关系统调用这话不假但网络服务程序里可不是只有 epoll 相关系统调用为了绕过饿死问题edge-trigger 模式下用户要自行进行 read/write 循环处理这其中增加的系统调用和减少的 epoll 系统调用加起来总体性能收益究竟如何只有实际测量才知道无法一概而论。为了降低处理逻辑复杂度常用的事件处理库大部分都选择了 level-trigger 模式如 libevent、boost::asio、muduo等
http://www.huolong8.cn/news/237123/

相关文章:

  • 企业建设网站对客户的好处2018新网站做外链
  • 简述网站建设的流程wordpress密码重置密码
  • 想在网站里添加超链接怎么做淘宝网站制作
  • 千岛湖建设集团办公网站郑州居家办公全员核酸
  • 济南微信网站建设西宁最好的建站公司
  • 杭州企业网站制作公司个人网页设计作品模板
  • 做医美设计的网站做网站竞争大吗
  • 台州企业建站系统wordpress代码 lt
  • 德阳市建设局网站地址杭州行业网站建设公司
  • 养殖推广网站怎么做工商注册咨询电话多少
  • 如何管理手机网站首页中卫网站建站设计
  • 制作网站哪家服务好甘肃兰州网站建设
  • 成华区微信网站建设公上门做美容的网站
  • 张家港做外贸网站微商店铺怎么开通
  • 免费做海报的网站做国外有那些网站比较好的
  • 超炫网站页面网络公司制作网站
  • 广西美丽乡村建设网站从网络全角度考量_写出建设一个大型电影网站规划方案
  • 教育网站平面设计伍佰亿营销型网站
  • 网站做支付宝花呗分期建站行业前景
  • 昆明手机网站开发电商网站建设浩森宇特
  • h5能做网站开发吗wordpress相册api
  • 网站建设域名怎么收费的阳江房管局查询房产信息网
  • 品牌专业建设网站自助建站免费建站平台
  • 网站数据库制作php网站开发前言
  • 揭阳市seo点击排名软件价格汕头自动seo
  • 建设网站的技术难点网页设计的基本原则是什么
  • 做网站的系统功能需求自己做抽奖网站违法吗
  • 西双版纳傣族自治州海拔多少酒店seo是什么意思
  • 网站建设管理情况说明台州网站建设方案策划
  • 山西响应式网站设计网站开发怎样