Gniazda komunikacyjne

0

Witam!

Mam problem, który powinien być załatwiony właściwie na wczoraj. Na zaliczenie miałam napisać serwer wielowątkowy w Visual Studio ( [diabel] ). Program napisany, został wysłany prowadzącemu i otrzymałam taką oto odpowiedź : nie zamykane gniazda komunikacyjne. Program muszę jeszcze dziś przesłać więc jeśli ktoś mógły rzucić okiem na to gdzie jest błąd byłabym dozgonnie wdzięczna. Nie mam bladego pojęcia co się mojemu wykładowcy nie podoba.

Oto kod:

#include "stdafx.h"
#include <winsock2.h>
#include <process.h>
#include <string.h>
#include <iostream.h>
#include <stdio.h>
#include <conio.h>
#pragma comment(lib,"ws2_32.lib")


void Connection(int iPort, char * cAdres);
void RecvSend(void * vClient);
void SetConsole(int width, int height, char * title);
void print_error(void);

int iClient = 0;
int iClientMax = 0;
CRITICAL_SECTION CriticalSection;

int main()
{
	int iPort;
	char ch_int[24];
	SetConsole(100,50,"multithread server");
	InitializeCriticalSection(&CriticalSection);

	

	printf("Podaj interfejs (IP): ");
	scanf("%s",&ch_int);
	if((inet_addr(ch_int)==INADDR_NONE)) ch_int[0]='0';
	printf("Podaj numer portu: ");
	scanf("%d",&iPort);


	if(iPort==0) iPort=7;
	printf("Max liczba klientow: ");
	scanf("%d",&iClientMax);

	
	printf("Czekam na polaczenia - nr portu: %d \n",iPort);
	printf("\nDowolny klawisz - wyjscie z programu\n");
	Connection(iPort, ch_int);	
	return 0;
}



//*******************************************************************************
//*Name: connection
//*Descripton: funkcja uruchamia gniazdo i kojarzy je z ardesem serwera oraz rozpoczyna nasluchiwanie na tak skojarzonym gniezdzie
//*Arguments: i_Port - numer portu
//*Return: brak
//*Uses: brak
//*Modify: brak
//*Author: 
//*Date: 21.05.2008
//*******************************************************************************
void Connection(int iPort, char * cAdres)
{
	WSADATA W_data;
	
	SOCKET sSerwer;
	struct sockaddr_in server;;
	struct hostent *host = NULL;
	server.sin_family = PF_INET;
	server.sin_addr.s_addr = inet_addr(cAdres);
	server.sin_port = htons(iPort);
	
	SOCKET sClient;
	struct sockaddr_in klient;
	int addrlenKlient = sizeof(klient);
	
	
	if (WSAStartup(MAKEWORD(2,2), &W_data) != 0)
	{
		SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),12);
		printf("socket error\n");
		exit(1);
	}
	
	sSerwer = socket(PF_INET, SOCK_STREAM, IPPROTO_IP);
	if (sSerwer == INVALID_SOCKET) 
	{
		SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),12);
		printf("socket creating failed!\n");
		print_error();
		
		
		if(closesocket(sSerwer) == SOCKET_ERROR)
		{		
			printf("socket closing failed!\n");
			print_error();
			
		}
		
		WSACleanup();
		exit(1);
	}
	
	
	if (bind(sSerwer, (SOCKADDR *) &server, sizeof(server))==INVALID_SOCKET)
	{
		SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),12);
		printf("error in function bind!\n");
		print_error();
		
		if(closesocket(sSerwer) == SOCKET_ERROR)
		{		
			printf("socket closing failed!\n");
			print_error();
		
		}
		
		WSACleanup();
		exit(1);
	}
	
	
	if (listen(sSerwer,SOMAXCONN) == SOCKET_ERROR)
	{
		SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),12);
		printf("error in function listen!\n");
		print_error();
		
		if(closesocket(sSerwer) == SOCKET_ERROR)
		{		
			printf("socket closing failed!\n");
			print_error();
			
		}
		
		WSACleanup();
		exit(1);
	}
	while(1)
	{
		
		SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),15);
		timeval t;
		t.tv_sec=0;
		t.tv_usec=100;	
		fd_set sockets;
		FD_ZERO(&sockets);
		FD_SET(sSerwer,&sockets);
		if(select(0,&sockets,NULL,NULL,&t))
		{
			sClient = accept(sSerwer, (SOCKADDR *) &klient, &addrlenKlient);
			if (sClient == INVALID_SOCKET)
			{
				SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),12);
				printf("error in function accept() error code : %d\n",WSAGetLastError());
				print_error();
				break;
			}
					
			EnterCriticalSection(&CriticalSection); 
			iClient++;
			LeaveCriticalSection(&CriticalSection);
			if (iClient<=iClientMax)
			{
				printf("\nPodlaczono nowego klienta [%d] \n\n",iClient);
				_beginthread(RecvSend,0,(void*)sClient);
			}
			else
			{
				SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),12);
				printf("\nOdmowa podlaczenia %d, max. ilosc klient przekroczona %d \n",iClient,iClientMax);
				EnterCriticalSection(&CriticalSection); 
				iClient--;
				LeaveCriticalSection(&CriticalSection);
			}

		
		
		}
		if (kbhit()) 
		{
		
			printf("Serwer zakonczyl prace :) \n");
			Sleep(1000);
			break;
		}
	}
	closesocket(sSerwer);
	WSACleanup();
	
}

