开发者

Socket Programming C/C++ - recv function hangs in Server

开发者 https://www.devze.com 2023-04-03 09:20 出处:网络
I am having problem in usage of recv function I have an application that send some data from client, these data are received by the server & send a responses based on data.

I am having problem in usage of recv function

I have an application that send some data from client, these data are received by the server & send a responses based on data.

The implementation works fine when I send less than ~16 requests. But when I send more than 16 request (one after the other) from the client, the response are fine from the server until 16th request but after this the server hangs. I could see that the data are transmitted from client but are not received by server. I am using the function recv

The reception is happening in a loop which is exited only when termination request is received from the client.

Server Code:

   // Request Winsock version 2.2
   fprintf(stderr,"Performing WSAStartup\n");
   if ((retval = WSAStartup(0x202, &wsaData)) != 0)
   {
      fprintf(stderr,"FAILED with error %d\n", retval);
      WSACleanup();
      return -1;
   }
   else
   {
      printf("OK\n");
   }

   if (port == 0)
   {
      Usage(argv[0]);
   }


   /* open socket connection */
   printf("Opening socket\n");
   local.sin_family = AF_INET;
   local.sin_addr.s_addr = (!ip_address) ? INADDR_ANY:inet_addr(ip_address);
   /* Port MUST be in Network Byte Order */
   local.sin_port = htons(port);
   // TCP socket
   listen_socket = socket(AF_INET, socket_type,0);

   if (listen_socket == INVALID_SOCKET){
      fprintf(stderr,"socket() failed with error %d\n", WSAGetLastError());
      WSACleanup();
      return -1;
   }
   else
   {   
      printf("OK\n");
   }

   // bind() associates a local address and port combination with the socket just created.
   // This is most useful when the application is a
   // server that has a well-known port that clients know about in advance.
   printf("Bind address and port to socket\n");
   if (bind(listen_socket, (struct sockaddr*)&local, sizeof(local)) == SOCKET_ERROR)
   {
      fprintf(stderr,"bind() failed with error %d\n", WSAGetLastError());
      WSACleanup();
      return -1;
   }
   else
   {  
      printf("OK\n");
   }

   // So far, everything we did was applicable to TCP as well as UDP.
   // However, there are certain steps that do not work when the server is
   // using UDP. We cannot listen() on a UDP socket.
   if (socket_type != SOCK_DGRAM)
   {
      printf("TCP: listening on socket\n");
      if (listen(listen_socket,5) == SOCKET_ERROR)
      {
         fprintf(stderr,"listen() failed with error %d\n", WSAGetLastError());
         WSACleanup();

         return -1;
      }
      else
      {
         printf("OK\n");

      }
   }


//Perform Applcation task
//initisations

   printf("Server is listening and waiting for a connection\non port %d, protocol %s\n",port, (socket_type == SOCK_STREAM)?"TCP":"UDP");

   executeServer = 1;
   while(executeServer == 1)

   {
      fromlen =sizeof(from);
      // accept() doesn't make sense on UDP, since we do not listen()
      if (socket_type != SOCK_DGRAM)
      {
         printf("TCP: Waiting for connection (accept())\n");
         msgsock = accept(listen_socket, (struct sockaddr*)&from, &fromlen);
         if (msgsock == INVALID_SOCKET)
         {
            fprintf(stderr,"accept() error %d\n", WSAGetLastError());
            WSACleanup();
            return -1;
         }
         else
         {   
            printf("OK\n");
            printf("accepted connection from %s, port %d\n", inet_ntoa(from.sin_addr), htons(from.sin_port)) ;
         }
      }
      else
      {   
         msgsock = listen_socket;
      }

      // In the case of SOCK_STREAM, the server can do recv() and send() on
      // the accepted socket and then close it.

      // However, for SOCK_DGRAM (UDP), the server will do recvfrom() and sendto()  in a loop.

      printf("Receiving data");
      if (so开发者_Python百科cket_type != SOCK_DGRAM)
      {   
         retval = recv(msgsock, Buffer, sizeof(Buffer), 0);
      }
      else
      {
         retval = recvfrom(msgsock,Buffer, sizeof(Buffer), 0, (struct sockaddr *)&from, &fromlen);
         printf("Received datagram from %s\n", inet_ntoa(from.sin_addr));

      }


      if (retval == SOCKET_ERROR)
      {
         fprintf(stderr,"recv() failed: error %d\n", WSAGetLastError());
         closesocket(msgsock);
         return -2;
      }
      else
      {
         printf("OK\n");
      }

      if (retval == 0)
      {
         printf("Client closed connection.\n");
         closesocket(msgsock);

      }
      else
      {
         printf("Received %d bytes, data \"%s\" from client\n", retval, Buffer);
      }

      printf("Processing Data\n");
      if (!stricmp(Buffer, "exit"))
      {
         wsprintf(AckBuffer,"ACK");
         executeServer = 0;
      }
      else
      {
        // Perform use task here based on recieved data

      }


      printf("Sending answer to client\n");
      if (socket_type != SOCK_DGRAM)
      {   
         retval = send(msgsock, AckBuffer, sizeof(AckBuffer), 0);
      }
      else
      {   
         retval = sendto(msgsock, AckBuffer, sizeof(AckBuffer), 0, (struct sockaddr *)&from, fromlen);
      }


      if (retval == SOCKET_ERROR)
      {
         fprintf(stderr,"send() failed: error %d\n", WSAGetLastError());
      }
      else
      {   
         printf("OK\n");
      }

      /* close TCP connection */
      if (socket_type != SOCK_DGRAM)
      {
         closesocket(msgsock);
      }


   }
   printf("terminating server\n");
   closesocket(msgsock);
   WSACleanup();

