standard Unix/Windows

0

Natknąłem się na taki problem ostatnio. Mianowicie chciałbym zbudować taką sobie aplikację sieciową i potrzebuję wykorzystać do tego celu bibliotekę <winsock.h>, jednakże ona nie załatwia mi wszystkiego ponieważ brakuje w niej różnych definicji np. definicji np. ifr_addr.
Mam kompilator MinGW i wygląda na to że to nie zapewnia mi dostępności wszystkich bibliotek.

Próbowałem na żądanie wkopiowywać te biblioteki (zaciągam z neta i wklejam do odpowiedniego katalogu) ale jest to karkołomne gdyż zazwyczaj zaciągnięta i wgrana biblioteka korzysta z innej lub nawet wielu innych i drzewko się rozbudowuje...

Wiem że jest coś takiego jak standard Posix i że jest coś takiego jak kompilator CygWin który ten standard zapewnia i tam są wszystkie te biblioteki obecne. Ale czy to znaczy że nie da się tego zrobić z użyciem MinGW ?

Mimo to zrobiłem tak:
Zainstalowałem tego CygWin, uruchomiłem Eclipse i utworzyłem nowy projekt ale wybrałem kompilator CygWin zamiast MinGW.
Sprawdziłem w folderze c:\cygwin64\usr\include obecność bibliotek - oczywiście się tam znajdują, pomimo tego wywala błąd że nie ma takiej biblioteki.
Tak jakby szukał nie tam gdzie potrzeba. Nie wiem gdzie tkwi błąd na skutek czego nie wiem jak go naprawić.
Pomocy.

1

ehh pewne pomieszanie z poplątaniem, nie wiesz co jest czym:
cygwin
POSIX
Chcesz używać winapi a aby to zrobić używasz narzędzi unixowych? To się nie dodaje za bardzo.

Twoim rozwiązaniem jest:
a)kompilator microsoftu(czyli producenta windows)
b) przejście na coś więcej niż winapi np. framework qt.

0

No tak...
Ale przecież po to instalowałem tego CygWin'a żeby móc pod Windowsem używać funkcjonalności standardu POSIX/UNIX, to przecież z tego co mi wiadomo jedno z zastosowań pakietu CygWin... czyż nie?
I wszystko byłoby dobrze gdyby w nowym projekcie utworzonym w eclipse na bazie kompilatora cygwin dało się zaciągnąć biblioteki które nota bene są obecne w odpowiednich folderach tego całego cygwina. W projekcie jednak odwołując się do tych bibliotek wyskakuje błąd że "no such file or directory" w kontekście danego pliku nagłówkowego.
Pomóżcie mi znaleźć przyczynę...

0

