V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Distributions
Ubuntu
Fedora
CentOS
中文资源站
网易开源镜像站
salamanderMH
V2EX  ›  Linux

ftp client 发送了 STOR 命令后,命令端口就阻塞了,我关闭了数据端口了

  •  
  •   salamanderMH · 2018-06-20 14:50:00 +08:00 · 2331 次点击
    这是一个创建于 2335 天前的主题,其中的信息可能已经有所发展或是发生改变。

    问题

    代码

    开了一个子进程来发送文件,发送完毕之后就 close 了 client_data_socket (数据 socket )

    // 非阻塞
    set_flag(client_data_socket, O_NONBLOCK);
    pid_t pid;
    if ((pid = fork()) < 0) {
        printf("fork error");
        continue;
    } else if (pid == 0) {
        FILE *fp;
        if ((fp = fopen(filename, "rb")) == NULL)
        {
            close(client_data_socket);
            printf("open file failed\n");
            exit(1);
        }
        size_t char_size = sizeof(char);
        char data_buffer[FILE_READ_BUFFER_SIZE];
        int numread;
        for (;;)
        {
            bzero(data_buffer, FILE_READ_BUFFER_SIZE);
            numread = fread(data_buffer, char_size, FILE_READ_BUFFER_SIZE, fp);
            if (numread < 0)
            {
                printf("read file failed\n");
                break;
            } 
            else if (numread > 0)
            {
                int length = send(client_data_socket, data_buffer, numread, 0);
                if (length == 0)
                {
                    break;
                }
                else if (length < 0)
                {
                    if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)
                    {
                        continue;
                    }
                    printf("[PUT] command send data failed\n");
                    exit(1);
                }
            }
            if (numread == FILE_READ_BUFFER_SIZE) continue;
            else {
                break;
            }
        }
        close(client_data_socket);
        fclose(fp);
        exit(0);
    } else {
        int status = 0;
        waitpid(pid, &status, 0);
        if (status == 0)
            printf("send file %s complete.\n", filename);
        else 
            printf("send file %s failed.\n", filename);
    }
    

    然后,发送别的命令在 recv 的时候,命令端 socket 就阻塞了
    Github

    4 条回复    2018-06-22 09:08:08 +08:00
    MeteorCat
        1
    MeteorCat  
       2018-06-20 16:22:39 +08:00
    numread < 0
    length == 0
    errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR
    这几个都是直接 break|container 之后不做 socket_close()吗?
    salamanderMH
        2
    salamanderMH  
    OP
       2018-06-20 16:34:33 +08:00
    @MeteorCat for 循环下有 close(client_data_socket);
    linyinma
        3
    linyinma  
       2018-06-20 17:47:46 +08:00
    神一样的代码,头文件包含函数,main 函数实现所有逻辑,能不能稍微模块化一下
    salamanderMH
        4
    salamanderMH  
    OP
       2018-06-22 09:08:08 +08:00
    @MeteorCat
    找到了原因:
    shutdown 可以选择关闭某个方向或者同时关闭两个方向,shutdown how = 0 or how = 1 or how = 2 (SHUT_RD or SHUT_WR or SHUT_RDWR),后两者可以保证对等方接收到一个 EOF 字符(即发送了一个 FIN 段),而不管其他进程是否已经打开了这个套接字。而 close 不能保证,只有当某个 sockfd 的引用计数为 0,close 才会发送 FIN 段,否则只是将引用计数减 1 而已。也就是说只有当所有进程(可能 fork 多个子进程都打开了这个套接字)都关闭了这个套接字,close 才会发送 FIN 段。
    因为我的 client_data_socket 是在父进程产生的,子进程又引用了,所以我需要用 shutdown
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3016 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 96ms · UTC 14:06 · PVG 22:06 · LAX 06:06 · JFK 09:06
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.