Winsock - kłopoty z połączeniem

0

Witam. Jestem w trakcie pisania programu. Stworzyłem klienta i serwer w oparciu o bibliotekę Winsock. Jednak mam kilka problemów z tym projektem, mianowicie piszę w devc++ z wykorzystaniem WinApi i np. chciałem aby Winsock inicjalizując WSA robił to w osobnej bibliotece a tak się niestety nie da. Wywala mi przy kompilacji błędy. Wszystko się ładnie kompiluje kiedy wrzucę to do WinMain. Teraz następny problem. Kiedy wrzucam cały kod do winmain to nie wiem jak teraz zrobić żeby klient cały czas próbował połączyć się z serwerem. Wymyśliłem że zrobię kontrolkę(button) i wkleję do niej kod z funkcją connect ale chyba to nie wypaliło tzn. kiedy próbuję tego użyć to cały czas pokazuje mi się komunikat że się nie połączyło. Nie wiem też dokładnie jak skończyć ten program tak aby serwer wyświetlał wiadomość że klient się podłączył. Wkleję kod który udało mi się napisać jeżeli znajdziecie błędy to proszę o wskazanie. Będę na prawdę wdzięczny.
To jest kod, który znajduje się w programie "Klient":(wszystkie potrzebne zmienne czy obiekty są zainicjalizowane w bibliotece dołączonej do projektu)

 
/*WSA*/
    error = WSAStartup( version, &wsaData );
    /* check for error */
    if ( error != 0 )
{
    /* error occured */
    return FALSE;
}
    /* check for correct version */
    if ( LOBYTE( wsaData.wVersion ) != 2 || HIBYTE( wsaData.wVersion ) != 0 )
{
    /* incorrect WinSock version */
    WSACleanup();
    return FALSE;

}

    /* WinSock has been initialized */
    //Deklaracje
    klient = socket( AF_INET, SOCK_STREAM, 0 ); //Tworzenia gniazda
    host=gethostbyname("");
    IP = inet_ntoa (*(struct in_addr *)*host->h_addr_list);
    memset( &sin, 0, sizeof sin );
    sin.sin_family = AF_INET;
    sin.sin_addr.s_addr = inet_addr(IP);
    sin.sin_port = htons(port);
    WSAAsyncSelect(klient,hwnd,WM_USER,FD_CONNECT|FD_READ|FD_WRITE|FD_ACCEPT);

kod klienta, który dołączyłem do komunikatu

case WM_COMMAND:

        

    result =connect(klient,(struct sockaddr *) &sin, sizeof(sin));

    if (result == SOCKET_ERROR)

    {

          closesocket (klient);

          MessageBox(NULL,"Nie po³¹czono.","NET",MB_OK);

          WSACleanup();

                    }

                    else

                    {

           result = send( klient, sendbuf, (int)strlen(sendbuf), 0 );

    if (result == SOCKET_ERROR) {

        MessageBox(NULL,"Nie wys³ano.","NET",MB_OK);

        closesocket(klient);

        WSACleanup(); 

                    }

}

              break;

     case WM_USER:

            switch (WSAGETSELECTEVENT(lParam))

            {           

            case FD_ACCEPT:

            break;

            case FD_READ:

            break;

            case FD_CONNECT:

            break;

            case FD_WRITE:

            break;

            }  

I kod serwera:

 /*WSA*/

    error = WSAStartup( version, &wsaData );

    /* check for error */

    if ( error != 0 )

{

    /* error occured */

    return FALSE;

}

    /* check for correct version */

    if ( LOBYTE( wsaData.wVersion ) != 2 || HIBYTE( wsaData.wVersion ) != 0 )

{

    /* incorrect WinSock version */

    WSACleanup();

    return FALSE;

}

    /* WinSock has been initialized */



nasluchujacy =  socket( AF_INET, SOCK_STREAM, 0 );

memset( &sin, 0, sizeof(sin) );

sin.sin_family = AF_INET;

sin.sin_addr.s_addr = INADDR_ANY;

sin.sin_port = htons(port);

rozmiar = sizeof(sin);

if ( bind(nasluchujacy,(struct sockaddr *)&sin, sizeof(sin)) == SOCKET_ERROR )

{ 

MessageBox(hwnd,"bind - b³¹d","b³¹d",MB_OK);

WSACleanup();

            }

if (listen(nasluchujacy,SOMAXCONN)==SOCKET_ERROR)

