[C] Prosta aplikacja klient-serwer

0

Witam!!

Chciałbym na ćwiczenia zrobić prostą aplikacje klient-serwer w C pod ort! korzystającą z JEDNEGO gniazda. Zadanie polega na tym aby wysłać do programu nasluchującego liczbę w formacie long (zakodowaną w formacie sieciowym). Następnie odebrać od niego losowo wygenerowaną liczbę (long) do ktorej dodaje 1 i znowu wysyłam. Udaje mi się wysłać liczbę, niestety problem zaczyna się gdy chce odebrać losową. Zgodnie z kodami zródłowymi podanymi niżej w siec.c wyskakuje komunikat "Bind nie powiodl sie!", natomiast w spr.c ukazuje się komunikat: "drugi recv nie powiodl sie". Meczę się już z tym 3 dzień i nie mogę dojść co jest przyczyną. Proszę o wskazanie błędu, będę wdzięczny.

Z góry dziekuję za odpowiedz.
Pozdrawiam

siec.c

#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <string.h>

int main(void) {
        unsigned int port=4444;
        char adres_ip[512]="XXX.XXX.XXX.XXX";
        long format_sieciowy, odbior=0, indeks=2122211;
        struct sockaddr_in wychodzace, przychodzace, nadawca;
        socklen_t dl;
        int gniazdo, gniazdo2;

        gniazdo = socket(AF_INET, SOCK_STREAM, 0);
        wychodzace.sin_family = AF_INET;
        wychodzace.sin_port = htons(port);
        wychodzace.sin_addr.s_addr = inet_addr(adres_ip);
        memset(&(wychodzace.sin_zero),0,8);

        if(connect(gniazdo, (struct sockaddr*) &wychodzace, sizeof(wychodzace))<0) {
                      printf("Polaczenie nie powiodlo sie");
                      return 1;
                      }
        format_sieciowy = htonl(indeks);
        printf("format sieciowy: %u\n", format_sieciowy);
        send(gniazdo, &format_sieciowy, sizeof(long), 0);

//-------------------!!!   pobranie losowej liczby  !!!--------------

        przychodzace.sin_family = AF_INET;
        przychodzace.sin_port = htons(port);
        przychodzace.sin_addr.s_addr = INADDR_ANY;
        if (bind(gniazdo, (struct sockaddr*) &przychodzace, sizeof(przychodzace))<0) {
                printf("Bind nie powiodl sie!\n");
                                return 1;
         }

       if(listen(gniazdo, 10)<0) {
                printf("Listen nie powidl sie!\n");
                return 1;
        }

        printf("Czekam na polaczenie ...\n");
        dl=sizeof(struct sockaddr_in);
        while((gniazdo2=accept(gniazdo, (struct sockaddr*) &nadawca, &dl))>0) {
                if(recv(gniazdo2,&odbior, sizeof(long), 0)!=sizeof(long)) {
                        printf("Recv nie powidl sie!\n");
                        close(gniazdo2);
                        continue;
                }
        }
        odbior=ntohl(odbior);
        printf("Liczba przesłana z serwera: %d", odbior);
        odbior++;
        odbior=htonl(odbior);
        send(gniazdo, &odbior, sizeof(long), 0);
        close(gniazdo);
        return 0;
}

spr.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>

struct sockaddr_in endpoint;
FILE *flog;
char myhostname[1024];

int main(int argc, char **argv) {
    long lnIn1, lnIn2, lhIn1, lhIn2, lhOut, lnOut;
    int sdServerSocket, sdConnection, retval;
    socklen_t sin_size;
    struct sockaddr_in incoming;
    struct hostent *heLocalHost;
    char sign;

    sin_size = sizeof(struct sockaddr_in);

    sdServerSocket = socket(AF_INET, SOCK_STREAM, 0);
    gethostname(myhostname, 1023);
    heLocalHost = gethostbyname(myhostname);

    endpoint.sin_family = AF_INET;
    endpoint.sin_port = htons(4444);
    endpoint.sin_addr = *(struct in_addr*)
                        heLocalHost->h_addr;
    memset(&(endpoint.sin_zero),0,8);

    printf("slucham na %s:%d\n",
           inet_ntoa(endpoint.sin_addr),
           ntohs(endpoint.sin_port));

    retval = bind(sdServerSocket,
                  (struct sockaddr*) &endpoint,
                  sizeof(struct sockaddr));

    if (retval < 0) {
        printf("bind nie powiodl sie\n");
        return 1;
    }

    listen(sdServerSocket, 10);

    sin_size = sizeof(struct sockaddr_in);
    while ((sdConnection =

            accept(sdServerSocket,
                   (struct sockaddr*) &incoming,
                   &sin_size))

            > 0) {
        printf("Polaczenie z %s:%d\n",
               inet_ntoa(incoming.sin_addr),
               ntohs(incoming.sin_port));

        if (recv(sdConnection, &lnIn1, sizeof(long),0)
            != sizeof(long)) {
            printf("pierwszy recv nie powiodl sie\n");
            close(sdConnection);
            continue;
        }
        lhIn1 = ntohl(lnIn1);

        lhOut = random();
        lnOut = htonl(lhOut);

        if (send(sdConnection, &lnOut, sizeof(long), 0)
            != sizeof(long)) {
            printf("send nie powiodl sie\n");
            close(sdConnection);
            continue;
        }

        if (recv(sdConnection, &lnIn2, sizeof(long), 0)
            != sizeof(long)) {
            printf("drugi recv nie powiodl sie\n");
            close(sdConnection);
            continue;
        }

        lhIn2 = ntohl(lnIn2);

        flog = fopen("zad.txt","a");
        if (lhIn2 == lhOut + 1) sign = '+';
        else sign = '-';
        fprintf(flog,"%c %ld from %s:%d : %ld, %ld\n",
                sign,
                lhIn1,
                inet_ntoa(incoming.sin_addr),
                ntohs(incoming.sin_port),
                lhOut,
                lhIn2);

        close(sdConnection);
        fflush(flog);
        fclose(flog);
    }

    printf("Blad sieci\n");
    fclose(flog);
    return 0;
}


