转自:http://www.cppblog.com/aaxron/archive/2012/04/27/172891.html

在发送端,一次发送4092个字节,
在接收端,一次接收4092个字节,
但是在接收端,偶尔会出现 socket.receive 接收不全的情况 ,

ret = sock.recv(bBuffer,iBufferLen,0); //也有可能无法收到全部数据!
必须要考虑0 < ret < iBufferLen的情况:继续接收iBufferLen - ret字节,然后合并
注意第recv函数的第四个参数:

MSG_WAITALL The receive request will complete only when one of the following events occurs:

  • The buffer supplied by the caller is completely full.
  • The connection has been closed.
  • The request has been canceled.

Note that if the underlying transport does not support MSG_WAITALL, or if the socket is in a non-blocking mode, then this call will fail with WSAEOPNOTSUPP. Also, if MSG_WAITALL is specified along with MSG_OOB, MSG_PEEK, or MSG_PARTIAL, then this call will fail with WSAEOPNOTSUPP. This flag is not supported on datagram sockets or message-oriented CO sockets.

Socket的Send,Recv的长度问题:

一个包没有固定长度,以太网限制在46-1500字节,1500就是以太网的MTU,超过这个量,TCP会为IP数据报设置偏移量进行分片传输,现在一般可允许应用层设置8k(NTFS系统)的缓冲区,8k的数据由底层分片,而应用层看来只是一次发送。
windows的缓冲区经验值是4k。
Socket本身分为两种,流(TCP)和数据报(UDP),你的问题针对这两种不同使用而结论不一样。甚至还和你是用阻塞、还是非阻塞Socket来编程有关。
1、通信长度,这个是你自己决定的,没有系统强迫你要发多大的包,实际应该根据需求和网络状况来决定。对于TCP,这个长度可以大点,但要知道,Socket内部默认的收发缓冲区大小大概是8K,你可以用SetSockOpt来改变。但对于UDP,就不要太大,一般在1024至10K。注意一点,你无论发多大的包,IP层和链路层都会把你的包进行分片发送,一般局域网就是1500左右,广域网就只有几十字节。分片后的包将经过不同的路由到达接收方,对于UDP而言,要是其中一个分片丢失,那么接收方的IP层将把整个发送包丢弃,这就形成丢包。显然,要是一个UDP发包佷大,它被分片后,链路层丢失分片的几率就佷大,你这个UDP包,就佷容易丢失,但是太小又影响效率。最好可以配置这个值,以根据不同的环境来调整到最佳状态。
send()函数返回了实际发送的长度,在网络不断的情况下,它绝不会返回(发送失败的)错误,最多就是返回0。对于TCP你可以写一个循环发送。当send函数返回SOCKET_ERROR时,才标志着有错误。但对于UDP,你不要写循环发送,否则将给你的接收带来极大的麻烦。所以UDP需要用SetSockOpt来改变Socket内部Buffer的大小,以能容纳你的发包。明确一点,TCP作为流,发包是不会整包到达的,而是源源不断的到,那接收方就必须组包。而UDP作为消息或数据报,它一定是整包到达接收方。
2、关于接收,一般的发包都有包边界,首要的就是你这个包的长度要让接收方知道,于是就有个包头信息,对于TCP,接收方先收这个包头信息,然后再收包数据。一次收齐整个包也可以,可要对结果是否收齐进行验证。这也就完成了组包过程。UDP,那你只能整包接收了。要是你提供的接收Buffer过小,TCP将返回实际接收的长度,余下的还可以收,而UDP不同的是,余下的数据被丢弃并返回WSAEMSGSIZE错误。注意TCP,要是你提供的Buffer佷大,那么可能收到的就是多个发包,你必须分离它们,还有就是当Buffer太小,而一次收不完Socket内部的数据,那么Socket接收事件(OnReceive),可能不会再触发,使用事件方式进行接收时,密切注意这点。这些特性就是体现了流和数据包的区别。
补充一点,接收BuffSize >= 发送BuffSize >= 实际发送Size,对于内外部的Buffer都适用,上面讲的主要是Socket内部的Buffer大小关系。
3、TCP是有多少就收多少,如果没有当然阻塞Socket的recv就会等,直到有数据,非阻塞Socket不好等,而是返回WSAEWOULDBLOCK。UDP,如果没有数据,阻塞Socket就会等,非阻塞Socket也返回WSAEWOULDBLOCK。如果有数据,它是会等整个发包到齐,并接收到整个发包,才返回。