Client Code:

 fprintf(stderr,"Performing WSAStartup");
   if ((retval = WSAStartup(0x202, &wsaData)) != 0)
   {

      fprintf(stderr,"WSAStartup() failed with error %d\n", retval);
      WSACleanup();

      return -1;
   }
   else
   {
      printf("OK\n");
   }

   if (port == 0)

   {
      Usage(argv[0]);
   }

   // Attempt to detect if we should call gethostbyname() or gethostbyaddr()
   printf("Translate hastname to address -> gethostbyaddr()\n");
   if (isalpha(server_name[0]))
   {   // server address is a name
      hp = gethostbyname(server_name);
   }
   else
   { // Convert nnn.nnn address to a usable one
      addr = inet_addr(server_name);
      hp = gethostbyaddr((char *)&addr, 4, AF_INET);
   }
   if (hp == NULL )
   {
      fprintf(stderr,"Cannot resolve address \"%s\": Error %d\n", server_name, WSAGetLastError());
      WSACleanup();
      exit(1);
   }
   else
   {
      printf("OK\n");
   }

   // Copy the resolved information into the sockaddr_in structure
   printf("Opening socket\n");
   memset(&server, 0, sizeof(server));
   memcpy(&(server.sin_addr), hp->h_addr, hp->h_length);
   server.sin_family = hp->h_addrtype;
   server.sin_port = htons(port);

   conn_socket = socket(AF_INET, socket_type, 0); /* Open a socket */
   if (conn_socket <0 )
   {
      fprintf(stderr,"Error Opening socket: Error %d\n", WSAGetLastError());
      WSACleanup();
      return -1;
   }
   else
   {
      printf("OK\n");
   }

   // Notice that nothing in this code is specific to whether we
   // are using UDP or TCP.
   // We achieve this by using a simple trick.
   //    When connect() is called on a datagram socket, it does not
   //    actually establish the connection as a stream (TCP) socket
   //    would. Instead, TCP/IP establishes the remote half of the
   //    (LocalIPAddress, LocalPort, RemoteIP, RemotePort) mapping.
   //    This enables us to use send() and recv() on datagram sockets,
   //    instead of recvfrom() and sendto()
   printf("Client connecting to: %s.\n", hp->h_name);
   if (connect(conn_socket, (struct sockaddr*)&server, sizeof(server)) == SOCKET_ERROR)
   {
      fprintf(stderr,"connect() failed: %d\n", WSAGetLastError());
      WSACleanup();
      return -1;
   }
   else
   {  
      printf("OK\n");
   }

   /* copy options string to buffer */     
   strcpy(Buffer,Options);
   printf("Sending Data \"%s\"\n", Buffer);
   retval = send(conn_socket, Buffer, sizeof(Buffer), 0);
   if (retval == SOCKET_ERROR)
   {
      fprintf(stderr,"send() failed: error %d.\n", WSAGetLastError());
      WSACleanup();
      return -1;
   }
   else
   {
      printf("OK\n");
   }

   printf("Receiving status from server\n");
   retval = recv(conn_socket, Buffer, sizeof(Buffer), 0);
   if (retval == SOCKET_ERROR)
   {
      fprintf(stderr,"recv() failed: error %d.\n", WSAGetLastError());
      closesocket(conn_socket);
      WSACleanup();
      return -1;
   }
   else
   {   
      printf("OK\n");
   }


   // We are not likely to see this with UDP, since there is no
   // 'connection' established.
   if (retval == 0)
   {
      printf("Client: Server closed connection.\n");
      closesocket(conn_socket);
      WSACleanup();
      return -1;
   }

   printf("Received %d bytes, data \"%s\" from server.\n", retval, Buffer);
   closesocket(conn_socket);
   WSACleanup();


If you use recv without making your socket non-blocking mode, your recv is doing a right thing. It blocks until it has something to read.

[UPDATE]

From the code, you are indeed using blocking socket. I recommend you use non-blocking socket at least for your server. I believe you can easily google how to make non-blocking socket and handle async IO in Windows. Good Luck!

[UPDATE2]

First of all, your server code seems to close connection once recv reads something. Since TCP does not care data boundary, you can't just close the connection. Remember one send call in client may require multiple recv calls in server with TCP or vice versa.

For your specific problem, I'm pretty sure there is nothing to read and that's why recv is blocking your program. Make it sure that your client really sends something successfully.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号