套接字编程 - 功能:错误的文件描述符

时间:2018-01-18 15:04:09

标签: c linux sockets udp

我在尝试创建以下代码的函数时遇到问题,因此我可以重复使用它来轻松创建新套接字:

if ( (socket_fd = socket(AF_INET, SOCK_DGRAM, 0) ) < 0 ) /* return 1 if okay */
  {
    printf("ERROR opening socket ... 1");
  }

  serv_addr.sin_family = AF_INET; /*Define the domain used*/
  serv_addr.sin_port = htons(PORT); /*Declare port #PORT to be used*/
  serv_addr.sin_addr.s_addr = inet_addr("INADDR_ANY"); /*Permit any incoming IP address by declaring INADDR_ANY*/

  setsockopt(socket_fd, SOL_SOCKET, SO_RCVTIMEO, (const char *)&tv , sizeof (struct timeval)); 

// Convert IPv4 and IPv6 addresses from text to binary form
if(inet_pton(AF_INET, SERVER, &serv_addr.sin_addr)<=0) 
  {
    printf("\nInvalid address/ Address not supported \n");
    return -1;
  }

if (connect(socket_fd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
  {
    printf("\nConnection Failed  \n");
    return -1;
 }
else
{
  printf("\n Connected \n");
}

上面的代码对我很有用,但是当我尝试创建一个简单的函数来重新组合时,当我尝试使用sendto()发送cmd时,我有错误bad file descriptor

所以这是我的功能:

void open_socket( int s_fd, struct sockaddr_in s_addr, struct timeval tv, char* ID_IP, int ID_Port)
{

    if ( (s_fd = socket(AF_INET, SOCK_DGRAM, 0) ) < 0 ) /* return 1 if okay */
      {
        printf("ERROR opening socket ");
      }

      s_addr.sin_family = AF_INET; /*Define the domain used*/
      s_addr.sin_port = htons(ID_Port); /*Declare port #PORT to be used*/
      s_addr.sin_addr.s_addr = inet_addr("INADDR_ANY"); /*Permit any incoming IP address by declaring INADDR_ANY*/

      setsockopt(s_fd, SOL_SOCKET, SO_RCVTIMEO, (const char *)&tv , sizeof (struct timeval)); /*config du timeout*/

    // Convert IPv4 and IPv6 addresses from text to binary form
    if(inet_pton(AF_INET, ID_IP, &s_addr.sin_addr)<=0)
      {
        printf("\nInvalid address/ Address not supported \n");
      }

    if (connect(s_fd, (struct sockaddr *)&s_addr, sizeof(s_addr)) < 0)
      {
        printf("\nConnection Failed \n");
     }
    else
    {
        printf("Socket Connected\n" );
    }

}

我尝试用:

来调用它
 //SOCKET 1
  struct sockaddr_in serv_addr; /* Server Socket address structure*/
  int serv_len=sizeof(serv_addr);
  int socket_fd;

  struct timeval tv;
  tv.tv_sec=1 ; 
  tv.tv_usec=0; 

  //FUNCTION CALL
  open_socket( socket_fd, serv_addr, tv, SERVER, PORT);

,错误出现在这里:

 //send the message
        if ( (sendto(socket_fd , cmd_final, BUFFLEN , 0 , (struct sockaddr *)&serv_addr, serv_len) ) < 0 )
        {
          perror("ERROR > send cmd failed  : ");
          return 0;
        }

我很确定我正在弄乱一些关于指针的基本信息(我是初学者,而且几年没有用C语言编码)...我尝试了很多不同的东西,却找不到任何解决方案。我希望得到一些帮助或在哪里寻找!

非常感谢!

2 个答案:

答案 0 :(得分:2)

您拨打open_socket的方式并不像您想象的那样工作。您作为参数传递socket_fd,因此该功能无法更新。你真的应该将新创建的套接字作为返回值返回 - 这样你就可以通过返回-1来处理错误,你的调用代码可以检查并执行相应的操作。

int open_socket( struct sockaddr_in s_addr, struct timeval tv, char* ID_IP, int ID_Port)
{
    int s_fd;
    // Code goes here, returning -1 if it fails at any point
    return s_fd;
}

并像这样称呼它

socket_fd = open_socket(serv_addr, tv, SERVER, PORT);
if(socket_fd==-1)
{
    // Handle failure to create socket
}

答案 1 :(得分:0)

函数open_socket()按值<{1}} 取值。也就是说,当函数被调用时:

s_fd

上面的函数调用获得了作为函数参数open_socket(socket_fd, serv_addr, tv, SERVER, PORT); 的参数传递的socket_fd的副本。在函数内部,此副本是使用s_fd获取的文件描述符而不是函数调用中的变量socket()编写的。

C编程语言为您提供了两种机制来获取在socket_fd内创建的文件描述符:

  • 通过引用传递参数 :调用者必须提供指向将存储文件描述符的变量的指针:

    open_socket()
  • 将文件描述符作为函数调用的返回值返回:

    void open_socket(int *s_fd, /* ... */);
    

我建议您坚持使用后者,因为界面类似于系统调用int open_socket(/* ... */); 提供的界面。发生错误时,您只需返回socket()即可发出错误信号,因为每个文件描述符都是非负数(即:&gt; = 0)。

由于您在-1内部设置了结构open_socket(),因此无需通过sockaddr_in参数传递它。

s_addr

如果在创建套接字后发生错误(即:在成功调用int open_socket(struct timeval tv, const char* ID_IP, int ID_Port) { int s_fd; struct sockaddr_in s_addr; if ((s_fd = socket(AF_INET, SOCK_DGRAM, 0) ) < 0 ) { printf("ERROR opening socket "); goto err; } s_addr.sin_family = AF_INET; /*Define the domain used*/ s_addr.sin_port = htons(ID_Port); /*Declare port #PORT to be used*/ s_addr.sin_addr.s_addr = inet_addr("INADDR_ANY"); /*Permit any incoming IP address by declaring INADDR_ANY*/ if (setsockopt(s_fd, SOL_SOCKET, SO_RCVTIMEO, (const char *)&tv , sizeof (struct timeval))) /*config du timeout*/ goto err_close_socket; // Convert IPv4 and IPv6 addresses from text to binary form if (inet_pton(AF_INET, ID_IP, &s_addr.sin_addr) != 1) { printf("\nInvalid address/ Address not supported \n"); goto err_close_socket; } if (connect(s_fd, (struct sockaddr *)&s_addr, sizeof(s_addr)) < 0) { printf("\nConnection Failed \n"); goto err_close_socket; } printf("Socket Connected\n" ); return s_fd; // return the socket err_close_socket: close(s_fd); err: return -1; // error } 之后),套接字必须是 socket() d 才能从函数返回{ {1}},否则会出现资源泄漏。这是使用close()语句的少数情况之一:跳转到用于错误处理的公共代码。