Wygląda mi na to że zaczynasz dopiero swoją przygodę z programowaniem.
Po pierwsze, wybór środowiska i narzędzi. Nie mam pojęcia co chcesz napisać ale wybierasz środowisko:

  • Windows -> najlepiej użyć visual studio c++(jest wersja darmowa) [LINK](https://msdn.microsoft.com/pl-pl/library/jj620919.aspx
  • Linux -> gcc/clang(najlpeiej zacznij od gcc) i to w sumie tyle(ide to sprawa drugorzędna)
    Następnie odpowiednio dobierasz biblioteki do zadania i je wrzucasz. Ogólnie polecam poczytać o Cmake jako systemie budowania.

Generalnie powyższe pkt. rozwiążą twoje problemy. Daruj sobie cygwin na windows bo pisanie od zera jakiś swoich programików i używanie do tego cygwin na windows to delikatnie mówiąc pomyłka.

0

Pracuję w systemie win7.
Używam Eclipse i mam zainstalowane MinGW64bit i zbudowałem już nie jedną aplikację konsolową.
Aktualnie pracuję nad czymś takim jak konsolowe gadu gadu. To co wpisze po jednej stronie ma wyskakiwać po drugiej i odwrotnie.
Model ten chciałbym realizować po tcpip a do tego wszystkiego potrzebuję pewnych bibliotek np. ifaddrs.h które niestety ten mingw mi nie daje.
Wiem jednak że różne rzeczy np. gniazdka (socket) są dostępne w standardowym winapi dlatego też podciągnąłem bibliotekę winsock2.h.
Nie rozwiązuje to jednak mojego problemu bo w tej bibliotece nie ma np. zdefiniowanej struktury ifr_addr którą bym potrzebował do napisania mojej aplikacji.

0

To tak względem odniesienia się do komentarza kolegi i poprzednich wypowiedzi.

Wydaje mi się, że najsensowniejsze(ale jednocześnie bardziej wymagające) będzie zrobienie serwera pod daną platformę oraz klienta/klienty pod (inne?) poszczególne platformy, które chcesz obsługiwać.
Wtedy musisz jedynie wystawić API serwera dla klientów i jest załatwione, możesz pisać "elementy" aplikacji używając narzędzi, które są łatwo dostępne pod daną platformą.
Co prawda Cpp jest przenośny, ale jednocześnie zahacza na tyle nisko, że często korzysta z rozwiązań specyficznych dla danego systemu i potem jest kopa, jak czegoś potrzebujesz, czego akurat nie ma, a nie możesz znaleźć alternatywy.

Może opisz dokładniej jakie są wymagania względem aplikacji, to uda się wymyślić bardziej logiczne i globalne rozwiązanie problemu, które pociągniesz dalej sam? Bo na razie to wygląda na szukanie na siłę znanych sobie rozwiązań poza natywną platformą i stąd rodzą się problemy?

Przy czym... Mogę gadać kompletne głupoty, bo C++ znam na poziomie najwyżej zajęć uczelnianych, nigdy w nim głębiej nie grzebałem, to też trudno coś sensownego wymyślić w tym konkretnym przypadku. Ale są bardziej kompetentni technologicznie koledzy, więc na pewno cosik się ogarnie :)

3

Masz kilka opcji:

  • Win32 API na Windows, POSIX na Linux
  • POSIX na Windows przez Cygwin, POSIX na Linux
  • Windows Subsystem for Linux na Windows, POSIX na Linux

MinGW nie dostarcza żadnego standardowego API, jest po prostu portem GCC i przyległości.
Jak ustawić projekt dla WSL pod VS: https://blogs.msdn.microsoft.com/vcblog/2017/02/08/targeting-windows-subsystem-for-linux-from-visual-studio/

0

Wybieram POSIX na Windows przez Cygwin.
Mam prośbę do wszystkich. Proszę od tego momentu traktować moje pytania z wyłączeniem tego co pisałem powyżej pomimo tego że będą ciągle odnosić się do tego samego problemu.

Problemem jest aktualnie:
zainstalowałem cygwina z interesującymi pakietami bibliotecznymi, mam utworzony nowy projekt który kompiluje się z użyciem narzędzi cygwina
jestem również pewien że biblioteka <ifaddrs.h> znajduje się w folderze cygwin64\usr\include a pomimo tego kompilator twierdzi że jej tam nie ma.
Wiem że mam coś najprawdopodobniej pochrzanione z ustawieniami bo to przecież niemożliwe aby tego nie widział, pomożecie?

0

Wybieram POSIX na Windows przez Cygwin i wiem że to niezgodne ze sztuką (no bo przecież po co stosować w aplikacji na windowsa interfejs POSIXowy jeśli można winapi) jak mówili przedmówcy ale potraktujcie moje zapytanie czysto teoretycznie i bardzo proszę nie dawajcie już takich komentarzy że jestem du... itd.

Mam prośbę do wszystkich. Proszę od tego momentu traktować moje pytania z wyłączeniem tego co pisałem powyżej pomimo tego że będą ciągle odnosić się do tego samego problemu.

