首页 > socket 通信流程示意图的理解

socket 通信流程示意图的理解

对 socket 的认识一直不够深入,之前一直是照类似于下面这样的图在理解

图中显示serveraccept,然后才是client发送connect

while(1){
    clin_len = sizeof(clin_addr);
    printf("1111\n");
    cfd = accept(lfd, (struct sockaddr *)&clin_addr, &clin_len);
    printf("2222\n");
    ...

当服务器端程序启动的时候,会先打印出1111,当有客户端连接的时候才会打印出2222,也就证明了在上面的代码中是先有了acceptconnect的。

而在使用select模型的时候,把服务器的监听套截字描述符加入到 select read fd set中之后,默认是没有数据可读的,只有当有客户端连接的之后,才调用accept,如下代码:

FD_ZERO(&read_set);
FD_SET(listenfd,&read_set);
while(1){
        struct sockaddr_in addr;  
        read_set = allset;
        fd_ready_num = select(maxfd, &read_set, NULL, NULL, NULL);
  
        if (FD_ISSET(listenfd,&read_set))
        {
            sin_size = sizeof(addr);
            if ((connectfd = accept(listenfd, (struct sockaddr *)&addr, &sin_size)) == -1)
            {
                perror("接收错误\\n");
                continue;
            }
...

当有客户端连接过来之后,listenfd有数据可读。


accept 翻译成人类的语言来说就是(服务员)「接受顾客的请求」,connect 就是(顾客)「上门寻求服务」。所以没有客户端连接的时候,accept 就在那里等着。那个传入的客户端地址加粗文字的参数是用来返回数据的加粗文字,因为 C 里边没法返回一个结构体,更没法返回多个值。

第一个图说的是函数调用的时机,而不是它返回的时机。第二个图则相反。

当服务器端程序启动的时候,会先打印出1111,当有客户端连接的时候才会打印出2222,也就证明了在上面的代码中是先有了accept再connect的。

这只能说明 connect 会导致执行状态的 accept 返回,并不能说明你不 accept 对端就不能成功地 connect。一个肯定的事例并不排除其否定事例的存在。


其实呢,这两种都不能算是错但也不是完全对,只是第一种好一点儿而已。
listen之后,客户端就可以链接服务器了,连接中需要的各种握手都是操作系统帮你完成的。
acceptselect从作用上来说都是判断有没有客户端连接进来。accept只是一种专用的判断:

  1. accept 是无限等待的

  2. accept 只是判断有没有客户端连接进来

  3. 如果同时有多个客户端连接进来,accept 只会返回其中一个连接的描述符,其他的要等下次(下下次。。。)调用accept

也就是说 accept 是一种同步模型,调用这个这个函数的意思就是,判断有没有客户端连接进来,如果有就返回这个链接的描述符(同时把客户端的地址放到第二个参数指向的位置),如果没有客户端连接进来,就无限的等待直到有客户端连接进来,再返回这个客户端的连接描述符和地址。

这两幅图都只是accept在上述两种情况下不同的行为而已,所以说都不能说是错的,也不能说是对的。只是第一种好一点儿而已:(如果没有连接进来)执行到accept应该要表明它是停止在这里的,等到有连接进来才会执行accept的下一句,从这方面说第一个图比较好,但是不应该阻塞accept不应该加那个箭头。从时间上来说一般执行listen之后立即执行accept所以一般情况下这之间很少会有客户端连接。从这方面来说也是第一个图好一点。

【热门文章】
【热门文章】