0

nie mozna re-uzywac socketow. socket raz zconnectowany albo ustawiony na nasluchiwanie, po skonczonej pracy jest do wyrzucenia. jedyne co mozna z nim zrobic po skonczonej pracy to zamknac polaczenie i zniszczyc socket.

ponizej przykladowe prawidlowe "cykle zycia" socketow. zwroc uwage, ze po stronie serwerowej, sockety otrzymane od accept traktuje sie w 100% tak jak klienckie

strona kliencka:

gniazdo = socket(...
connect(gniazdo..
send|recv(gniazdo,...
send|recv(gniazdo,...
..
send|recv(gniazdo,...
send|recv(gniazdo,...
shutdown(gniadzo
close(gniazdo

strona serwerowa:

gniazdo=socket(,..
bind(gniazdo,..
listen(gniazdo,..
klient = accept(gniazdo,..
send|recv(klient,...
send|recv(klient,...
...
send|recv(klient,...
shutdown(klient,
close(klient
klient = accept(gniazdo,..
send|recv(klient,...
send|recv(klient,...
...
send|recv(klient,...
shutdown(klient,
close(klient
...
klient = accept(gniazdo,..
send|recv(klient,...
...
send|recv(klient,...
shutdown(klient,
close(klient
shutdown(gniazdo,
close(gniazdo

0

Czyli nie da się tego zrobić za pomocą tylko jednego gniazda, tak jak jest w zadaniu??

0

w ten sposob jak probujesz - nie. natomiast w najprostszym przypadku, do napisnia klineta potzrebujesz 1 gniazdo, a do serwera - 1 + po jednym gniezdzie na klienta ktore otrzymasz od accept. tak wiec mzna powiedziec ze jest tylko po jednym. zastanow sie np. po co w pierwszym pliku zrywasz pierwotne polaczenie? jak juz raz sie connectniesz, to jestes podlaczony to mozesz zarowno wysylac jak i odbierac.. nie ma pootrzeby przerywac polaczenia tylko po to aby zaraz je nawiazac tylko w druga strone.. tosamo zreszta w drugim pliku.. przemysl to:

plik1, "klient":
socket()
connect()
send(liczba)
recv(jegoliczba)
send(jegoliczba+1)
shutdown()
close()

plik2, "serwer":
socket()
bind()
listen()
klient = accept()
recv(klient, liczbaklietna)
send(klietn rand())
recv(randklietn, _plus1)
shutdown(klient)
close(klient)
shutdown()
close()

jak widac, zadanie jest wypelnione, a polaczenie jest tylko jedno!

0

Na program drugi nie mam wpływu. Dostałem go aby testować swój. Jak po stronie klienta mam użyć recv jeżeli jako pierwszy parametr trzeba podać deskryptor gniazda, który tworzy się za pomocą polecenia accept?? A accept'a nie figuruje na liście w poście wyżej po stronie klienta.

0

czlowiecze.. zastanow sie: socket to socket. nie ma zadnej roznicy pomiedzy socketem ktory otrzymasz z accept a socketem ktory sobie recznie utworzysz i zconnect()ujesz. jedyny wymog to jest taki, zeby po jednej stronie byl socket utworzony w sposob A a po drugiej stronie przez sposob B. nikt nigdy nie mowil ze zeby moc uzywac recv to musisz miec socket zwrocony przez accept. jedyny wymog brzmi: socket ma byc podlaczony. caly czas z uporem maniaka pokazuje Ci dwa przyklady kodu - serwerowy i kliencki. klient laczy sie przy pomocy connect, a serwer - przy pomocu accpet. i tyle. a potem po kazdej stronie uzywasz send i recv do woli

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