send函数

  1. int send( SOCKET s,const char* buf,int len,int flags);

不论是客户还是服务器应用程序都用send函数来向TCP连接的另一端发送数据。

客户程序一般用send函数向服务器发送请求,而服务器则通常用send函数来向客户程序发送应答。

该函数的第一个参数指定发送端套接字描述符;

第二个参数指明一个存放应用程序要发送数据的缓冲区;

第三个参数指明实际要发送的数据的字节数;

第四个参数一般置0。

这里只描述同步Socket的send函数的执行流程。当调用该函数时,send先比较待发送数据的长度len和套接字s的发送缓冲的 长度,如果len大于s的发送缓冲区的长度,该函数返回SOCKET_ERROR;如果len小于或者等于s的发送缓冲区的长度,那么send先检查协议 是否正在发送s的发送缓冲中的数据,如果是就等待协议把数据发送完,如果协议还没有开始发送s的发送缓冲中的数据或者s的发送缓冲中没有数据,那么 send就比较s的发送缓冲区的剩余空间和len,如果len大于剩余空间大小send就一直等待协议把s的发送缓冲中的数据发送完,如果len小于剩余 空间大小send就仅仅把buf中的数据copy到剩余空间里(注意并不是send把s的发送缓冲中的数据传到连接的另一端的,而是协议传的,send仅仅是把buf中的数据copy到s的发送缓冲区的剩余空间里)。如果send函数copy数据成功,就返回实际copy的字节数,如果send在copy数据时出现错误,那么send就返回SOCKET_ERROR;如果send在等待协议传送数据时网络断开的话,那么send函数也返回SOCKET_ERROR。

要注意send函数把buf中的数据成功copy到s的发送缓冲的剩余空间里后它就返回了,但是此时这些数据并不一定马上被传到连接的另一端。如 果协议在后续的传送过程中出现网络错误的话,那么下一个Socket函数就会返回SOCKET_ERROR。(每一个除send外的Socket函数在执 行的最开始总要先等待套接字的发送缓冲中的数据被协议传送完毕才能继续,如果在等待时出现网络错误,那么该Socket函数就返回 SOCKET_ERROR)

注意:在Unix系统下,如果send在等待协议传送数据时网络断开的话,调用send的进程会接收到一个SIGPIPE信号,进程对该信号的默认处理是进程终止。

recv函数

  1. int recv( SOCKET s,char* buf,int len,int flags);

不论是客户还是服务器应用程序都用recv函数从TCP连接的另一端接收数据。

该函数的第一个参数指定接收端套接字描述符;

第二个参数指明一个缓冲区,该缓冲区用来存放recv函数接收到的数据;

第三个参数指明buf的长度;

第四个参数一般置0。

这里只描述同步Socket的recv函数的执行流程。当应用程序调用recv函数时,recv先等待s的发送缓冲 中的数据被协议传送完毕,如果协议在传送s的发送缓冲中的数据时出现网络错误,那么recv函数返回SOCKET_ERROR,如果s的发送缓冲中没有数 据或者数据被协议成功发送完毕后,recv先检查套接字s的接收缓冲区,如果s接收缓冲区中没有数据或者协议正在接收数据,那么recv就一直等待,只到 协议把数据接收完毕。当协议把数据接收完毕,recv函数就把s的接收缓冲中的数据copy到buf中(注意协议接收到的数据可能大于buf的长度,所以 在这种情况下要调用几次recv函数才能把s的接收缓冲中的数据copy完。recv函数仅仅是copy数据,真正的接收数据是协议来完成的),recv函数返回其实际copy的字节数。如果recv在copy时出错,那么它返回SOCKET_ERROR;如果recv函数在等待协议接收数据时网络中断了,那么它返回0。

