Hej,
Na wstępie: C++ znam tylko trochę. Do tej pory bardziej PHP, więc muszę się przestawić - potrzebuję dorobić do biblioteki DLL kod, który pozwoli na wystawienie portu zewnętrznego (w sieci lokalnej) i komunikację po tym porcie.
Biblioteka wspomniana to plugin do X-Plane 11, jeśli kogoś interesuje.
Wyglądałoby to tak, że X-Plane ładuje bibliotekę, która wystawia na zewnątrz jakąś funkcjonalność, a ja ją później obrabiam w innym miejscu.
Czy to w ogóle możliwe? Jeśli tak, to czy możecie mi zaproponować jakieś tutoriale? Korzystam z Visual Studio 2017 Community i wolałbym nie zmieniać środowiska, bo musiałbym wszystko przekonfigurować i znowu dostosowywać...
Komunikacja sieciowa z biblioteki DLL
- Rejestracja: dni
- Ostatnio: dni
- Postów: 7
- Rejestracja: dni
- Ostatnio: dni
- Postów: 741
Ale ty bardziej potrzebujesz chyba klienta tcp, żeby po wczytaniu ddl i pozyskaniu danych wysłał je do tej zew apki.
Jak duże paczki danych to będą? Czy oczekujesz jakiegoś wyniku zwrotnego który będzie wpływał na tą gre?
- Rejestracja: dni
- Ostatnio: dni
- Lokalizacja: Silesia/Marki
- Postów: 5550
Hm, próbuję zrozumieć co chcesz zrobić, podzielmy to na punkty
- Bierzesz cudzą bibliotekę która jest pluginem do X-Plane 11
- Dodajesz do biblioteki swój kod zamieniający ją w serwer TCP (nie wiem czy to poprawne okreslenie), ale tak żeby dalej była pluginem do X-Plane 11
- Komunikujesz się swoim programem z tym serwerem po TCP
Czy dobrze Cię rozumiem?
- Rejestracja: dni
- Ostatnio: dni
- Postów: 7
To ma być plugin do X-Plane, a nie nakładka na inny plugin. Odczytywanie danych w teorii mam, ale nie mam jak tego podpiąć, bo rozwiązania, które teraz zastosowałem, blokują wykonanie aplikacji dopóki nie otrzyma ona pakietów z aplikacji testowej.
Paczki będą małe (około 1-2 KB). Nie chcę robić tego tak, że apka na androida, która docelowo ma odczytywać te dane, miałaby być serwerem - to nie przejdzie. Jedyny wpływ na grę ma być akceptowalnym opóźnieniem pobrania danych i wysłania paczki - nic innego ten plugin nie będzie robił.
Na chwilę obecną próbuję skleić coś z winsock2, ale brak umiejętności podpięcia pod to wielowątkowości mnie blokuje.
- Rejestracja: dni
- Ostatnio: dni
- Rejestracja: dni
- Ostatnio: dni
- Postów: 7
Kolega wyżej wrzucił link do TCPListenera, ale z C#. Poszukałem na necie czegoś podobnego i znalazłem coś: https://www.sfml-dev.org/documentation/2.5.1/classsf_1_1TcpListener.php ale to nie rozwiązuje chyba problemu z tym, że połączenie będzie blokowało wykonanie instrukcji w bibliotece...
- Rejestracja: dni
- Ostatnio: dni
- Postów: 741
Albo tylko na początku nawiązujesz połączenie i je podtrzymujesz przez całe życie apki wysyłając przez nie dane. Albo przy każdym wysyłaniu bierzesz i odpalasz wątek w którym to już sobie nawiązuje połączenie i wysyła te dane nie blokując apki.
- Rejestracja: dni
- Ostatnio: dni
- Postów: 7
http://www.cplusplus.com/reference/thread/thread/detach/
Zrobiłem jak w powyższym przykładzie - walnąłem zammiast 'join' - 'detach' i zadziałało :D
Tylko pytanie: czy przy wychodzeniu z pluginu powinienem jakoś zwalniać zasoby z winsock2?
- Rejestracja: dni
- Ostatnio: dni
- Postów: 741
- Rejestracja: dni
- Ostatnio: dni
- Postów: 7
Oto kod wątku, który obsługuje wystawienie danych:
void InstrumentDataThread() {
useSocket = true;
WSADATA wsaData;
SOCKET mainSocket;
sockaddr_in service;
int result = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (result != NO_ERROR) {
useSocket = false;
}
else {
mainSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (mainSocket == INVALID_SOCKET)
{
useSocket = false;
WSACleanup();
}
else {
memset(&service, 0, sizeof(service));
service.sin_family = AF_INET;
service.sin_addr.s_addr = inet_addr("127.0.0.1");
service.sin_port = htons(30123);
if (bind(mainSocket, (SOCKADDR *)& service, sizeof(service)) == SOCKET_ERROR)
{
useSocket = false;
closesocket(mainSocket);
}
else {
if (listen(mainSocket, 1) == SOCKET_ERROR) {
useSocket = false;
}
else {
SOCKET acceptSocket = SOCKET_ERROR;
acceptSocket = accept(mainSocket, NULL, NULL);
if (acceptSocket != SOCKET_ERROR) {
mainSocket = acceptSocket;
char Buffer[256];
while (useSocket) {
sprintf(Buffer, "%f", psi);
int bytesSent;
int bytesRecv = SOCKET_ERROR;
char recvbuf[2] = "";
bytesSent = send(mainSocket, Buffer, strlen(Buffer), 0);
while (bytesRecv == SOCKET_ERROR)
{
bytesRecv = recv(mainSocket, recvbuf, 1, 0);
if (bytesRecv == 0 || bytesRecv == WSAECONNRESET)
{
useSocket = false;
break;
}
if (bytesRecv < 0) {
useSocket = false;
break;
}
}
}
closesocket(mainSocket);
}
}
}
}
}
WSACleanup();
InstrumentDataThread();
}
Na chwilę obecną nie podtrzymuje połączenia.
Na końcu jest powtórne wywołanie funkcji, ale problem jest taki, że po połączeniu klienta i zakończeniu połączenia, aplikacja się wywala :/
Jak mogę zrestartować wątek tak, aby mógł się do niego podłączyć inny klient?
W funkcji głównej modułu uruchamiam pierwszy wątek tak:
std::thread t(InstrumentDataThread);
t.detach();