阻塞模式下,对基本套接字函数的理解

下面讨论的都是阻塞模式下的socket
bind
connect
listen和accept
send和recv
closesocket
 

bind

int bind(int sockfd, const struct sockaddr *myaddr, int addrLen);
bind将本地的一个ip和端口号赋给了一个socket,此时这个socket就具有了此ip和端口号的所有权,其他socket不能再次绑定。
    此后,当此ip和端口号上有数据到来时,我们便可以调用recv来获取数据了。
    bind指定了TCP通信的本地地址
 

connect

int connect(int sockfd, const struct sockaddr *servaddr, int addrLen);
这个函数开始了TCP三次握手的过程。
    1)客户端调用connect -> 向服务器发送一个SYN分节
    2)服务器端 -> 向客户端发送一个SYN分节和一个ACK
    3)客户端接收到SYN分节和ACK,并向服务器发送一个ACK
        此时三次握手的过程完成,connect返回
可能发生的错误:
1) TCP客户收不到SYN分节,发生ETIMEOUT错误
2) TCP客户没有收到SYN却收到了RST,说明目标机器没有在此端口监听,发生ECONNREFUSED错误
3) 如果找不到目标主机,会产生ICMP错误(目标主机不可达),此时发生ENETUNREACH错误
对于客户端来说,connect指定了TCP通信的对端地址。此后,我们便可以向对端发送数据了。
 

listen和accept

    当一个连接请求到达服务器时(即一个SYN分节),如果服务器在对应端口上有已监听的socket,那么便响应一个SYN和ACK,否则响应一个RST。
    而listen便是告诉系统,现在这个socket要监听这个端口了。
    系统会为每个监听套接字分配两个队列: 
        未完成连接队列(处于SYN_RCVD状态):我们正在等待三次握手完成
        已完成连接队列(ESTABLISHED状态) :我们已经完成连接了,快调用accept将我们取走吧。
    当我们调用accept时,如果已完成连接队列有已完成的连接,系统便将其取出来,并立即返回。
                        如果已完成连接队列为空,则等待,直到不空。
 

send和recv

    int send(int sock, const char *buf, int len, int flags);
        send只是将buf中的数据拷贝到TCP的发送缓冲区。
        除非TCP发送缓冲区是满的,否则send是不会阻塞的。
    int recv(int sock, const char *buf, int len, int flags);
        recv只是将TCP接收缓冲区中的数据拷贝到buf中。
        除非TCP接收缓冲区是空的,否则recv是不会阻塞的。
 

closesocket

    int closesocket(int sock);
    此函数只是将sock标记为已经关闭,之后对sock调用send,recv等函数都将失败。
    假设此socket的引用计数在,closesocket后置为0,那么还会促发TCP连接释放序列,即发送FIN分节。
posted on 2013-05-31 17:55  sanlo  阅读(1748)  评论(0编辑  收藏  举报