[C++] Problem z funkcją 'bind'


(Kalin 93) #1

Witam, piszę sobie prosty serwerek oprarty na winsock, no i wszystko jest fajnie, kod się kompiluje, ale funkcja 'bind' zwraca wartość 'INVALID_SOCKET'.

#include 

#include 

#include 


using namespace std;


SOCKET sClient,sListen;


int main ()

{

	WSADATA wsaData;

	WORD wVersion = MAKEWORD (2,0);

	if (!WSAStartup (wVersion,&wsaData)) cout << "WSA uruchomione poprawnie!\n";

	sListen = socket (AF_INET,SOCK_STREAM,IPPROTO_IP);

	if (sListen == INVALID_SOCKET) cout << "Blad socketa\n";

	sockaddr_in server;

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

	int nPort = 9999;

	server.sin_port = htons ((u_short) nPort);

	server.sin_addr.s_addr = htonl (INADDR_ANY);

	server.sin_family = AF_INET;

	if (bind (sListen,(sockaddr*)&server,sizeof (server) == INVALID_SOCKET)) cout << "Bind zakonczony porazka\n";

	if (listen (sListen,SOMAXCONN) == SOCKET_ERROR) cout << "Listen error\n";

	sockaddr_in client;

	sClient = accept (sListen, (sockaddr*)&client, (int *)sizeof(client));

	if (sClient == INVALID_SOCKET) cout << "sClient error\n";

	send (sClient,"Welcome",8,0);

	char cRecieve [5001];

	for (;;)

	{

		recv (sClient,cRecieve,5001,0);

		send (sClient,cRecieve,5000,0);

	}

}

([alex]) #2

Nawias w złym miejscu, ma być:

if (bind (sListen,(sockaddr*)&server,sizeof (server)) == INVALID_SOCKET) cout << "Bind zakonczony porazka\n";

(Kamilozor) #3

Witam, probuje napisac prosta aplikacje "serwera" w VC++ pod Windows, jednak podobnie jak kolega wyzej, mam problem z funkcja bind(). Nie chcialem zakladac kolejnego watku z tym problemem, dlatego pisze tutaj, jako ze jest jeszcze swiezy :wink: otoz funkcja bind zwraca mi kod bledu -1, powyzsze rozwiazanie nie skutkuje, wydaje mi sie ze moze to byc cos z portami, jednak proba zmian nie przyniosla zadnego rezultatu :wink: oto kod programu

#include 

#include 

#include 

#include 

#include 


#pragma comment(lib, "ws2_32.lib")


using namespace std;



int main()

{

	int m_port = 1040;

	int odp;


	WSAData wsdat;

	if (WSAStartup(MAKEWORD(1,1),&wsdat)!= 0)

	{

	cout<
	exit(1);

	}


	struct sockaddr_in odb; 

	odb.sin_family = PF_INET;

	odb.sin_port = htonl(m_port);

	odb.sin_addr.s_addr = inet_addr("128.110.10.1");

	memset(&(odb.sin_zero),'\0', 8); 


	int soc = socket(PF_INET,SOCK_STREAM,0);

	if (soc == -1) 

	{

		cout<<"Blad przy tworzeniu socketa.."<
		exit(1);

	}

	else

		cout<<"Utworzono socket na porcie.. "<<"( "<

	odp = bind(soc,(struct sockaddr *) &odb, sizeof(struct sockaddr_in)); 

	if (odp == -1)

	{

		cout<<"Przypisanie adresu nie powiodlo sie.."<
		exit(1);

	}

	else

		cout<<"Przypisano adres.. "<<"( "<

            // ...

            // itd

            // ...


	closesocket(soc1);


	WSACleanup();


	getch();


}

z gory dziekuje za wskazowki :slight_smile:


([alex]) #4
memset(&(odb.sin_zero),'\0', 8);

zamień na:

memset(odb.sin_zero,0,sizeof(odb.sin_zero)); [/code]

(Kamilozor) #5

podmienilem linijki, niestety nadal zwraca -1 i "Przypisanie adresu nie powiodlo sie.." :confused: kod "wydaje sie" byc poprawny jednak cos tutaj nie gra