Problemem jest aktualnie:
zainstalowałem cygwina z interesującymi pakietami bibliotecznymi, mam utworzony nowy projekt który kompiluje się z użyciem narzędzi cygwina
jestem również pewien że biblioteka <ifaddrs.h> znajduje się w folderze cygwin64\usr\include a pomimo tego kompilator twierdzi że jej tam nie ma.
Wiem że mam coś najprawdopodobniej pochrzanione z ustawieniami bo to przecież niemożliwe aby tego nie widział, pomożecie?

0

Ustaliłem następującą rzecz.
Kompilator cygwin znajdujący się w:
c:\cygwin64\bin\x86_64-w64-mingw32-gcc.exe
szuka wszystkich bibliotek jedynie w folderze:
C:\cygwin64\usr\x86_64-w64-mingw32\sys-root\mingw\include
podczas gdy interesujące mnie bibiloteki są nie tylko tutaj (bo tutaj też są niektóre np.stdio.h, conio.h) ale także i tutaj:
c:\cygwin64\usr\include
Jak tego dziada zmusić do tego żeby szukał także i w innych swoich folderach ???

W zasadzie to ustaliłem jeszcze że np.stdio.h i conio.h są nie tylko tu:
C:\cygwin64\usr\x86_64-w64-mingw32\sys-root\mingw\include
ale i tutaj:
c:\cygwin64\usr\include
tak więc rozwiązaniem byłoby zmuszenie tego cygwina do tego aby szukał ich tylko tutaj:
c:\cygwin64\usr\include
Załatwiłoby to kompletnie sprawę. Ponawiam pytanie: jak zmusić go do tego???

0

winsock to implementacja microsoftowa socketów, które są koncepcją z uniksa. Żeby skompilować cokolwiek pod mingw/cygwinem raczej szukaj materiałów pod Linuksa. Na przykład tu masz prosty serwer http: https://github.com/ankushagarwal/nweb . Taki kod powinien się skompilować w tym środowisku.
http://www.linuxhowtos.org/C_C++/socket.htm - tu masz dokładniejszy opis socketów. To jest standard POSIX, ale myślę, że słowo kluczowe „Linux” da lepsze rezultaty w wyszukiwarce.

0

Panowie napisałem coś takiego:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <ifaddrs.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <pthread.h>
#include <termios.h>

/* deklaracja statycznych struktur potrzebnych do obslugi terminala (funkcja _getch) */
static struct termios old, new;

/* funkcja inicjalizujaca ustawienia terminala i/o */
void initTermios(int echo)
{
    /* przechwycenie starych ustawien terminala i/o */
    tcgetattr(0, &old);

    /* ustawienie nowych ustawien takich jak stare */
    new = old;

    /* wylaczenie buforowania i/o */
    new.c_lflag &= ~ICANON;

    /* ustawienie trybu echa */
    new.c_lflag &= echo ? ECHO : ~ECHO;

    /* uzycie nowych ustawien terminala i/o */
    tcsetattr(0, TCSANOW, &new);
}

/* funkcja przywracajaca poprzednie ustawienia terminala i/o */
void resetTermios(void)
{
  tcsetattr(0, TCSANOW, &old);
}

/* funkcja odczytujaca jeden znak - echo parametr (0-brak, 1-obecne echo) */
char getch_(int echo)
{
  char ch;
  initTermios(echo);
  ch = getchar();
  resetTermios();
  return ch;
}

/* funkcja odczytujaca pojedynczy znak (bez echa) */
char getch(void)
{
  return getch_(0);
}

/* funkcja odczytujaca pojedynczy znak (z echem) */
char getche(void)
{
  return getch_(1);
}

