C++实现多线程并发服务器(UDP案例)
Implementing Multi-threading concurrent server by C++ (UDP case)
我使用 "Create-new-thread method" 来处理新客户端并在 UDP 中遇到问题。
首先我使用主线程创建一个 TCP 线程来处理新的 accept()
并创建一个 UDP 线程来处理新的 recvfrom()。 (TCP 案例没问题)
一旦第一个 recvfrom() 回调,我尝试将客户端传递给新的 UDP 线程并保留当前线程以处理下一个新的 UDP 客户端
它应该通过将地址和新创建的数据报套接字传递给新线程继续执行 recvfrom() 来工作,对吗?
在实验过程中,我发现旧的UDP线程一直在接收来自客户端的数据报,而新线程只是在做while循环和recvfrom()转为非阻塞方式,结果returns -1 .
所以我的代码有什么问题....谢谢~
我是不是理解错了..?
PassToUDPThread 是我为将数据传递到新线程而创建的结构类型:
typedef struct {
sockaddr_in ReceiverSocket;
SOCKET sendSocket;
char* recvbuf;
long packet_size;
}PassToUDPThread;
这是我的第一个 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;
}
这是新创建的 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;
}
- 使用线程池。
- 摆脱额外的 UDP 套接字。使用同一个发送请求到达的响应。这样对客户来说也更简单。
我使用 "Create-new-thread method" 来处理新客户端并在 UDP 中遇到问题。 首先我使用主线程创建一个 TCP 线程来处理新的 accept() 并创建一个 UDP 线程来处理新的 recvfrom()。 (TCP 案例没问题) 一旦第一个 recvfrom() 回调,我尝试将客户端传递给新的 UDP 线程并保留当前线程以处理下一个新的 UDP 客户端 它应该通过将地址和新创建的数据报套接字传递给新线程继续执行 recvfrom() 来工作,对吗?
在实验过程中,我发现旧的UDP线程一直在接收来自客户端的数据报,而新线程只是在做while循环和recvfrom()转为非阻塞方式,结果returns -1 .
所以我的代码有什么问题....谢谢~ 我是不是理解错了..?
PassToUDPThread 是我为将数据传递到新线程而创建的结构类型:
typedef struct {
sockaddr_in ReceiverSocket;
SOCKET sendSocket;
char* recvbuf;
long packet_size;
}PassToUDPThread;
这是我的第一个 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;
}
这是新创建的 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;
}
- 使用线程池。
- 摆脱额外的 UDP 套接字。使用同一个发送请求到达的响应。这样对客户来说也更简单。