([alex]) #6

Zamierzasz podłączać klientów tylko z adresu 128.110.10.1 ? Na ile wiem windows'y tego nie obsłużą, łącz że wszystkimi a na etapie accept - odrzucaj połączenia od innych klientów.

Zamień:

odb.sin_addr.s_addr = inet_addr("128.110.10.1");

na:

odb.sin_addr.s_addr=htonl(INADDR_ANY); [/code]

(Kamilozor) #7

hmm..cos poszlo dalej :slight_smile: bind zwrocil 0 czyli niby jest ok, nawet win sie zapytal czy "odblokowac", ale "cout<


([alex]) #8

A co oczekiwałeś zobaczyć sin_addr?

Do połączenia 1 do 1 jedna aplikacja(wątek) ma być dla klienta a druga aplikacja(wątek) ma być dla serwera.

Z gniazdami datagramowymi można uzyskać połączenie nawet typu N:N*, ale bez gwarancji otrzymania przekazanej informacji.

* gdzie ilość połączonych aplikacji(wątków) jest N+1, czyli każdy do każdego.


(Kamilozor) #9

myslalem ze po wykonaniu bind() i wykonaniu cout zobacze jakis adres (serwera/odbiorcy), ktory wpisal sie do odb.sin_addr :wink: wlasnie takie mialem zalozenie, dlatego zaczalem pisac 1 aplikacje dla serwera, a potem dla klienta :slight_smile: w sumie z gniazdami datagramowymi to bylaby ciekawa sprawa, mysle ze z tym tez sie pobawie, ale najpierw chcialbym to doprowadzic do ladu :slight_smile:


([alex]) #10

Serwer po podłączeniu się pod port musi zacząć nasłuchiwanie, jeżeli jakiś klient spróbuje nawiązać połączenie (dopiero w tym momencie można sprawdzić IP klienta) to serwer musi odrzucić lub zaakceptować połączenie, dopiero kiedy (i jeżeli) serwer zaakceptuję połączenie, klient może próbować coś wysyłać.

W sin_addr serwera zawszę pozostanie htonl(INADDR_ANY) czyli "0.0.0.0", na ile pamiętam można tam próbować wstawić maskę ale nigdy nie widziałem żadnego działającego kodu z takim maskowaniem.


(Kalin 93) #11

Jeśli coś Ci nie działa, to porównaj z moim kodem. On na 100% działa (sprawdzone)


(Kamilozor) #12

wlasnie na poczatku porownywalem kody :wink: jedyne co sie nie zgadzalo to INADDR_ANY, bo chcialem przypisac adres z reki :wink: a nie da sie ustawic adresu serwera na jakis inny? bo widzialem kod do apikacji klienta i w niektorych bylo zawarte "podaj ip serwera", potem "podaj port" i mozna bylo wpisac, wiec chyba nie zawsze musi byc 0.0.0.0? bo zalozmy jakbym chcial zeby dwa hosty (gniazda datagramowe) byly w tej samej sieci to musza miec zgodny adres sieciowy, jak w takim przypadku go ustawic?


([alex]) #13

To nie rozumiem, piszesz klienta czy serwera? Podaj IP serwera - pyta aplikacja po stronie klienta.

UDP działa zupełnie na innej zasadzie, mimo ze program wygląda podobnie.


(Kamilozor) #14

Narazie pisze serwer :slight_smile: dlatego pytam jak to jest z ustawianiem adresu serwera, bo widzialem ze po stronie klienta mozna wpisac IP, a na pewno nie kazdy wpisuje 0.0.0.0 :slight_smile: udp narazie sobie odpuszcze, musze sie zajac tcp :wink:


([alex]) #15

Dla części klienta konieczne jest podanie IP serwera. Część klienta może prosić o nazwę serwera (zamiast IP), wtedy po nazwie najpierw odszukuje adres IP, czyli tak czy owak w końcu do utworzenia sokety potrzebny jest ten IP.


(Kamilozor) #16