{

            MessageBox(hwnd,"error listen","ERROR",MB_OK);

            WSACleanup();

}

WSAAsyncSelect(nasluchujacy,hwnd,WM_USER,FD_ACCEPT|FD_CONNECT|FD_READ|FD_WRITE);

I do tego dołączona jest lista komunikatów do przechwycenia. Kompletnie nie mogę się w tym połapać.

 case WM_USER:

             switch (WSAGETSELECTEVENT(lParam))

        {

        case FD_ACCEPT:

             polaczony = accept(nasluchujacy,(struct sockaddr *)&sin, &rozmiar);

                       break;

        case FD_READ:

             recv(polaczony,odbiorcza,sizeof(odbiorcza),0);

                       break;

        case FD_CONNECT:

                       break;

        case FD_WRITE:         

                       break;

                       }

Komunikaty te dołączyłem do listy komunikatów w programie. Będę wdzięczny za pomoc, jeśli ktoś jest w stanie mi pomóc i z chęcią to zrobi to proszę pisać na maila lub gg. Pozdrawiam serdecznie

0

Przejrzalem tylko pierwszy kod i kilka uwag:

host=gethostbyname("");

Powinienes podac hosta w tym cudzyslowiu.

IP = inet_ntoa (*(struct in_addr *)*host->h_addr_list);

Zamiast tego uzyj

memcpy(&(sin.sin_addr.s_addr), host->h_addr, host->h_length);
memset( &sin, 0, sizeof sin );

Tu chyba albo cos zle wkleiles albo zapomniales napisac nawiasow. Mozesz tez dac sizeof(struct sockaddr_int);

Dobrze bylo by jeszcze jakbys napisal jakie bledy masz przy kompilacji.

0

Właśnie chodzi że wszystko się bardzo ładnie kompiluje bez najmniejszych problemów kiedy jest wpisane tak jak teraz. Problem polega na tym że uruchamiam na jednym komputerze klienta i serwer i na kliencie naciska na "połącz" i wtedy niby powinno próbować się połączyć no ale chyba się nie łączy bo mi wyskakuje ten komunikat że się nie połączyło i nie wiem czy coś z kodem nie tak czy po prostu się nie może połączyć czy jak. Też wolałbym ten kod jakoś ulepszyć w sensie żeby był bardziej przejrzysty ale kiedy próbuję dać to do biblioteki to wtedy nie chce się skompilować.

0

Witam ponownie. Poradziłem sobie mniej więcej z niektórymi problemami. Napisałem klienta jeszcze raz i udało mi się kod wpakować do osobnego pliku źródłowego, wrzuciłem funkcję connect do reakcji na kliknięcie na przycisk ale mam problem z serwerem. Też mi nieźle poszło z napisaniem ale mam problem przy uruchamianiu. Pisząc program wspomagałem się msdn ale tam momentami mają jakiś dziki kod, który w moim devc++ za nic w świecie się nie skompiluję.

#include <stdio.h>
#include <ws2tcpip.h>
using namespace std;
HWND hwnd;  
SOCKET klient=INVALID_SOCKET;
WSADATA wsaData;
WORD version = MAKEWORD( 2, 0);
struct sockaddr_in sin;

void WSA_init(WORD version, WSADATA wsaData);
void WSA_init(WORD version, WSADATA wsaData)
{
    if (WSAStartup(version,&wsaData) != 0)
    {
    MessageBox(hwnd,"Nastąpił błąd inicjalizacji WSA.", "Error",MB_OK);
    WSACleanup();                               } 
    else
    {
    MessageBox(hwnd,"Inicjalizacja WSA przebiegła pomyślnie.", "Info",MB_OK);
    }
 
 
 }

void set_addr(sockaddr_in sin);
void set_addr(sockaddr_in sin)
{
    sin.sin_family = AF_INET;
    sin.sin_addr.s_addr = inet_addr("199.247.56.121");
    sin.sin_port = htons(50500);
 }
 

void create_listen(SOCKET klient);
void create_listen(SOCKET klient)
{
     
     klient = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
     if (klient == INVALID_SOCKET)
     {
                MessageBox(hwnd,"Socket nie powstał.","Error",MB_OK);
                WSACleanup();
                }
     
 }

void bind_klient(SOCKET klient, sockaddr_in sin);
void bind_klient(SOCKET klient, sockaddr_in sin)
{
     if (bind(klient,(SOCKADDR*)&sin, sizeof(sin)) == SOCKET_ERROR)
     {
     MessageBox(hwnd,"Bind - błąd.","Error",MB_OK);
     closesocket(klient);
     WSACleanup();
                             }
 }

To jest kod nowego serwera. Kompiluje się bez błędu, uruchamia się ale przy bindowaniu wyskakuje błąd że nie może zbindować i nie wiem dlaczego. Ustawiałem IP na IP swojego komputera ale próbowałem też z innym komputerem. Jeżeli ktoś wie w czym tkwi problem, proszę o radę. Pozdrawiam

0

Do funkcji bind przeslij adres socketa i struktury sockaddr_in, zamiast robic kopie.

0

w ogóle to do kazdej z tych funkcji przesylaj adresy, zeby operacje byly wykonywane na tej samej strukturze.

0

Możesz dokładnie napisać jak przesłać ten adres? W sensie nie wiem co rozumiesz przez adres socketa bo on jest właśnie w tej strukturze zapisany. Byłbym wdzięczny jak ktoś spróbowałby to skompilować i sprawdzić u siebie.

0

Odpal sobie te dwa kody i przerob na podobnej zasadzie swoje funkcje:

#include <stdio.h>

void raz(int *l)
{
	*l = 2;
	printf("%d\n", *l);
}

int main(void)
{
	int l;
	l = 5;

	printf("%d\n", l);
	raz(&l);
	printf("%d\n", l);


	return 0;
}

....

#include <stdio.h>

void raz(int l)
{
        l = 2;
        printf("%d\n", l);
}

int main(void)
{
        int l;
        l = 5;

        printf("%d\n", l);
        raz(l);
        printf("%d\n", l);


        return 0;
}

Te dwa przyklady dokladnie ilustruja to co mam na mysli ;)

0

Dalej nie bardzo kumam. W sensie wiem co miałeś na myśli, ale w funkcje które mam w kodzie nie przyjmują wskaźników chyba że chodzi Ci o to aby właśnie przyjmowały wskaźniki. Piszę tego typu program od kilku dni i już jestem na maksa zakręcony z tym wszystkim. Kiedy

void bind_klient(SOCKET *klient, sockaddr_in *sin);
void bind_klient(SOCKET *klient, sockaddr_in *sin)
{
     if (bind(klient,(SOCKADDR*)&sin, sizeof(sin)) == SOCKET_ERROR)
     {
     MessageBox(hwnd,"Bind - błąd.","Error",MB_OK);
     closesocket(klient);
     WSACleanup();
                             }
 }

Kiedy zmieniam w ten sposób to mi wywala błędy przy kompilacji.

0

Odpal tego kody to zobaczysz roznice, a ta Twoja funkcja o tak powinna byc, reszta funkcji tez w ten sposob.

 // klient mozesz w sumie przesylac normalnie, bo to i tak numerek jest
void bind_klient(SOCKET *klient, sockaddr_in *sin)
{
     if (bind(*klient,(struct sockaddr*)sin, sizeof(*sin lub struct sockaddr)) == SOCKET_ERROR) // samo sin juz jest adresem, wiec bez ampresandu
     {
     MessageBox(hwnd,"Bind - błąd.","Error",MB_OK);
     closesocket(*klient);                
     WSACleanup();
                             }
 }

Mozesz tez zrobic przez referencje, Twoj wybor.

0

Spoko zrobiłem tak jak napisałeś i biblioteka kompiluje się bez problemu. Błąd wyskakuje przy wywołaniu funkcji.
Wpisuję bind_klient(*klient,sin) i wywala błąd "invalid type argument of unary". Tak samo kiedy dam jako argument sin albo (struct sockaddr)sin. Jakiś pomysł?

0

Prototypy zmien funkcji zmien, albo w ogóle wywal oraz przesylac masz do funkcji adres, wiec wywolujesz bind(&klient, &sin);

0

No ok właśnie sam wpadłem na pomyśł że adresy wysłać trzeba tylko że po skompilowaniu dalej wywala błąd że nie binduje. Sukces że się kompiluje tyle że dalej nie chce działać ;/

0

Super widzę że nikt nie jest w stanie mi pomóc. Szukałem już wszędzie i nigdzie nie mogę znaleźć odpowiedzi a serwer dalej nie działa jak należy.

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