c语言 - 一次成功后套接字"Bad file desc." write()/read()



这是一个带有select()'的服务器实现,以及一个简单的客户端。它不是主应用程序,而是一个示例,可能无法运行。重要的是来自服务器的无限循环。

问题出现在这里:客户端发送(正确的)消息,

从服务器接收(正确的)答案,然后,当他发送另一条消息时,它收到错误:写入():错误的文件描述符。

我重新检查了服务器,他没有关闭它。我怀疑问题出在选择()或服务器架构中。

编辑:如果相关,我在 127.0.0.1 上测试我的应用程序。

服务器

        #include <sys/types.h>
        #include <sys/socket.h>
        #include <sys/time.h>
        #include <netinet/in.h>
        #include <unistd.h>
        #include <errno.h>
        #include <stdio.h>
        #include <arpa/inet.h>
        #include <string.h>
        #define PORT 2728
        extern int errno;       
        /* converting client address int char*  */
        char * conv_addr (struct sockaddr_in address)
        {
          static char str[25];
          char port[7];
          strcpy (str, inet_ntoa (address.sin_addr));   
          bzero (port, 7);
          sprintf (port, ":%d", ntohs (address.sin_port));  
          strcat (str, port);
          return (str);
        }

        int main ()
        {
          struct sockaddr_in server;    
          struct sockaddr_in from;
          fd_set readfds;   //clients which are ready to write  
          fd_set actfds;    //active clients    
          struct timeval tv;        
          int sd, client;       
          int optval=1;             
          int fd;           
          int nfds;      //max number of descriptors        
          int len;          

          if ((sd = socket (AF_INET, SOCK_STREAM, 0)) == -1)
            {
              perror ("[server] Error:socket().n");
              return errno;
            }
          /*SO_REUSEADDR  option*/ 
          setsockopt(sd, SOL_SOCKET, SO_REUSEADDR,&optval,sizeof(optval));

          bzero (&server, sizeof (server));

          server.sin_family = AF_INET;
          server.sin_addr.s_addr = htonl (INADDR_ANY);
          server.sin_port = htons (PORT);

          if (bind (sd, (struct sockaddr *) &server, sizeof (struct sockaddr)) == -1)
            {
              perror ("[server] Error:bind().n");
              return errno;
            }

          if (listen (sd, 5) == -1)
            {
              perror ("[server] Error:listen().n");
              return errno;
            }

          FD_ZERO (&actfds);        
          FD_SET (sd, &actfds);     
          tv.tv_sec = 1;        
          tv.tv_usec = 0;

          nfds = sd;
          printf ("[server] Waiting at port %d...n", PORT);
          fflush (stdout);
          /* serving clients... */
          while (1)
            {
              bcopy ((char *) &actfds, (char *) &readfds, sizeof (readfds));

              if (select (nfds+1, &readfds, NULL, NULL, &tv) < 0)
            {
              perror ("[server] Error:select().n");
              return errno;
            }

              if (FD_ISSET (sd, &readfds))
            {
              /* preparing client structure */
              len = sizeof (from);
              bzero (&from, sizeof (from));

              client = accept (sd, (struct sockaddr *) &from, &len);

              if (client < 0)
                {
                  perror ("[server] Error:accept()n");
                  continue;
                }
                  if (nfds < client) /* adjusting max value */
                    nfds = client;

              FD_SET (client, &actfds);
              printf("[server] Client with %d descriptor and %s address connected.n",client, conv_addr (from));
              fflush (stdout);
            }
              /* checking if any client is ready so 'speak' */
              for (fd = 0; fd <= nfds; fd++)    
            {
              if (fd != sd && FD_ISSET (fd, &readfds))
                {   
                       //receive message from client
                       //do something 
                       //sent back result
                }
            }
                            /* for */
            }               /* while */
        }               /* main */

客户

    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <errno.h>
    #include <unistd.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <netdb.h>
    #include <string.h>
    extern int errno;

    int port;
    int main (int argc, char *argv[])
    {
      int sd;           
      struct sockaddr_in server; 
      char msg[100];    
      if (argc != 3)
        {
          printf ("[client] Sintax: %s <server_address> <port>n", argv[0]);
          return -1;
        }
      port = atoi (argv[2]);
      if ((sd = socket (AF_INET, SOCK_STREAM, 0)) == -1)
        {
          perror ("[client] Error:socket().n");
          return errno;
        }

      server.sin_family = AF_INET;
      server.sin_addr.s_addr = inet_addr(argv[1]);
      server.sin_port = htons (port);

      if (connect (sd, (struct sockaddr *) &server,sizeof (struct sockaddr)) == -1)
        {
          perror ("[client]Error: connect().n");
          return errno;
        }

    while(1)/*meaning untill user doesn't close the client*/)
     {
        //here are the functions used to communicate with server. Same in server.
      if (write (sd, msg, 100) <= 0)
        {
          perror ("[client]Error:write().n");
          return errno;
        }

      if (read (sd, msg, 100) < 0)
        {
          perror ("[client]Error:read().n");
          return errno;
        }
     }//while
      close (sd);
  }//main

while(/*user doesn't close client*/)
 {
    //here are the functions used to communicate with server. Same in server.
  if (write (sd, msg, 100) <= 0)
    {
      perror ("[client]Error:write().n");
      return errno;
    }
  if (read (sd, msg, 100) < 0)
    {
      perror ("[client]Error:read().n");
      return errno;
    }
 }
  close (

如果这个循环在第二次写入时失败,EBADF ,显然这不是真正的代码,显然收盘价在循环内高出一行,正如其缩进所暗示的那样。

服务器和客户端的代码似乎都缺少设置"SO_KEEPALIVE"选项。建议使用类似以下内容:

int keepAlive = 1;

if( 0 > setsockopt(sd, SOL_SOCKET, SO_KEEPALIVE,
               &keepAlive, (socklen_t)sizeof(keepAlive)) )
{ // then, setsockopt failed
    // process error
}

当前代码通过以下方式创建套接字:

if ((sd = socket (AF_INET, SOCK_STREAM, 0)) == -1)
{ // then socket failed
    // process error
}

建议使用:

if ((sd = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1)
{ // then socket failed
    // process error
}

相关内容

最新更新