//*******************************************************************************
//*Name: RecvSend
//*Descripton: Funkcja wywolywana jako nowy watek. Odbiera i wysyla dane               
//*Arguments:      void *vClient - wskaznik typu void do zmiennej vClient
//*Return: brak
//*Uses: brak
//*Modify: brak
//*Author: 
//*Date: 21.05.2008
//*******************************************************************************
void RecvSend(void *vClient)
{	

char szBuffer[255];
int iretval;


SOCKET socket=(SOCKET)vClient;


	while(!kbhit())
	{
		iretval = recv(socket,szBuffer,sizeof (szBuffer),0 ); 
		SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),15);
		if ((iretval<0)||(iretval>255))
		{
			SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),12);
			printf("\nklient rozlaczyl sie... (recv)!\n");
			print_error();
			printf("\n\nOczekuje na polaczenie...\n");
			closesocket(socket);
			EnterCriticalSection(&CriticalSection); 
			iClient--;
			LeaveCriticalSection(&CriticalSection);
			_endthread();
			return;
		}			
		
		
		szBuffer[iretval]=0;
		int rozm=strlen(szBuffer);
		SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),10);
		printf("\nreceived %d bytes [%s] from client\n",rozm,szBuffer);


		if (send(socket,szBuffer,rozm+1,0)==SOCKET_ERROR)
		{
			SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),12);
			printf("\nklient rozlaczyl sie... (send)!\n");
			print_error();
			printf("\n\nOczekuje na polaczenie...\n");
			closesocket(socket);
			EnterCriticalSection(&CriticalSection); 
			iClient--;
			LeaveCriticalSection(&CriticalSection);
			_endthread();
			return;
		}
		printf("data sent to client\n");
	}
}


//*******************************************************************************
//*Name: SetConsole
//*Descripton: funkcja ustawia wielkosc konsoli oraz jej pasek tytulowy
//*Arguments: width - szerokosc konsoli
//*			  height- wysokosc konsoli
//*			  title- tytul okna konsolowego
//*Return: brak
//*Uses: brak
//*Modify: brak
//*Author: 
//*Date: 23.05.2008
//*******************************************************************************
void SetConsole(int width, int height, char * title)
{
	COORD size;
	size.X = width;
	size.Y = height;
	SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE),size);
	SetConsoleTitle(title);
}


