一、Socket中send的普通执行流程。
当调用该函数时,send先比较待发送数据的长度len和套接字s的发送缓冲的长度,
(1) 如果len大于s的发送缓冲区的长度,该函数返回SOCKET_ERROR;
(2) 如果len小于或者等于s的发送缓冲区的长度,那么send先检查协议是否正在发送s的发送缓冲中的数据,就是等待协议把数据发送完
(3) 如果协议还没有开始发送s的发送缓冲中的数据或者s的发送缓冲中没有数据,那么send就比较s的发送缓冲区的剩余空间和len
1> 如果len大于剩余空间大小,send就一直等待协议把s的发送缓冲中的数据发送完
2> 如果len小于剩余空间大小,send就仅仅把buf中的数据copy到剩余空间里(注意并不是send把s的发送缓冲中的数据传到连接的另一端的,而是协议传的,send仅仅是把buf中的数据copy到s的发送缓冲区的剩余空间里)。
(4) 如果send函数copy数据成功,就返回实际copy的字节数,如果send在copy数据时出现错误,那么send就返回SOCKET_ERROR;
(5) 如果send在等待协议传送数据时网络断开的话,那么send函数也返回SOCKET_ERROR。
要注意send函数把buf中的数据成功copy到s的发送缓冲的剩余空间里后它就返回了,但是此时这些数据并不一定马上被传到连接的另一端。如果协议在后续的传送过程中出现网络错误的话,那么下一个Socket函数就会返回SOCKET_ERROR。(每一个除send外的Socket函数在执行的最开始总要先等待套接字的发送缓冲中的数据被协议传送完毕才能继续,如果在等待时出现网络错误,那么该Socket函数就返回SOCKET_ERROR)
二、而对于不同进程或线程访问向同一个Socket传递数据(即使用send时),是否会出现数据出错问题
在TCP/TP卷2中有这样的结构体
struct sockbuf{
short sb_flags; .......... }so_recv,so_snd; 其中flag 有这几种标志: SB_LOCK;一个进程已经锁定了插口缓存 SB_WANT;一个进程正在等待给插口缓存加锁. sblock, sbunlock, sbwait(page 388,389)//还有些宏和函数来管理插口的发送缓存和接收缓存
而在(tcp/ip 卷2, page 394,395)找到了send的实现 有如下代码:
if(error = sblock(&so->so_snd, SBLOCKWAIT(flag))) goto out; do{ ....... } 可以看到send在向缓冲传送数据之前,首先会对缓冲加锁.通过加锁确保多个进程或线程按序互斥访问插口缓冲 所以说多个线程或进程向同一个Socket发送数据时(利用send)根本不需要加锁,系统已经为缓冲区加过锁了.