void * client_loop(void * arg)
{
    /* deklaracje zmiennych lokalnych */
    int sck = *((int *) arg);
    char buffer[1024];
    int rcvd, i;

    /* wieczna petla w watku */
    while (1)
    {
        /* odbior w locie danych */
        rcvd = recv(sck, buffer, 1024, 0);

        /* jesli odebrano przynajmniej jeden bajt */
        if (rcvd > 0)
        {
            /* wyswietlenie waznych danych z bufora */
            for (i = 0; i < rcvd; i++)
            {
                printf("%c", buffer[i]);
            }
        }
    }

    /* zakonczenie watku */
    pthread_exit(NULL);
}

/* glowna funkcja programu */
int main(int argc, char * argv[])
{
    /* deklaracje potrzebnych zmiennych uzywanych w programie serwera */
    int port, nFoo = 1, nBind, nListen, nClientSocket;
    struct sockaddr_in stAddr, stClientAddr;
    socklen_t nTmp;

    /* wypisanie komunikatow startowych */
    printf("Witaj w programie serwera!\n\n");
    printf("Wpisz port na ktorym serwer bedzie nasluchiwal polaczenia\nPort : ");

    /* odczyt numeru portu */
    scanf("%d", &port);

    /* zerowanie struktury adresowej */
    memset(&stAddr, 0, sizeof(struct sockaddr_in));

    /* wybor sieci : internetwork tcp lub udp */
    stAddr.sin_family = AF_INET;

    /* konwersja z reprezentacji lokalnej do sieciowej dla liczb 32 bitowych */
    /* i przypisanie do pola struktury adresowej */
    stAddr.sin_addr.s_addr = htonl(INADDR_ANY);

    /* konwersja z reprezentacji lokalnej do sieciowej dla liczb 16 bitowych */
    /* i przypisanie do pola struktury adresowej */
    stAddr.sin_port = htons(port);

    /* utworzenie gniazda */
    int nSocket = socket(AF_INET, SOCK_STREAM, 0);

    /* jesli nie udalo sie poprawnie utworzyc to dajemy komunikat i wychodzimy z programu */
    if (nSocket < 0)
    {
        fprintf(stderr, "%s: Can't create a socket.\n", argv[0]);
        exit(1);
    }

    /* ustawienie opcji gniazda na odpowiednie */
    setsockopt(nSocket, SOL_SOCKET, SO_REUSEADDR, (char *)&nFoo, sizeof(nFoo));

    /* laczenie powolanego do zycia gniazda oraz struktury adresowej - tzw.bindowanie */
    nBind = bind(nSocket, (struct sockaddr *)&stAddr, sizeof(struct sockaddr));

    /* jesli nie udalo sie poprawnie zbindowac to dajemy komunikat i wychodzimy z programu */
    if (nBind < 0)
    {
        fprintf(stderr, "%s: Can't bind a name to a socket.\n", argv[0]);
        exit(1);
    }

    /* rozpoczecie nasluchiwania serwera na wybranym porcie wraz z ustawieniem rozmiaru kolejki */
    nListen = listen(nSocket, 5);

    /* jesli nie udalo sie poprawnie rozpoczac nasluchu to dajemy komunikat i wychodzimy z programu */
    if (nListen < 0)
    {
        fprintf(stderr, "%s: Can't set queue size.\n", argv[0]);
        exit(1);
    }

    /* nieskonczona (wieczna) petla */
    while(1)
    {
        /* pozyskanie rozmiaru struktury */
        nTmp = sizeof(struct sockaddr);

        /* instrukcja blokujaca - program bedzie czekal az przyjdzie jakies żadanie polaczenia */
        nClientSocket = accept(nSocket, (struct sockaddr *)&stClientAddr, &nTmp);

        /* jesli nie udalo sie poprawnie przejsc przez powyzsza procedure to dajemy komunikat i wychodzimy */
        if (nClientSocket < 0)
        {
            fprintf(stderr, "%s: Can't create a connection's socket.\n", argv[0]);
            exit(1);
        }

        /* ta czesc programu bedzie wykonywana jesli żadanie polaczenia zostalo zrealizowane */
        /* wowczas piszemy komunikat skad takie żadanie przyszlo do nas (adres ip) */
        printf("[connection from %s] accepted\n", inet_ntoa((struct in_addr)stClientAddr.sin_addr));

        /* utworzenie dodatkowego watku - do odbierania danych nadawanych przez clienta */
        pthread_t id;
        pthread_create(&id, NULL, client_loop, nClientSocket);

        while(1)
        {
            char temp = getch();
            write(nClientSocket, &temp, 1);
        }

        close(nClientSocket);
    }

    return 0;
}

