接字描述符和套接字数据结构的对应关系。该表中有一个字段存放新创建的套接字的描述符,另一个
字段存放套接字数据结构的地址,因此根据套接字描述符就可以找到其对应的套接字数据结构。每个
进程在自己的进程空间里都有一个套接字描述符表但是套接字数据结构都是在操作系统的内核缓冲里。
下面是一个创建流套接字的例子:
struct protoent *ppe;
ppe=getprotobyname("tcp");
SOCKET ListenSocket=socket(PF_INET,SOCK_STREAM,ppe->p_proto);
四、closesocket 函数
int closesocket(
SOCKET s
);
closesocket 函数用来关闭一个描述符为 s 套接字。由于每个进程中都有一个套接字描述符表,表中
的每个套接字描述符都对应了一个位于操作系统缓冲区中的套接字数据结构,因此有可能有几个套接
字描述符指向同一个套接字数据结构。套接字数据结构中专门有一个字段存放该结构的被引用次数,
即有多少个套接字描述符指向该结构。当调用 closesocket 函数时,操作系统先检查套接字数据结构
中的该字段的值,如果为 1,就表明只有一个套接字描述符指向它,因此操作系统就先把 s 在套接字描
述符表中对应的那条表项清除,并且释放 s 对应的套接字数据结构;如果该字段大于 1,那么操作系统
仅仅清除 s 在套接字描述符表中的对应表项,并且把 s 对应的套接字数据结构的引用次数减 1。
closesocket 函数如果执行成功就返回 0,否则返回 SOCKET_ERROR。
五、send 函数
int send(
SOCKET s,
const char FAR *buf,
int len,
int flags
);
不论是客户还是服务器应用程序都用 send 函数来向 TCP 连接的另一端发送数据。客户程序一般用 se
nd 函数向服务器发送请求,而服务器则通常用 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 中的数据 c
opy 到 s 的发送缓冲区的剩余空间里)。如果 send 函数 copy 数据成功,就返回实际 copy 的字节数,如
果 send 在 copy 数据时出现错误,那么 send 就返回 SOCKET_ERROR;如果 send 在等待协议传
送数据时网络断开的话,那么 send 函数也返回 SOCKET_ERROR。要注意 send 函数把 buf 中的数
据成功 copy 到 s 的发送缓冲的剩余空间里后它就返回了,但是此时这些数据并不一定马上被传到连接
的另一端。如果协议在后续的传送过程中出现网络错误的话,那么下一个 Socket 函数就会返回 SOCKET