TCP/IP   Winsock编程要点    
   
  蒋勇    
   
  2002.5.23    
   
       
   
  利用Winsock编程由同步和异步方式,同步方式逻辑清晰,编程专注于应用,在抢先式的多任务操作系统中(WinNt、Win2K)采用多线程方式效率基本达到异步方式的水平,应此以下为同步方式编程要点。    
   
  1、快速通信    
   
  Winsock的Nagle算法将降低小数据报的发送速度,而系统默认是使用Nagle算法,使用    
   
  int   setsockopt(    
   
      SOCKET   s,                                    
   
      int   level,                                    
   
      int   optname,                              
   
      const   char   FAR   *optval,      
   
      int   optlen                                  
   
  );函数关闭它    
   
  例子:    
   
  SOCKET   sConnect;    
   
  sConnect=::socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);    
   
  int   bNodelay   =   1;    
   
  int   err;    
   
  err   =   setsockopt(    
   
                  sConnect,    
   
                  IPPROTO_TCP,    
   
                  TCP_NODELAY,    
   
                  (char   *)&bNodelay,    
   
                  sizoeof(bNodelay));//不采用延时算法    
   
  if   (err   !=   NO_ERROR)    
   
  TRACE   ("setsockopt   failed   for   some   reason/n");;    
   
       
   
  2、SOCKET的SegMentSize和收发缓冲    
   
  TCPSegMentSize是发送接受时单个数据报的最大长度,系统默认为1460,收发缓冲大小为8192。    
   
  在SOCK_STREAM方式下,如果单次发送数据超过1460,系统将分成多个数据报传送,在对方接受到的将是一个数据流,应用程序需要增加断帧的判 断。当然可以采用修改注册表的方式改变1460的大小,但MicrcoSoft认为1460是最佳效率的参数,不建议修改。    
   
  在工控系统中,建议关闭Nagle算法,每次发送数据小于1460个字节(推荐1400),这样每次发送的是一个完整的数据报,减少对方对数据流的断帧处理。    
   
       
   
  3、同步方式中减少断网时connect函数的阻塞时间    
   
  同步方式中的断网时connect的阻塞时间为20秒左右,可采用gethostbyaddr事先判断到服务主机的路径是否是通的,或者先ping一下对方主机的IP地址。    
   
  A、采用gethostbyaddr阻塞时间不管成功与否为4秒左右。    
   
  例子:    
   
  LONG   lPort=3024;    
   
  struct   sockaddr_in   ServerHostAddr;//服务主机地址    
   
  ServerHostAddr.sin_family=AF_INET;    
   
  ServerHostAddr.sin_port=::htons(u_short(lPort));    
   
  ServerHostAddr.sin_addr.s_addr=::inet_addr("192.168.1.3");    
   
  HOSTENT*   pResult=gethostbyaddr((const   char   *)   &    
   
  (ServerHostAddr.sin_addr.s_addr),4,AF_INET);      
   
  if(NULL==pResult)    
   
  {    
   
  int   nErrorCode=WSAGetLastError();    
   
  TRACE("gethostbyaddr   errorcode=%d",nErrorCode);    
   
  }    
   
  else    
   
  {    
   
  TRACE("gethostbyaddr   %s/n",pResult->h_name);;    
   
  }    
   
  B、采用PING方式时间约2秒左右    
   
  暂略    
   
       
   
  4、同步方式中解决recv,send阻塞问题    
   
  采用select函数解决,在收发前先检查读写可用状态。    
   
  A、读    
   
  例子:    
   
  TIMEVAL   tv01   =   {0,   1};//1ms钟延迟,实际为0-10毫秒    
   
  int   nSelectRet;    
   
  int   nErrorCode;    
   
  FD_SET   fdr   =   {1,   sConnect};    
   
  nSelectRet=::select(0,   &fdr,   NULL,   NULL,   &tv01);//检查可读状态    
   
  if(SOCKET_ERROR==nSelectRet)    
   
  {    
   
  nErrorCode=WSAGetLastError();    
   
  TRACE("select   read   status   errorcode=%d",nErrorCode);    
   
  ::closesocket(sConnect);    
   
  goto   重新连接(客户方),或服务线程退出(服务方);    
   
  }    
   
  if(nSelectRet==0)//超时发生,无可读数据    
   
  {    
   
  继续查读状态或向对方主动发送    
   
  }    
   
  else    
   
  {    
   
  读数据    
   
  }                    
   
  B、写    
   
  TIMEVAL   tv01   =   {0,   1};//1ms钟延迟,实际为9-10毫秒    
   
  int   nSelectRet;    
   
  int   nErrorCode;    
   
  FD_SET   fdw   =   {1,   sConnect};    
   
  nSelectRet=::select(0,     NULL,   NULL,&fdw,   &tv01);//检查可写状态    
   
  if(SOCKET_ERROR==nSelectRet)    
   
  {    
   
  nErrorCode=WSAGetLastError();    
   
  TRACE("select   write   status   errorcode=%d",nErrorCode);    
   
  ::closesocket(sConnect);    
   
  //goto   重新连接(客户方),或服务线程退出(服务方);    
   
  }    
   
  if(nSelectRet==0)//超时发生,缓冲满或网络忙    
   
  {    
   
  //继续查写状态或查读状态    
   
  }    
   
  else    
   
  {    
   
  //发送    
   
  }    
   
  5、改变TCP收发缓冲区大小    
   
  系统默认为8192,利用如下方式可改变。    
   
  SOCKET   sConnect;    
   
  sConnect=::socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);    
   
  int   nrcvbuf=1024*20;    
   
  int   err=setsockopt(    
   
  sConnect,                    
   
  SOL_SOCKET,                  
   
  SO_SNDBUF,//写缓冲,读缓冲为SO_RCVBUF    
   
  (char   *)&nrcvbuf,    
   
  sizeof(nrcvbuf));    
   
  if   (err   !=   NO_ERROR)    
   
  {    
   
  TRACE("setsockopt   Error!/n");    
   
  }    
   
  在设置缓冲时,检查是否真正设置成功用    
   
  int   getsockopt(    
   
  SOCKET   s,                    
   
  int   level,                  
   
  int   optname,              
   
  char   FAR   *optval,    
   
  int   FAR   *optlen      
   
  );    
   
  6、服务方同一端口多IP地址的bind和listen    
   
  在可靠性要求高的应用中,要求使用双网和多网络通道,再服务方很容易实现,用如下方式可建立客户对本机所有IP地址在端口3024下的请求服务。    
   
  SOCKET   hServerSocket_DS=INVALID_SOCKET;    
   
  struct   sockaddr_in   HostAddr_DS;//服务器主机地址    
   
  LONG   lPort=3024;    
   
  HostAddr_DS.sin_family=AF_INET;    
   
  HostAddr_DS.sin_port=::htons(u_short(lPort));    
   
  HostAddr_DS.sin_addr.s_addr=htonl(INADDR_ANY);    
   
       
   
  hServerSocket_DS=::socket(   AF_INET,   SOCK_STREAM,IPPROTO_TCP);    
   
       
   
  if(hServerSocket_DS==INVALID_SOCKET)    
   
  {    
   
  AfxMessageBox("建立数据服务器SOCKET   失败!");    
   
  return   FALSE;    
   
  }    
   
       
   
  if(SOCKET_ERROR==::bind(hServerSocket_DS,(struct    
   
  sockaddr   *)(&(HostAddr_DS)),sizeof(SOCKADDR)))    
   
  {    
   
  int     nErrorCode=WSAGetLastError   ();    
   
  TRACE("bind   error=%d/n",nErrorCode);                                  
   
  AfxMessageBox("Socket   Bind   错误!");    
   
  return   FALSE;    
   
  }    
   
  if(SOCKET_ERROR==::listen(hServerSocket_DS,10))//10个客户    
   
  {    
   
  AfxMessageBox("Socket   listen   错误!");    
   
  return   FALSE;    
   
  }    
   
  AfxBeginThread(ServerThreadProc,NULL,THREAD_PRIORITY_NORMAL);    
   
  在客户方要复杂一些,连接断后,重联不成功则应换下一个IP地址连接。也可采用同时连接好后备用的方式。    
   
       
   
  7、用TCP/IP   Winsock实现变种Client/Server    
   
  传统的Client/Server为客户问、服务答,收发是成对出现的。而变种的Client/Server是指在连接时有客户和服务之分,建立好通信连 接后,不再有严格的客户和服务之分,任何方都可主动发送,需要或不需要回答看应用而言,这种方式在工控行业很有用,比如RTDB作为I/O   Server的客户,但I/O   Server也可主动向RTDB发送开关状态变位、随即事件等信息。在很大程度上减少了网络通信负荷、提高了效率。    
   
  采用1-6的TCP/IP编程要点,在Client和Server方均已接收优先,适当控制时序就能实现。