//*******************************************************************************
//*Name: print_error
//*Descripton: funkcja wyswietla rodzaj zaistnialego bledu
//*Arguments: brak
//*Return: brak
//*Uses: brak
//*Modify: brak
//*Author: 
//*Date: 23.05.2008
//*******************************************************************************
void print_error(void)
{
	char *ch_error=new char [200];
	switch (WSAGetLastError())
	{
	case 0:
		{
			strcpy(ch_error,"Connection finished by host"); break;
		}
	case 10013 :
		{
			strcpy(ch_error,"Permission denied"); break;
		}		
	case 10048 :
		{
			strcpy(ch_error,"Address already in use"); break;
		}
	case 10049 :
		{
			strcpy(ch_error,"Cannot assign requested address"); break;
		}
	case 10047 :
		{
			strcpy(ch_error,"Address family not supi_ported by protocol family"); break;
		}
	case 10037 :
		{
			strcpy(ch_error,"Operation already in progress"); break;
		}
	case 10053 :
		{
			strcpy(ch_error,"Software caused connection abort"); break;
		}
	case 10054 :
		{
			strcpy(ch_error,"Client's software was closed"); break;
		}
	case 10039 :
		{
			strcpy(ch_error,"Destination address required"); break;
		}
	case 10014 :
		{
			strcpy(ch_error,"Bad address"); break;
		}
	case 10064 :
		{
			strcpy(ch_error,"Host is down"); break;
		}
	case 10065 :
		{
			strcpy(ch_error,"No route to host"); break;
		}
	case 10036 :
		{
			strcpy(ch_error,"Operation now in progress"); break;
		}
	case 10004 :
		{
			strcpy(ch_error,"Interrupted function call"); break;
		}
	case 10022 :
		{
			strcpy(ch_error,"Invalid argument"); break;
		}
	case 10056 :
		{
			strcpy(ch_error,"Socket is already connected"); break;
		}
	case 10024 :
		{
			strcpy(ch_error,"Too many open files"); break;
		}
	case 10040 :
		{
			strcpy(ch_error,"Message too long"); break;
		}
	case 10050 :
		{
			strcpy(ch_error,"Network is down"); break;
		}
	case 10052 :
		{
			strcpy(ch_error,"Network dropped connection on reset"); break;
		}
	case 10051 :
		{
			strcpy(ch_error,"Network is unreachable"); break;
		}
	case 10055 :
		{
			strcpy(ch_error,"No buffer space available"); break;
		}
	case 10042 :
		{
			strcpy(ch_error,"Bad protocol option"); break;
		}
	case 10057 :
		{
			strcpy(ch_error,"Socket is not connected"); break;
		}
	case 10038 :
		{
			strcpy(ch_error,"Socket operation on nonsocket"); break;
		}
	case 10045 :
		{
			strcpy(ch_error,"Operation not supi_ported"); break;
		}
	case 10046 :
		{
			strcpy(ch_error,"Protocol family not supi_ported"); break;
		}
	case 10067 :
		{
			strcpy(ch_error,"Too many processes"); break;
		}
	case 10043 :
		{
			strcpy(ch_error,"Protocol not supi_ported"); break;
		}
	case 10041 :
		{
			strcpy(ch_error,"Protocol wrong type for socket"); break;
		}
	case 10058 :
		{
			strcpy(ch_error,"Cannot send after socket shutdown"); break;
		}
	case 10044 :
		{
			strcpy(ch_error,"Socket type not supi_ported"); break;
		}
	case 10060 :
		{
			strcpy(ch_error,"Connection timed out"); break;
		}
	case 10109 :
		{
			strcpy(ch_error,"Class type not found"); break;
		}
	case 10035 :
		{
			strcpy(ch_error,"Resource temporarily unavailable"); break;
		}
	case 11001 :
		{
			strcpy(ch_error,"Host not found"); break;
		}
	case 10093 :
		{
			strcpy(ch_error,"Successful WSAStartup not yet performed"); break;
		}
	case 11004 :
		{
			strcpy(ch_error,"Valid name, no data record of requested type"); break;
		}
	case 11003 :
		{
			strcpy(ch_error,"This is a nonrecoverable error"); break;
		}
	case 10091 :
		{
			strcpy(ch_error,"Network subsystem is unavailable"); break;
		}
	case 11002 :
		{
			strcpy(ch_error,"Nonauthoritative host not found"); break;
		}
	case 10092 :
		{
			strcpy(ch_error,"Winsock.dll version out of range"); break;
		}
	case 10101 :
		{
			strcpy(ch_error,"Graceful shutdown in progress"); break;
		}
	default :
		{
			strcpy(ch_error,"unknown error"); break;
		}
 	}
	
	SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),12);
	printf("error: %s\n",ch_error);
	delete [] ch_error;
	return;
}
0

Powinienes zamykac gniazda

if (iClient<=iClientMax)
                        {
                                printf("\nPodlaczono nowego klienta [%d] \n\n",iClient);
                                _beginthread(RecvSend,0,(void*)sClient);
                        }
                        else
                        {
                                SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),12);
                                printf("\nOdmowa podlaczenia %d, max. ilosc klient przekroczona %d \n",iClient,iClientMax);
                                EnterCriticalSection(&CriticalSection);
                                iClient--;
                                LeaveCriticalSection(&CriticalSection);
                        }

tutaj w else, poniewaz accept ci zwraca polaczone gniazdo z klientem, gdy odmawiasz mu polaczenia powiniensc pozniej zamknac gniazdo "sClient".

A kolejnym miejscem gdzie powinienes zamknac gniazda jest

    if (kbhit())
                {
               
                        printf("Serwer zakonczyl prace :) \n");
                        Sleep(1000);
                        break;
                }

powinienes rozlaczyc polaczonych klientow i zamknac gniazdo serwera.

0

Czyli powinno być tak:

if (kbhit())
{

  	printf("Serwer zakonczyl prace :) \n");
  	Sleep(1000);
  	break;
  	closesocket(sSerwer);
  	WSACleanup();
  }

i tak:

if (iClient<=iClientMax)
{
printf("\nPodlaczono nowego klienta [%d] \n\n",iClient);
_beginthread(RecvSend,0,(void*)sClient);
}
else
{
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),12);
printf("\nOdmowa podlaczenia %d, max. ilosc klient przekroczona %d \n",iClient,iClientMax);
closesocket(sSerwer);
WSACleanup();
EnterCriticalSection(&CriticalSection);
iClient--;
LeaveCriticalSection(&CriticalSection);
}

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