注意:在Unix系统下,如果recv函数在等待协议接收数据时网络断开了,那么调用recv的进程会接收到一个SIGPIPE信号,进程对该信号的默认处理是进程终止。

  1. #include "socketclient.h"
  2. int main()
  3. {
  4. SocketClient cli;
  5. char* szIp = "127.0.0.1";
  6. WORD wPort = ;
  7. int nRet = cli.Open(szIp,wPort);
  8. if (nRet!=)
  9. {
  10. printf("Open %s:%d error:%d \r\n",szIp,wPort,nRet);
  11. return -;
  12. }
  13. char buf[];
  14. int i=;
  15. DWORD dwTickCount0 = ;
  16. DWORD dwTickCount1 = ;
  17. int nSended = ;
  18. while ()
  19. {
  20. dwTickCount0 = cli.GetTickCount();
  21. //printf("%d,TickCount(0):%u \r\n",i,dwTickCount0);
  22.  
  23. nSended = cli.Send(buf,); //超时2秒发送
  24.  
  25. dwTickCount1 = cli.GetTickCount();
  26. //printf("%d,TickCount(1):%u \r\n",i,dwTickCount1);
  27. //usleep(20*100);
  28. printf("%d,time:%u,sended:%d,err:%d \r\n",i,dwTickCount1 - dwTickCount0,nSended,errno);
  29. if (nSended<)
  30. {
  31. break;
  32. }
  33. i++;
  34. }
  35. }
  1. 1,time:0,sended:1500,err:0
  2. 2,time:0,sended:1500,err:0
  3. 3,time:0,sended:1500,err:0
  4. 4,time:0,sended:1500,err:0
  5. 5,time:0,sended:1500,err:0
  6. 6,time:0,sended:1500,err:0
  7. 7,time:0,sended:1500,err:0
  8. 8,time:1,sended:1500,err:0
  9. 9,time:0,sended:1500,err:0
  10. 10,time:0,sended:1500,err:0
  11. 11,time:0,sended:1500,err:0
  12. 12,time:0,sended:1500,err:0
  13. 13,time:0,sended:1500,err:0
  14. 14,time:0,sended:1500,err:0
  15. 15,time:0,sended:1500,err:0
  16. 16,time:0,sended:1500,err:0
  17. 17,time:0,sended:1500,err:0
  18. 18,time:0,sended:1500,err:0
  19. 19,time:0,sended:1500,err:0
  20. 20,time:0,sended:1500,err:0
  21. 21,time:0,sended:1500,err:0
  22. 22,time:0,sended:1500,err:0
  23. 23,time:0,sended:1500,err:0
  24. 24,time:0,sended:1500,err:0
  25. 25,time:0,sended:1500,err:0
  26. 26,time:0,sended:1500,err:0
  27. 27,time:0,sended:1500,err:0
  28. 28,time:0,sended:1500,err:0
  29. 29,time:0,sended:1500,err:0
  30. 30,time:0,sended:1500,err:0
  31. 31,time:0,sended:1500,err:0
  32. 32,time:0,sended:1500,err:0
  33. 33,time:0,sended:1500,err:0
  34. 34,time:0,sended:1500,err:0
  35. 35,time:0,sended:1500,err:0
  36. 36,time:0,sended:1500,err:0
  37. 37,time:0,sended:1500,err:0
  38. 38,time:0,sended:1500,err:0
  39. 39,time:0,sended:1500,err:0
  40. 40,time:0,sended:1500,err:0
  41. 41,time:0,sended:1500,err:0
  42. 42,time:0,sended:1500,err:0
  43. 43,time:0,sended:1500,err:0
  44. 44,time:0,sended:1500,err:0
  45. 45,time:0,sended:1500,err:0
  46. 46,time:0,sended:1500,err:0
  47. 47,time:0,sended:1500,err:0
  48. 48,time:39,sended:1500,err:0
  49. 49,time:0,sended:1500,err:0
  50. 50,time:0,sended:1500,err:0
  51. 51,time:0,sended:1500,err:0
  52. 52,time:0,sended:1500,err:0
  53. 53,time:0,sended:1500,err:0
  54. 54,time:0,sended:1500,err:0
  55. 55,time:0,sended:1500,err:0
  56. 56,time:0,sended:1500,err:0
  57. 57,time:0,sended:1500,err:0
  58. 58,time:0,sended:1500,err:0
  59. 59,time:0,sended:1500,err:0
  60. 60,time:0,sended:1500,err:0
  61. 61,time:0,sended:1500,err:0
  62. 62,time:0,sended:1500,err:0
  63. 63,time:0,sended:1500,err:0
  64. 64,time:0,sended:1500,err:0
  65. 65,time:0,sended:1500,err:0
  66. 66,time:0,sended:1500,err:0
  67. 67,time:0,sended:1500,err:0
  68. 68,time:0,sended:1500,err:0
  69. 69,time:0,sended:1500,err:0
  70. 70,time:0,sended:1500,err:0
  71. 71,time:0,sended:1500,err:0
  72. 72,time:0,sended:1500,err:0
  73. 73,time:0,sended:1500,err:0
  74. 74,time:0,sended:1500,err:0
  75. 75,time:0,sended:1500,err:0
  76. 76,time:0,sended:1500,err:0
  77. 77,time:0,sended:1500,err:0
  78. 78,time:0,sended:1500,err:0
  79. 79,time:0,sended:1500,err:0
  80. 80,time:0,sended:1500,err:0
  81. 81,time:0,sended:1500,err:0
  82. 82,time:0,sended:1500,err:0
  83. 83,time:0,sended:1500,err:0
  84. 84,time:0,sended:1500,err:0
  85. 85,time:0,sended:1500,err:0
  86. 86,time:0,sended:1500,err:0
  87. 87,time:0,sended:1500,err:0
  88. 88,time:0,sended:1500,err:0
  89. 89,time:0,sended:1500,err:0
  90. 90,time:0,sended:1500,err:0
  91. 91,time:0,sended:1500,err:0
  92. 92,time:0,sended:1500,err:0
  93. 93,time:0,sended:1500,err:0
  94. 94,time:0,sended:1500,err:0
  95. 95,time:0,sended:1500,err:0
  96. 96,time:0,sended:1500,err:0
  97. 97,time:0,sended:1500,err:0
  98. 98,time:0,sended:1500,err:0
  99. 99,time:0,sended:1500,err:0
  100. 100,time:0,sended:1500,err:0
  101. 101,time:0,sended:1500,err:0
  102. 102,time:0,sended:1500,err:0
  103. 103,time:0,sended:1500,err:0
  104. 104,time:0,sended:1500,err:0
  105. 105,time:0,sended:1500,err:0
  106. 106,time:0,sended:1500,err:0
  107. 107,time:0,sended:1500,err:0
  108. 108,time:0,sended:1500,err:0
  109. 109,time:0,sended:1500,err:0
  110. 110,time:0,sended:1500,err:0
  111. 111,time:0,sended:1500,err:0
  112. 112,time:0,sended:1500,err:0
  113. 113,time:0,sended:1500,err:0
  114. 114,time:0,sended:1500,err:0
  115. 115,time:0,sended:1500,err:0
  116. 116,time:0,sended:1500,err:0
  117. 117,time:0,sended:1500,err:0
  118. 118,time:0,sended:1500,err:0
  119. 119,time:0,sended:1500,err:0
  120. 120,time:0,sended:1500,err:0
  121. 121,time:0,sended:1500,err:0
  122. 122,time:0,sended:1500,err:0
  123. 123,time:0,sended:1500,err:0
  124. 124,time:0,sended:1500,err:0
  125. 125,time:1999,sended:340,err:0 //这里出现了发送不全
  126. 126,time:0,sended:1500,err:0
  127. 127,time:0,sended:1500,err:0
  128. 128,time:0,sended:1500,err:0
  129. 129,time:0,sended:1500,err:0
  130. 130,time:0,sended:1500,err:0
  131. 131,time:0,sended:1500,err:0
  132. 132,time:0,sended:1500,err:0
  133. 133,time:0,sended:1500,err:0
  134. 134,time:0,sended:1500,err:0
  135. 135,time:0,sended:1500,err:0
  136. 136,time:0,sended:1500,err:0
  137. 137,time:0,sended:1500,err:0
  138. 138,time:0,sended:1500,err:0
  139. 139,time:0,sended:1500,err:0
  140. 140,time:0,sended:1500,err:0
  141. 141,time:0,sended:1500,err:0
  142. 142,time:0,sended:1500,err:0
  143. 143,time:0,sended:1500,err:0
  144. 144,time:0,sended:1500,err:0
  145. 145,time:0,sended:1500,err:0
  146. 146,time:0,sended:1500,err:0
  147. 147,time:2000,sended:1268,err:0
  148. 148,time:2000,sended:-1,err:11