hmm..czyli zalozmy ustawiam ten adres serwera na INADDR_ANY czyli automatycznie 0.0.0.0, a nastepnie po stronie klienta po poleceniu "wpisz adres serwera" ktos wpisuje zalozmy 128.110.10.1 i jak maja sie wtedy polaczyc? :slight_smile: zreszta najnizszy adres w IPv4 to 1.0.0.0 to nie rozumiem dlaczego on przyjmuje taka wartosc :wink: kalin93 masz moze swoj kod do klienta? :slight_smile:


([alex]) #17

Tak, po stronie klienta wpisujesz 128.110.10.1 i klient się łączy do serwera podczas instrukcji bind. Zresztą nie musisz się wdawać w to jak to działa pod spodem aby program zaczął działać. :smiley:


(Kalin 93) #18

Miałem :confused: Ale dziś miałem przygodę z dyskiem i straciłem wszystkie dane (w tym projekty C++) więc kodu nie mam.

EDIT: Jednak kod był na forum więc sie uratował :wink:

#include 

#include 

#include 

#include 


using namespace std;


SOCKET Polaczenie;


DWORD WINAPI Wysylanie ()

{

   cout << "Uruchomiono watek Wysylajacy\n";

   string sPolecenie;

   if (Polaczenie == INVALID_SOCKET) cout << "Blad!!!";

   for (;;)

   {

      getline (cin,sPolecenie);

      if (send (Polaczenie,sPolecenie.c_str(),sPolecenie.length()+1,NULL) == 0) cout << "Blad wyslania !";

   }

}


int main ()

{

   WORD wersja = MAKEWORD (2,0);

   WSADATA wsaData;

   if(!WSAStartup(wersja, &wsaData))

   {

      cout << "WSA uruchomione poprawnie!\n";

   }

   if (LOBYTE (wsaData.wVersion) != 2 && HIBYTE (wsaData.wVersion != 0)) cout << "Uruchomiono niepoprawna wersje WSA !";

   Polaczenie = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);

   if (Polaczenie == INVALID_SOCKET)

   {

      cout << "Nie mozna utworzyc socketa!";

      WSACleanup ();

   }

   hostent *host=0;

   cout << "Podaj adres serwera : ";

   string sAdresSerwera;

   cin >> sAdresSerwera;

   sockaddr_in server;

   int nPort = 6667;

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

   server.sin_family = AF_INET;

   server.sin_port = htons ((u_short)nPort);

   server.sin_addr.s_addr = inet_addr (sAdresSerwera.c_str());

   if (server.sin_addr.s_addr == INADDR_NONE)

   {

      host = gethostbyname (sAdresSerwera.c_str());

      if (host == NULL) cout << "Nie moge skonwertowac adresu!\n";

      CopyMemory(&server.sin_addr, host->h_addr_list[0], host->h_length);


   }

   if (!connect (Polaczenie,(sockaddr*)&server,sizeof (server)))

   {

      cout << "Polaczono !\n";

   };

   DWORD ThreadID;

   HANDLE hWysylanie = CreateThread (0,0,(LPTHREAD_START_ROUTINE)Wysylanie,0 ,NULL,&ThreadID);

   char cBufor [10241];

   for (;;)

   {

      memset (cBufor,0,sizeof (cBufor));

      recv (Polaczenie,cBufor,10240,NULL);

      cout << cBufor << "\n";

   }

   _getch();

}

(Kamilozor) #19

dokleilem do kodu serwera fragment z Twojego kodu w celu sprawdzenia i po komunikacie "Oczekiwanie na polaczenie.." nic sie nie wyswietla :wink:

cout<<"Oczekiwanie na polaczenie..."<

struct sockaddr_in nad;

dl = sizeof(struct sockaddr_in);


soc2 = accept(soc1,(struct sockaddr *)&nad,&dl);

if (soc2 == INVALID_SOCKET) cout << "Blad polaczenia..";


send(soc2,"Welcome",8,0);

char message [5001];

for (;;)

{

recv(soc2,message,5001,0);

send(soc2,message,5000,0);

}

(Kalin 93) #20

Te kody na 100 % działają :wink: Sprawdzałem na 2-óch komputerach :wink: