Wes Poon
Wes Poon

Reputation: 33

Implementing Multi-threading concurrent server by C++ (UDP case)

I used "Create-new-thread method" to deal with new clients and met problem in UDP. First I used main thread to create one TCP thread to deal with new accept() and create one UDP thread to deal with new recvfrom(). (TCP cases are OK) Once the first recvfrom() callback, i try to pass the client to the new UDP thread and keep the current one to deal with next new UDP client It should be work by passing the address and new-created datagram socket to the new thread to continue do recvfrom(), right ?

During experiment, I found that the OLD UDP thread keeps receiving datagram from the client while the new thread just doing while loop and recvfrom() turns to non-blocking manner and returns -1 as a result.

Therefore what is the problem of my code....thanks~ Do I understand something wrongly..?

PassToUDPThread is the typeof struct i made for data passing to new thread:

typedef struct {
   sockaddr_in ReceiverSocket;
   SOCKET sendSocket;
   char* recvbuf;
   long packet_size;

}PassToUDPThread;

Here is my code for the FIRST UDP thread function (dealing with first recvfrom() ONLY) :

sockaddr_in *ReceiverSocket = new sockaddr_in;

ReceiverSocket->sin_family = AF_INET;
if (strcmp(recv_hostname, "INADDR_ANY") != 0)
inet_pton(AF_INET, ip_addr_char, &ReceiverSocket->sin_addr.s_addr);
else ReceiverSocket->sin_addr.s_addr = INADDR_ANY;
ReceiverSocket->sin_port = htons((u_short)recv_port);

//*** Create the socket
SOCKET s;

s = socket(AF_INET, SOCK_DGRAM, 0);
printf("Receiver: Socket Created - UDP connection\n");
bind(s, (struct sockaddr *)ReceiverSocket, sizeof(struct sockaddr_in));

do
{
   int fromlen = (int)sizeof(struct sockaddr_in);
   retVal = recvfrom(s, recvbuf, packet_size, 0, (struct sockaddr*)ReceiverSocket, &fromlen);
   std::cout << "UDP recv by MAIN "<<std::endl;
   if (retVal == SOCKET_ERROR) {
      std::cout << "UDP Socket error : " + WSAGetLastError()<<std::endl;
      return 0;
   }
   else {
       SOCKET sendSocket = socket(AF_INET, SOCK_DGRAM, 0);
       PassToUDPThread _p;
       PassToUDPThread *p = &_p;
       p->sendSocket = sendSocket;
       p->ReceiverSocket = *ReceiverSocket;
       p->recvbuf = recvbuf;
       p->packet_size = packet_size;

       thrd_t UDPthread;
       if (thrd_create(&UDPthread, ThreadUDPReceiver, (void*)p) == thrd_success) {
           std::cout<<"success create new UDP thread"<<std::endl;
                            }




   }
   } while (retVal>0);
     closesocket(s);
     UDPReceiver(arg);
     return 1;
}

Here is the code for the function on NEW-CREATED UDP thread:

 int ThreadUDPReceiver(void *arg) {

    int retVal;
    SOCKET s = ((PassToUDPThread*)arg)->sendSocket;
    char* recvbuf = ((PassToUDPThread*)arg)->recvbuf;
    long packet_size = ((PassToUDPThread*)arg)->packet_size;
    sockaddr_in *ReceiverSocket = new sockaddr_in;
    memcpy(ReceiverSocket, &(((PassToUDPThread*)arg)->ReceiverSocket), sizeof sockaddr_in);

    bind(s, (struct sockaddr *)ReceiverSocket, sizeof(struct sockaddr_in));

    do {
       int fromlen = (int)sizeof(struct sockaddr_in);
       retVal = recvfrom(s, recvbuf, packet_size, 0, (struct sockaddr *)ReceiverSocket, &fromlen);
       std::cout << "UDP recv by thread "<< std::endl;
    } while (true);

    return 0;

    }

Upvotes: 0

Views: 2205

Answers (1)

user207421
user207421

Reputation: 310980

  1. Use a thread pool.
  2. Get rid of the extra UDP sockets. Use the same one to send the response that the request arrived on. Simpler for the client that way too.

Upvotes: 0

Related Questions