Operuję na kompilatorze GCC z cygwina a to znaczy że standard posix ma tutaj zastosowanie. Ja rozumiem że to może być niezgodne ze sztuką ale ja się uczę i pomimo to (jak zresztą powiedział @elwis któremu nota bene jestem wdzięczny że bierze mnie w obronę) prosiłbym o odpowiedzi.
Odpalam telnet który robi mi za klienta. Jak skasuję to:

pthread_create(&id, NULL, client_loop, nClientSocket);

to normalnie w telnecie pokazuje mi się to co nadaję z tej aplikacji serwera. Natomiast jak już stworzę ten wątek (niewycięta linia kodu) to wówczas aplikacja się zamyka a telnet mówi o przerwanym połączeniu. Dlaczego tak się dzieje. Przecież w tym wątku dodatkowym nie ma nic co by mogło powodować nieprawidłowe działanie, no chyba że o czymś nie wiem. Pomóżcie please.
Mało tego, jak ta funkcja związana z wątkiem dodatkowym nie ma nic w sobie tylko wieczną pętlę załóżmy to telnet również informuje o tym że zerwano połączenie. Wygląda na to że coś pochrzaniłem z tym wątkiem dodatkowym ale co (przekazuję do niego tylko parametr który jest id socketa utworzonego ale już sam fakt takiego przekazania musi powodować wysypywanie się aplikacji - wątpię....) ???

0

Dobra, nie było pytania. Brakowało ampersanda w przekazywaniu argumentu typu identyfikator socketa. Wszystko działa jak należy. Dzięki.

0

W C++ np. Boost ASIO byłoby 30x lepiej, bez zastanawiania się czy to POSIX, WinSock czy inny zwierz. Opcja druga, jak już musi być POSIX, ale może być C++: ACE Reactor to całkiem przyzwoity kod. Jak ma być czyste C, to nadal możesz użyć reaktora, Google: Adam Tornhill C reactor pattern. Ale na Boga, nie używaj gołych wątków.

0

Czemu nie powinno się używać "gołych wątków" ?

0

Może źle to sformułowałem: w tym przypadku gołe wątki to walenie do muchy z naprawdę sporego kalibru armaty, jednowątkowy reactor spokojnie sobie da radę. Jak już koniecznie chcesz jakoś to osobno obsługiwać to wieloprocesowość może być prostsza z uwagi na lepsze (imho) mechanizmy komunikacji, ale to nadal rusznica przeciwczołgowa (zamiast artylerii) na tego samego, niezbyt grubego zwierza.
W innych przypadkach nadal warto rozważyć np. Boost ASIO, bo zapewnia abstrakcję nad systemowymi wywołaniami do obsługi TCP/IP czy timerów (jest przenośne), poza tym pozwala uwolnić się od pilnowania wątków (no dobra, nie zawsze) na rzecz pisania faktycznego programu.
Generalnie wątki są złe, bo mało kto umie ich dobrze używać, a nawet wyjadaczom potrafi wątkowy „heisenbug” stanąć ością w gardle.

0

A możecie jeszcze napisać co to takiego ten jednowątkowy reactor? Co to w ogóle "reactor" ? Pierwszy raz słyszę to określenie...

0

Taki wzorzec projektowy. Podałem Ci czego w google’u szukać.

1 użytkowników online, w tym zalogowanych: 0, gości: 1