Problem z programem Client/Serwer

0

Witam. Na poczatek informuje ze dopiero zaczynam zabawe z WinSock dlatego prosze o wyrozumialosc... Pisze program client/serwer i mam juz problem, na samym poczatku bo nie wyglada no to ze nie ma polaczenia, korzystam z kursu z winapi.org i jeszcze jakiegos z neta...

kawałek kodu:

SERWER:

LRESULT CALLBACK WndProc ( HWND hwnd , UINT message , WPARAM wParam , LPARAM lParam )
{
	HDC         hdc ;
	PAINTSTRUCT ps ;

	static SOCKET nasluchujacy , polaczony ;
	struct sockaddr_in my_addr , their_addr ;
	int size ;

	static TCHAR szBuffer [ MAX_PATH ] ;
	wsprintf ( szBuffer , TEXT ( "Brak połączeń" ) ) ;
	
	switch ( message )
	{
	case WM_CREATE:

		my_addr.sin_addr.s_addr = INADDR_ANY ;
		my_addr.sin_family = AF_INET ;
		my_addr.sin_port = 8080 ;
		memset ( &( my_addr.sin_zero ) , '\0' , 8 ) ;

		nasluchujacy = socket ( PF_INET , SOCK_STREAM , 0 ) ;
		if ( !nasluchujacy )
		{
			MessageBox ( hwnd , TEXT ( "Błąd" ) , NULL , MB_OK | MB_ICONERROR ) ;
		}

		bind ( nasluchujacy , ( struct sockaddr * ) & my_addr , sizeof ( struct sockaddr ) ) ;
		listen ( nasluchujacy , 5 ) ;
		WSAAsyncSelect ( nasluchujacy , hwnd , WM_USER , FD_ACCEPT | FD_CONNECT | FD_READ | FD_WRITE ) ;
		return 0 ;

	case WM_USER :
		switch ( WSAGETSELECTEVENT ( lParam ) )
		{
		case FD_ACCEPT :
			polaczony = accept ( nasluchujacy , ( struct sockaddr * ) & their_addr , & size ) ;
			wsprintf ( szBuffer , TEXT ( "Klient podłączony" ) ) ;
			InvalidateRect ( hwnd , NULL , TRUE ) ;
			break ;

		case FD_CONNECT :
			break ;
		}

		return 0 ;
		
	case WM_PAINT:
		hdc = BeginPaint ( hwnd , &ps ) ;

		TextOut ( hdc , 10 , 10 , szBuffer , lstrlen ( szBuffer ) ) ;

		EndPaint ( hwnd , &ps ) ;
		return 0 ;
		
	case WM_DESTROY:
		closesocket ( nasluchujacy ) ;
		PostQuitMessage ( 0 ) ;
		return 0 ;
	}
	return DefWindowProc ( hwnd , message , wParam , lParam ) ;
}

KLIENT:

LRESULT CALLBACK WndProc ( HWND hwnd , UINT message , WPARAM wParam , LPARAM lParam )
{
	HDC         hdc ;
	PAINTSTRUCT ps ;

	static SOCKET klient ;
	struct sockaddr_in my_addr ;
	
	switch ( message )
	{
	case WM_CREATE:

		klient = socket ( PF_INET , SOCK_STREAM , 0 ) ;

		my_addr.sin_addr.s_addr = INADDR_ANY ; // inet_addr ( "10.4.12.2" )
		my_addr.sin_family = AF_INET ;
		my_addr.sin_port = htons ( 8080 ) ;
		memset ( &( my_addr.sin_zero ) , '\0' , 8 ) ;

		if ( !klient )
		{
			MessageBox ( hwnd , TEXT ( "Błąd" ) , NULL , MB_OK | MB_ICONERROR ) ;
		}

		if ( !connect ( klient , ( struct sockaddr * ) &my_addr , sizeof ( struct sockaddr ) ) )
		{
			MessageBox ( hwnd , TEXT ( "Nie można nawiązać połączenia" ) , NULL , MB_OK | MB_ICONERROR ) ;
		}
		WSAAsyncSelect ( klient , hwnd , WM_USER , FD_CONNECT | FD_READ | FD_WRITE | FD_ACCEPT ) ;

		return 0 ;
		
	case WM_PAINT:
		hdc = BeginPaint ( hwnd , &ps ) ;
		EndPaint ( hwnd , &ps ) ;
		return 0 ;
		
	case WM_DESTROY:
		closesocket ( klient ) ;
		PostQuitMessage ( 0 ) ;
		return 0 ;
	}
	return DefWindowProc ( hwnd , message , wParam , lParam ) ;
}

