Я немного практикуюсь с сокетами и архитектурой клиент-сервер UDP, и, ссылаясь на некоторые примеры, доступные в Интернете, я реализовал очень простой сервер UDP, использующий C, и класс клиента UDP, использующий C ++.
Вкратце, текущая реализация позволяет серверу прослушивать входящие сообщения и передавать обратно тот же пакет клиенту.
Кажется, что он работает нормально, если клиент делает последовательные запросы.
Вот краткий пояснительный пример:
#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
)? Разве многопоточность на сервере только для ответа не решает проблему, упомянутую в любом случае?