我正在使用套接字和UDP客户端-服务器体系结构进行一些练习,并参考网络上的一些示例,我已经使用C实现了一个非常简单的UDP服务器,并使用C ++实现了一个UDP客户端类。
简而言之,当前的实现使服务器可以侦听传入的消息并将相同的数据包发送回客户端。
如果客户端发出顺序请求,这似乎很好。
这是一个简短的说明性示例:
#include "UDPClient.h"
int main(int argc, char* argv[]) {
UDPClient testClient;
testClient.initSockets(1501, "127.0.0.1", 1500);
for (int i = 0; i < 10; i++) {
testClient.notifyEntry();
testClient.notifyExit();
}
return 0;
}
由于客户端实际上应该同时与服务器共享更多信息,因此我测试了启动新线程的相同代码块:
#include <thread>
#include "UDPClient.h"
int main(int argc, char* argv[]) {
UDPClient testClient;
std::thread thrdOne, thrdTwo;
testClient.initSockets(1501, "127.0.0.1", 1500);
for (int i = 0; i < 10; i++) {
thrdOne = std::thread(UDPClient::notifyEntry, std::ref(testClient));
thrdTwo = std::thread(UDPClient::notifyExit, std::ref(testClient));
}
return 0;
}
如您所见,notifyEntry
和notifyExit
已制成static
,目前需要引用一个类实例才能正常工作。
此外,在它们的功能体内,我还添加了一个小代码块,以检查由于服务器发送回相同的内容,因此发送的消息是否等于接收到的消息。
这是一个说明性示例:
void UDPClient::notifyEntry(UDPClient& inst) {
char buffer = "E"
inst.sendPacket(buffer); // sendto...
inst.receivePacket(buffer); // recvfrom...
if (!(buffer == 'E') ){
std::string e = "Buffer should be E but it is ";
e.append(buffer);
throw UDPClientException(e);
}
}
使用多线程通常会发生上述检查引发异常的情况,因为缓冲区实际上包含另一个char
(由notifyExit
发送的缓冲区)。
考虑到这些信息,我想问你:
recvfrom
还能捕获来自另一个请求的响应,因为该套接字仅实例化了一个绑定的套接字?notifyEntry
的消息和一个用于notifyExit
的消息)?服务器上的多线程响应仅不能解决上述问题吗?答案 0 :(得分:1)
之所以发生这种情况,是因为线程的recvfrom也可以捕获 来自另一个请求的响应,被套接字实例化 只有一个绑定的套接字?
这很有可能-如果您有多个线程在同一个UDP套接字上调用recvfrom()
,那么哪个线程将接收哪个传入的UDP数据包将是不确定的/不可预测的。
如果是,我应该实例化多个套接字(例如, 每个仅可用于一种类型的消息,即 notifyEntry和一个notifyNotit)?
是的,我建议让每个线程创建自己的专用UDP套接字,并将其套接字绑定到自己的单独端口(例如,将端口号0传递给bind()
);这样,每个线程都可以确保只接收自己的响应,而不会被原本用于其他线程的响应所混淆。 (请注意,您还希望对服务器进行编码,以将其回复发送回recvfrom()
呼叫所报告的IP地址和端口,而不是将回复数据包发送回硬编码的端口号)< / p>
服务器上的多线程响应仅不能解决问题 反正提到了吗?
否,对UDP数据包的正确处理(或不正确)是一个独立的问题,与服务器是单线程还是多线程无关。