Co tu jest zle, wydaje mi sie ze wszystko zrobilem tak jak w kursie... chodzi o to, ze po wlaczeniu serwera, mam w nim komunikat Brak polaczen... nastepnie wlaczam klienta... i nadal to samo, mimo ze komunikat powinien sie zmienic... co jest nie tak?

0

Dobra widze, że będzie problem z odpowiedzią, może zapytam się jakie czynności powinien wykonać klient i serwer, żeby się upewnić czy na pewno wszystko zawarłem w programie co potrzebne...

Serwer:

  1. Wypełnienie struktury adresu
  2. Wywołanie socket ()
  3. Wywołanie bind (), aby ustawić socket na odpowiedzni port
  4. Wywołanie listen ()
  5. Wywołanie WSAAsyncSelect () aby informacje o polaczeniu byla przekazywana jako komunikat

Klient:

  1. Wywołanie socket ()
  2. Wypełnienie struktury adresu
  3. Wywołanie connect ()
  4. Wywołanie WSAAsyncSelect ()

Tak właśnie zrobiłem i nie otrzymuje po stronie serwera komunikatu FD_CONNECT ani FD_ACCEPT tak wiec dupa, czy takie kroki sa prawidlowe ?

0

Nie jestem zbyt dobry w temacie, ale ostatnio napisałem czerpiac źródła tutaj coś takiego:
Serwer

#include <winsock.h>
#include <stdio.h>
#include <stdlib.h>
#include <vcl.h>
#include <string.h>

#define DEFAULT_PORT 10017
#define DEFAULT_BUFFER 4096

int koniec=0;
static char *s_koniec="bye";

SOCKET sListen,	sClient;

//wątek do komunikacji z klientem
DWORD WINAPI ClientThread(LPVOID lpParam)
{
	SOCKET sock = (SOCKET)lpParam;
	char szBuff[DEFAULT_BUFFER];
	int ret;
	while(!koniec)
	{
		/*tutaj sobie piszesz co ma robic po polaczeniu klienta... czyli odbieranie, przetwarzanie pakietow itd...*/
		ret = recv(sock, szBuff, DEFAULT_BUFFER, 0);
		if (ret == 0) break;	   // Zamknięcie uzgodnione
		else if (ret == SOCKET_ERROR)
		{
			printf("Funkcja recv() zakończona błędem: %d\n",WSAGetLastError());
			break;
		}
		szBuff[ret] = '\0';
		printf("ODBIÓR: '%s'\n", szBuff);
		send(sock, szBuff, strlen(szBuff), 0);
		if (!strcmp(szBuff,s_koniec)) koniec=1;
	}
	return 0; 
}

int main()
{
	WSADATA wsd;
	HANDLE hThread;
	DWORD dwThreadID;
	struct sockaddr_in local, client; 
	struct hostent *host = NULL;
	int iAddrsize;

	// inicjuj Winsock 2.2 
	if (WSAStartup(MAKEWORD(2,2), &wsd) != 0)
	{
		printf("Bladd ladowania Winsock 2.2!\n");
		return 1;
	}

	sListen = socket(AF_INET, SOCK_STREAM, 0);
	if (sListen == SOCKET_ERROR) 
	{
		printf("Blad funkcji socket(): %d\n", WSAGetLastError());
		return 1;
	}

	memset((void *)(&local), 0, sizeof(local));
	local.sin_addr.s_addr = htonl(INADDR_ANY);
	local.sin_family = AF_INET;
	local.sin_port = htons(DEFAULT_PORT);
	if (bind(sListen, (struct sockaddr *)&local, sizeof(local)) == SOCKET_ERROR)
	{
		printf("Blad funkcji bind(): %d\n", WSAGetLastError());
		return 1;
	}

	host = gethostbyname("localhost");
	if (host == NULL)
	{
		printf("Nie udalo sie wydobyc nazwy serwera\n");
		return 1;
	}

	listen(sListen, 8);
	printf("SERWER NASLUCHUJE\n");
	printf("Adres: %s, port: %d\n", host->h_name, DEFAULT_PORT);

	/* tutaj akceptuje nadchodzace polaczenia i kazdemu polaczeniu przydziela nowe gniazdo i wykonywane sa operacje w watku...*/
	while (!koniec)
	{
		iAddrsize=sizeof(client);
		sClient = accept(sListen, (struct sockaddr FAR *)&client, &iAddrsize);
		if (sClient == INVALID_SOCKET)
		{
			printf("Blad funkcji accept(): %d\n", WSAGetLastError());
			return 1;
		}
		printf("Zaakceptowano polaczenie: serwer %s, port %d\n", inet_ntoa(client.sin_addr), ntohs(client.sin_port));

		//tutaj jest tworzony watek dla nowego polaczenia
		hThread = CreateThread(NULL, 0, ClientThread,(LPVOID)sClient, 0, &dwThreadID);
		if (hThread == NULL)
		{
			printf("Blad funkcji CreateThread(): %d\n", WSAGetLastError());
			return 1;
		} 
		CloseHandle(hThread);
	} 
	closesocket(sListen);

	WSACleanup();
	return 0;
}