同样send也会出现和recv一样,会有发送不全的现象.

socket函数send和recv函数的更多相关文章

  1. socket中send和recv函数

    Socket一次Recv接受的字节有限制么? 从套接字接收数据. 返回值是表示接收数据的字符串. 一次接收的最大数据量由bufsize指定.它默认为零. 注意为了最好地匹配硬件和网络现实,bufsiz ...

  2. SOCKET中send和recv函数工作原理与注意点

    https://blog.csdn.net/rankun1/article/details/50488989

  3. socket使用TCP协议时,send、recv函数解析以及TCP连接关闭的问题

    Tcp协议本身是可靠的,并不等于应用程序用tcp发送数据就一定是可靠的.不管是否阻塞,send发送的大小,并不代表对端recv到多少的数据. 在阻塞模式下, send函数的过程是将应用程序请求发送的数 ...

  4. linux Socket send与recv函数详解

    转自:http://www.cnblogs.com/blankqdb/archive/2012/08/30/2663859.html linux send与recv函数详解   1 #include ...

  5. [转]socket使用TCP协议时,send、recv函数解析以及TCP连接关闭的问题

    Tcp协议本身是可靠的,并不等于应用程序用tcp发送数据就一定是可靠的.不管是否阻塞,send发送的大小,并不代表对端recv到多少的数据. 在阻塞模式下, send函数的过程是将应用程序请求发送的数 ...

  6. 分片传输——send和recv函数

    最近在写socket编程收发数据,对于如何发送和接收大量数据,一直在思考.send和recv一般缓存区大小为4K,但是如果你要传输的数据超过了这个标准该如何做呢. 我想到的就是如改写write和rea ...

  7. linux内核中send与recv函数详解

    Linux send与recv函数详解 1.简介 #include <sys/socket.h> ssize_t recv(int sockfd, void *buff, size_t n ...

  8. send()和recv()函数详解

    send()函数 int send( SOCKET s, const char FAR *buf, int len, int flags ); 不论是客户还是服务器应用程序都用send函数来向TCP连 ...

  9. UNIX网络编程——send与recv函数详解

    #include <sys/socket.h> ssize_t recv(int sockfd, void *buff, size_t nbytes, int flags); ssize_ ...