socket的延时技巧相关推荐

  1. STM32系统滴答_及不可不知的延时技巧

    我想每个单片机爱好者及工程开发设计人员都有过点灯的经历.流水灯是个好东西,尤其是在调试资源有限的环境中,有时会帮上大忙. 然在最初入门时,如何让这些小灯们按照我们的想法欢快地跑起来呢,绝大多数小朋友的 ...

  2. STM32系统滴答_及不可不知的延时技巧 - (上)

    文章转载自https://my.oschina.net/czzhu/blog/228596:作者:小汉憨憨 摘要: 尤应强调注意的是SysTick 中断优先级. 我想每个单片机爱好者及工程开发设计人员 ...

  3. STM32系统滴答_及不可不知的延时技巧 - (下)

    本文转载自https://my.oschina.net/czzhu/blog/261802:作者:小汉憨憨 摘要: 单片机非阻塞延时巧妙的软件设计. 下面为大家介绍一个曾见过的在裸机系统中,非阻塞延时 ...

  4. python socket tcp6_渗透技巧——使用远程桌面协议建立通道

    0x00 前言 最近从@cpl3h的博客中学到了使用远程桌面协议建立通道的方法. 本文将对这个方法进行整理,结合自己的经验,添加个人理解. 学习地址: 0x01 简介 本文将要介绍以下内容: ·使用场 ...

  5. Socket连接的小知识,和一个疑难杂症

    我这篇文章说一个Socket的小技巧,另外咨询一个问题 这些天重点攻打Socket 以前总觉得Socket编程应该比较容易,也做过简单的Socket程序. 但真正要应用时,发现有很大问题! 我用C#语 ...

  6. 百度前200页部分答案(初稿)

    1操作系统中 heap 和 stack 的区别 栈(stack)与堆(heap)都是Java用来在Ram中存放数据的地方.Java自动管理栈和堆,程序员不能直接地设置栈或堆. 在函数中定义的一些基本类 ...

  7. java网页解析包_java 网页解析工具包 Jsoup

    Jsoup是一个非常好的解析网页的包,用java开发的,提供了类似DOM,CSS选择器的方式来查找和提取文档中的内容. 相关资料如下: 今天做了一个Jsoup解析网站的项目,使用Jsoup.conne ...

  8. java org.jsoup does not exist_java使用Jsoup连接网站超时的解决方法

    今天做了一个Jsoup解析网站的项目,使用Jsoup.connect(url).get()连接某网站时偶尔会出现 java.net.SocketTimeoutException:Read timed ...

  9. Tomcat7.0源码分析——请求原理分析(上)

    前言 谈起Tomcat的诞生,最早可以追溯到1995年.近20年来,Tomcat始终是使用最广泛的Web服务器,由于其使用Java语言开发,所以广为Java程序员所熟悉.很多早期的J2EE项目,由程序 ...