Klient:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>
#include <winsock2.h>
#include <vcl.h>

#define DEFAULT_PORT 10017
#define DEFAULT_BUFFER 4096

char koniec_k[]="q";
char koniec_s[]="bye";

int main(int argc, char **argv)
{
	WORD    RequiredVersion;
	WSADATA WData;
	SOCKET  s;
	struct  sockaddr_in addr;
	char buf[DEFAULT_BUFFER];
	int buflen,k,result,ret;

	printf("Trwa ladowanie winsock2...\n\n");

	RequiredVersion = MAKEWORD(2, 2);
	if (WSAStartup(RequiredVersion, &WData) != 0)
	{
		printf("Blad inicjalizacji WinSock2\n");
		return 1;
	}

	memset((void *)(&addr), 0, sizeof(addr));
	addr.sin_family      = AF_INET;
	addr.sin_port        = htons(DEFAULT_PORT);
	addr.sin_addr.s_addr = inet_addr("127.0.0.1");

	s = socket(AF_INET, SOCK_STREAM, 0);
	printf("\nNawiazuje polaczenie z serwerem...\n");
	result=connect(s, (struct sockaddr*)&addr, sizeof(addr));
	if (result == SOCKET_ERROR)
	{
		printf("\nBłąd połączenia!\n");
		return 1;
	}
	printf("\nNawiazano polaczenie...\n");

	while(1)
	{
		fgets (buf, DEFAULT_BUFFER, stdin);
		buflen=(int)strlen(buf);
		buf[buflen-1]='\0';
		k=send(s, buf, buflen, 0);
		printf("Wyslano znakow: %d\n",k);

		ret = recv(s, buf, DEFAULT_BUFFER, 0);
		if (ret == 0) break;   // Zamkniŕcie uzgodnione
		else if (ret == SOCKET_ERROR)
		{
			printf("Funkcja recv() zakonczona bledem: %d\n",WSAGetLastError());
			break;
		}
		buf[ret] = '\0';
		printf("ODBIOR: '%s'\n", buf);
		if (strcmp(buf, koniec_k) == 0) break;
		if (strcmp(buf, koniec_s) == 0) break;
	}

	closesocket(s);

	WSACleanup();
	return 0;
}

Serwer tworzy wątki dla łączących się klientów
Klient pisze - serwer odbiera i wysyła dotego samego klienta
Pytanie: Jak zrobić, żeby serwer odsyłał do wszystkich?

Jeśli mogę się podłączyć do tematu...
Piszę w Javie (mniejsza o język - chodzi mi o ideę) prostego muda (tekstowa gra przygodowa).
Polega to na tym, że uruchamiamy serwer, do którego podłączają się klienci (może być ich wielu). Gdy klient wysyła informację do serwera, serwer rozsyła ją do wszystkich. Problem jest w postaci blokady: jak zrobić, żeby każdy klient odebrał informację niezaleznie od tego, co robi - układ "Pisz i Odbierz" nie jest tu raczej możliwy.

Ma ktoś jakiś pomysł? Może jakieś wątki odczytywania informacji od serwera i wysyłania informacji na serwer (łącznie z czytaniem z klawiatury).
[???]

0

Klient ma dwa wątki. Jeden odpowiedzialny za kontakt z użytkownikiem, który opiera się na pętli z wykorzystaniem WaitForSingleObjectEx lub MsgWaitForMultipleObjectsEx
Drugi odpowiedzialny jest za kontakt z serwrem, może wysłać temu pierwszemu informacje "priorytetową" za pomocą funkcji QueueUserAPC.

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