随机推荐

  1. win7下docker环境搭建nginx+php-fpm+easyswoole+lavarel+mysql开发环境

    win7环境基础在上一篇win7下docker环境搭建nginx+php-fpm+easyswoole开发环境中已经详细叙述搭建完成 本篇文章将叙述如何在上述基础上搭建laravel开发环境,这个其实 ...

  2. ThreadLocal和ThreadLocalMap源码分析

    目录 ThreadLocal和ThreadLocalMap源码分析 背景分析 定义 例子 源码分析 ThreadLocalMap源码分析 ThreadLocal源码分析 执行流程总结 源码分析总结 T ...

  3. 【原创】MySQL5.7.18(ptmalloc VS tcmalloc VS jemalloc)性能测试

    ptmalloc(glibc的malloc)是Linux提供的内存分配管理模块,目前我们MySQL默认使用的内存分配模块. tcmalloc是Google提供的内存分配管理模块. jemalloc是F ...

  4. python流行的原因

    12~14年是云计算最火的几年,大批创业公司和巨头挤破头地进军云计算领域,大家都在做IAAS,最著名的云计算开源平台OpenStack 就是基于Python 开发的,为此催生出不少Python 岗位 ...

  5. NetCore+Dapper WebApi架构搭建(六):添加JWT认证

    WebApi必须保证安全,现在来添加JWT认证 1.打开appsettings.json添加JWT认证的配置信息 2.在项目根目录下新建一个Models文件夹,添加一个JwtSettings.cs的实 ...

  6. [leetcode DP]72. Edit Distance

    计算最少用多少不把word1变为word2, 思路:建立一个dp表,行为word1的长度,宽为word2的长度 1.边界条件,dp[i][0] = i,dp[0][j]=j 2.最优子问题,考虑已经知 ...

  7. python 列表的浅拷贝和深拷贝

    转自:https://www.cnblogs.com/laolibk/p/7821369.html 浅拷贝 shallow copy 和深拷贝 deep copy list.copy() 浅拷贝:复制 ...

  8. 解决mongo 端口占用问题

    在打开mongod之后如果不用了就按ctrl + c ,就不会出现以下的问题了 执行mongod报错 mongod 2016-08-03T14:31:15.691+0800 I CONTROL [in ...

  9. Git 入门使用

    Git是什么? Git是一个开源的分布式版本控制系统,用于敏捷高效地处理任何或小或大的项目. Git 是 Linus Torvalds 为了帮助管理 Linux 内核开发而开发的一个开放源码的版本控制 ...

  10. luoguP4491 [HAOI2018]染色 广义容斥原理 + FFT

    非常明显的摆了一个NTT模数.... 题目中求恰好\(k\),那么考虑求至少\(k\) 记\(g(k)\)表示至少\(k\)中颜色出现了恰好\(S\)次 那么,\[g(k) = \binom{M}{k ...