c - 为什么在 tcp 套接字上写入会阻塞?

标签 c sockets tcp ftp

我正在为学校项目编写简单的 FTP 服务器,但在文件传输方面遇到问题。

事实上,当发送命令 PASV 时,我创建一个具有指定端口的套接字并监听,但稍后当发送命令 RETR 并且我尝试在套接字文件描述符上写入文件时,写入会阻止执行程序和ftp客户端一直在等待。

为什么会出现写阻塞?

这个函数创建我的套接字

int     create_s_socket(struct sockaddr_in *sock, int port)                                    
{                                                                                              
  int           socket_fd;                                                                     
  int           enable;                                                                        

  if ((socket_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)                                     
    return (-1);                                                                               
  enable = 1;                                                                                  
  if (setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)) < 0)               
    return (-1);                                                                               
  sock->sin_family = AF_INET;                                                                  
  sock->sin_addr.s_addr = htonl(INADDR_LOOPBACK);                                              
  sock->sin_port = htons(port);                                                                
  if (bind(socket_fd, (struct sockaddr *)sock, sizeof(*sock)) < 0)                             
    return (-1);                                                                               
  return (socket_fd);                                                                          
}

该函数open打开数据连接(被动模式)

void                    cmd_pasv(t_handle *hdl)                                                
{                                                                                              
  struct sockaddr_in    data_sock;                                                             
  uint16_t              port;                                                                  
  socklen_t             len;                                                                   

  len = sizeof(data_sock);                                                                     
  if ((hdl->data_fd = create_s_socket(&data_sock, 0)) != -1)                                   
    {                                                                                          
      listen(hdl->data_fd, 5);                                                                 
      getsockname(hdl->data_fd, (struct sockaddr *)&data_sock, &len);                          
      port = ntohs(data_sock.sin_port);                                                        
      printf("port = %d\n", port);                                                             
      set_rep(hdl, 227, "Entering Passive Mode (%d,%d,%d,%d,%d,%d).",                          
              (int)(data_sock.sin_addr.s_addr & 0xFF),                                         
              (int)((data_sock.sin_addr.s_addr & 0xFF00) >> 8),                                
              (int)((data_sock.sin_addr.s_addr & 0xFF0000) >> 16),                             
              (int)((data_sock.sin_addr.s_addr & 0xFF000000) >> 24),                           
              (int)(port / 256), (int)(port % 256));                                           
      printf("data fd %d\n", hdl->data_fd);                                                    
    }                                                                                          
  else                                                                                         
    set_rep(hdl, 500, "Canno open data connection");                                           
}

该函数打开并通过数据线发送文件

void            cmd_retr(t_handle *hdl)                                                        
{                                                                                              
  char          *fullpath;                                                                     
  FILE          *file;                                                                         
  size_t        nread;                                                                         
  char          buf[BLOCK_SIZE];                                                               

  log_msg(INFO, "data fd is %d", hdl->data_fd);                                                
  if (hdl->data_fd > 0)                                                                        
    {                                                                                          
      log_msg(INFO, "data fd is %d", hdl->data_fd);                                            
      if (hdl->cmd_arg)                                                                        
        {                                                                                      
          log_msg(INFO, "file to uploadis %s", hdl->cmd_arg);                                  
          fullpath = malloc(sizeof(char) *                                                     
                            strlen(hdl->path) + strlen(hdl->cmd_arg) + 2);                     
          sprintf(fullpath, "%s/%s", hdl->path, hdl->cmd_arg);                                 
          log_msg(INFO, "full path is %s", fullpath);                                          
          if ((file = fopen(fullpath, "r")) != NULL)                                           
            {                                                                                  
              log_msg(INFO, "file opened correctly");                                          
              while ((nread = fread(buf, sizeof(char), BLOCK_SIZE, file)) > 0)                 
                {                                                                              
                  log_msg(INFO, "read %d bytes \"%s\"", nread, buf);                           
                  if (write(hdl->data_fd, buf, nread) == -1)                                   
                    log_msg(ERROR, "write: %s", strerror(errno));                              
                }                                                                              
              if (nread < 0)                                                                   
                log_msg(ERROR, "read: %s", strerror(errno));                                   
            }                                                                                  
          else                                                                                 
            set_rep(hdl, 000, "File \"%s\" not found", fullpath);                              
          free(fullpath);                                                                      
        }                                                                                      
      else                                                                                     
        set_rep(hdl, 000, "Missing arg");                                                      
    }                                                                                          
  else                                                                                         
    set_rep(hdl, 000, "Data connection not open fd %d", hdl->data_fd);                         
}            

谢谢;)

最佳答案

In fact, when the command PASV is sent, I create a socket with the specified port and listen but then later when the command RETR is sent and I try to write the file on the socket file descriptor, the write block the excecution of the program and the ftp client keep waiting.

Why is this write blocking ?

尚不清楚您是否已提供所有相关代码。如果有,那么问题肯定是您正在尝试写入服务器套接字。您应该改为 accept() 与该套接字的连接,验证它是否来自预期的客户端,并使用生成的已连接套接字(它将具有不同的文件描述符)进行沟通。

关于c - 为什么在 tcp 套接字上写入会阻塞?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43924899/

相关文章:

c++ - 函数指针需要和号吗

c - 实现 strcpy : what if the destination is shorter than the source?

ios - GCDAsyncSocket-如何使其连接?

python - 家庭作业 - Python 代理服务器

http - XMLHttpRequest 和常规 HTTP 请求之间的数据包级区别是什么?

c++ - C/C++ 中的累积正态分布函数

用于网络摄像头捕获的 C 程序

Python TCP 几个同时监听多个端口

http - 有没有监控HTTP响应的工具?

tcp - 开发无服务器局域网聊天程序求助!