最新文章

  1. 推荐一个 Python 手绘图形库(附代码)
  2. java map to map 拷贝_java复制Map 对象(深拷贝和浅拷贝)
  3. 怎样新建Oracle数据库
  4. SpringBoot+Spring Security验证密码MD5加密
  5. Linux 下重新编译Windows下生成的Qt工程
  6. poj 1862 Stripies/优先队列
  7. Qt6 在线安装图文步骤
  8. mac 显示隐藏文件的命令行和快捷键
  9. matlab 度表示,在matlab中,单精度类型用关键字()表示,双精度类型用关键字()表示...
  10. Servlet中forward和redirect的区别
  11. Excel数据透视表如何创建?
  12. Python基于随机游走模型的PageRank算法及应用
  13. android程序怎样远程控制手机,如何用手机远程控制手机(安卓),看这就够了,怎样使用手机远程控制它人手机...
  14. SaaS多租户管理系统是什么?SaaS多租户平台应用管理功能有哪些?
  15. SourceInsight4.0自定义编译命令
  16. 【博客181】查看一个端口是否被占用
  17. 爱做梦的人工智能「Stabled Diffusion」
  18. steam你画我猜中文版
  19. windows下命令行解压zip文件
  20. 指纹识别遇水失灵?那是你的手机没有这项黑科技

热门文章

  1. 365天挑战LeetCode1000题——Day 117 矩形区域不超过 K 的最大数值和
  2. 判断点是否在视景体内的参考资料
  3. 有趣并不能拯救 Web3 游戏
  4. centos 7.6——Nginx中rewrite模块应用(location)——基于域名的跳转等
  5. sqlserver数据库清理(收缩文件)
  6. CSS 背景色 背景图片 渐变背景 - 径向渐变 background-image:radial-gradient()
  7. 提高篇-深度优先搜索DFS与剪枝-《算法笔记》同步笔记总结与补充
  8. 对SSM框架中Dao层,Mapper层,controller层,service层,model层,entity层等层的理解
  9. 关于ATM渗透与欺诈的知识点Part 1
  10. 赌你无法坚持看完的nginx配置文件解析