通过C ++实现多线程并发服务器(UDP案例)

时间:2015-11-04 07:13:05

标签: c++ multithreading sockets udp serversocket

我使用"创建新线程方法"处理新客户端并遇到UDP问题。 首先,我使用主线程创建一个TCP线程来处理新的accept() 并创建一个UDP线程来处理新的recvfrom()。 (TCP案例还可以) 一旦第一次recvfrom()回调,我尝试将客户端传递给新的UDP线程,并保持当前的一个处理下一个新的UDP客户端 应该通过将地址和新创建的数据报套接字传递给新线程来继续执行recvfrom(),对吗?

在实验过程中,我发现OLD UDP线程一直在从客户端接收数据报,而新线程正在执行while循环,recvfrom()转为非阻塞方式,结果返回-1。

因此我的代码有什么问题....谢谢〜 我是否理解错误??

PassToUDPThread是我为传递给新线程的数据所做的结构类型:

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

}PassToUDPThread;

这是我的FIRST UDP线程函数的代码(仅处理第一个recvfrom()):

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;
}

以下是NEW-CREATED UDP线程上的函数代码:

 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;

    }

1 个答案:

答案 0 :(得分:0)

  1. 使用线程池。
  2. 摆脱额外的UDP套接字。使用相同的一个发送请求到达的响应。对客户来说也更简单。