Błąd odczytu z pliku WINSOCK

0

Witam.
Problem polega na tym, że po wpisaniu dobrej nazwy pliku program wywala komunikat o błędnej nazwie, choć plik jest w katalogu o tej takiej nazwie. W załączniku umieszczam kod serwera.

0
#include <winsock2.h>
#include <Windows.h>
#include <Ws2tcpip.h>
#include <map>
#include <iostream>
#include <stdio.h>
#include <stdlib.h>

#pragma warning(disable : 4996)

#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif

#ifndef WS2_LIB
#define WS2_LIB
#pragma comment(lib, "Ws2_32.lib")
#endif 

using namespace std;

int main(){

	//Ustawie stalych
	const int PACK_SIZE = 2048;
	const int MAX_INT_LENGTH = 11;
	char nazwa[1024];

	//Wywołanie funkcji do zainicjowania biblioteki Winsock'a
	WSADATA winsockData;
	int errorFlag = WSAStartup(MAKEWORD(2, 2), &winsockData);

	if (errorFlag != 0)
		cout << "Blad podczas inicjacji Winsock ..." << endl;

	//Wywolanie funcji do tworzenia socketa
	SOCKET servSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (servSocket == INVALID_SOCKET)
		cout << "Blad podczas tworzenia Socketa" << endl;

	sockaddr_in servAddr;

	//Ustawienie adresu serwera
	servAddr.sin_family = AF_INET;
	servAddr.sin_port = htons(6091);
	servAddr.sin_addr.s_addr = INADDR_ANY;
	memset(servAddr.sin_zero, 0, sizeof(servAddr.sin_zero));

	//Wywolanie metody do przypisania odpowiedniego portu
	int errorBind = bind(servSocket, (sockaddr*)&servAddr, sizeof(servAddr));
	//sprawdzanie bledu
	if (errorBind == SOCKET_ERROR)
		cout << "Blad podczas przypisywania portu" << endl;

	//Wywołanie metody nasluchiwania polaczenia
	int errorListen = listen(servSocket, SOMAXCONN);
	//sprawdzenie bledu
	if (errorListen == SOCKET_ERROR)
		cout << "Blad podczas nasluchiwania" << endl;

	cout << "Czekam na polaczenie... " << "ADRES: " << inet_ntoa(servAddr.sin_addr) 
		 << " PORT:" << ntohs(servAddr.sin_port) << endl;

	//Deklaracja struktury do pozniejszego uzywania select
	fd_set mainSet;
	FD_ZERO(&mainSet);

	//Dodanie listen do tab gniaz
	FD_SET(servSocket, &mainSet);

	//Utworzenie map
	map<SOCKET, FILE*> connectionFiles;
	map<SOCKET, bool> connectionsSuccess;
	map<SOCKET, int> size;

	//Utworzenie petli by program ciagle odbieral dane
	while (1) 
	{
		//Tworzenie kopii
		fd_set copySet = mainSet;

		//Wywolanie select
		int socketCount = select(NULL, &copySet, NULL, NULL, NULL);

		//Petla do obslugi tablicy gniazd
		for (int i = 0; i < socketCount; i++) 
		{
			//Tablica gniazd
			SOCKET currSocket = copySet.fd_array[i];
			
			if (currSocket == servSocket) 
			{
				//Deklaracja nowej struktury dla klienta
				sockaddr_in clientInfo;
				int clientInfoSize = sizeof(clientInfo);
				
				//Akceptacja nowego polaczenia dla klienta
				SOCKET newClient = accept(servSocket, (sockaddr*)&clientInfo, &clientInfoSize);
				FD_SET(newClient, &mainSet);

				//mapowanie połaczenia z klientem
				pair<SOCKET, bool> pol(newClient, false);
				connectionsSuccess.insert(pol);
			}
			else
			{
				if(connectionsSuccess.find(currSocket)->second == false)
				{
					//Deklaracja buffora
					ZeroMemory(nazwa,1024);
					int dane = recv(currSocket, nazwa,1024,0);
					
						if(dane > 0)
						{
							FILE* clientFile = fopen(nazwa, "r");

							if(clientFile == NULL)
							{
								send(currSocket, "0", 2, 0);
								cout << "Podany plik nie istnieje" << endl;
								cout << "Nazwa szukanego pliku: " << nazwa << endl;
							}
							else
							{
								send(currSocket, "1", 2, 0);
								cout << "Podany plik istnieje" << endl;

								//Dodanie nowego gniazda i pliku do mapy
								pair<SOCKET, FILE*> filePair(currSocket, clientFile);
								connectionFiles.insert(filePair);
								connectionsSuccess.find(currSocket)->second = true;
								
								//rozmiar pliku
								fseek(clientFile, 0, SEEK_END);
								int Size = ftell(clientFile);
								fseek(clientFile, 0, SEEK_SET);
								char cSize[MAX_PATH];
								ZeroMemory(cSize, MAX_PATH);
								sprintf(cSize, "%i", Size);

								//wysyla rozmiar
								send(currSocket, cSize, MAX_PATH, 0);

								//mapuje rozmiar z socketem
								pair<SOCKET, int> fileSize(currSocket, Size);
								size.insert(fileSize);	
							}
						}
						else
						{
							cout << "Klient zerwal polaczenie" << endl;
							closesocket(currSocket);
							FD_CLR(currSocket, &mainSet);
						}
				}
				else
				{
					//zawartość pliku
					char *Buffer = new char[size.find(currSocket)->second];
					ZeroMemory(Buffer, size.find(currSocket)->second);
					fread(Buffer, size.find(currSocket)->second, 1, connectionFiles.find(currSocket)->second);
					char *data = Buffer;
					int len = size.find(currSocket)->second;  

					//zamyka plik dla danego socketa
					fclose(connectionFiles.find(currSocket)->second);
					size.erase(currSocket);

					while (len > 0) {
					int amount = send(currSocket, data, len, 0);
					if (amount == SOCKET_ERROR) {
						cout << "Blad wysylki" << endl;
						} 
					else 
						{
							len -= amount;
							data += amount;
						}
					}
					
					connectionsSuccess.find(currSocket)->second = false;

					//usuwanie z mapy pliku
					connectionFiles.erase(currSocket);
				}
			}
		}
	}
	return 0;
}
3

Sprawdź errno to będziesz wiedział co jest powodem błędu https://www.tutorialspoint.com/cprogramming/c_error_handling.htm

0

Value of errno: 22
Error printed by perror: Invalid argument
Error opening file: Invalid argument

1

EINVAL przy fopen zazwyczaj oznacza, że został użyty nieprawidłowy string dla trybu. Ty użyłeś r który jest prawidłowy. Errno sprawdziłeś przed czy po wywołaniem funkcji send w tym ifie?

if(clientFile == NULL)
{
  send(currSocket, "0", 2, 0);
  cout << "Podany plik nie istnieje" << endl;
  cout << "Nazwa szukanego pliku: " << nazwa << endl;
}

Jeżeli send się nie udał to mógł przykryć Ci kod błędu z fopen.

0

W załączniku przesyłam screen błędów, nic się nie różnią- oba mają kod 22.
Po wpisaniu na sztywno nazwy działa poprawnie. Tylko otrzymana nazwa od klienta mu się nie podoba. Wyświetlam nazwę i nie ma żadnego niechcianego syfu z pamięci. Moim zdaniem tutaj siedzi diabeł. Tylko nie mam pojęcia jak go rozwiązać.

//Deklaracja buffora
ZeroMemory(nazwa, MAX_PATH);
int dane = recv(currSocket, nazwa, MAX_PATH, 0); //odebrana nazwa mu się nie podoba 
					
if(dane > 0)
{	
       FILE* clientFile = fopen(nazwa, "r");
}


1

Niektóre "krzaczki" mogą nie być wyświetlane w konsoli. Moja rada to spróbuj na maksymalnie uproszczonym serwerze, gotowca możesz wziąć stąd https://asawicki.info/Mirror/Beej_s%20Guide%20to%20Network%20Programming%20PL/bgnet.pdf sekcja "Prosty strumieniowy serwer".

0

Prawdopodobnie problemem są nadmiarowe "krzaki". Chcę zrobić tak, że "rozcina" mi nazwę pliku na pozycji -1 zależny od rozmiaru odebranego przez recv. Czy to jest dobry tok myślenia?

2

Skopiuj po prostu odebraną nazwę do osobnego bufora, który będzie miał rozmiar dane + 1 ('\0' na końcu) i do fopen przekaż ten tymczasowy bufor.

0

Dzięki za pomoc. Problem rozwiązany :)

0

Serwer odbierał niechciane znaki. Nie były one widoczne w oknie konsoli. Pomogło skopiowanie odebranego rozmiaru do zmiennej tymczasowej.

char *tmp = new char[dane - 1];
ZeroMemory(tmp, dane);
for(int i = 0; i < dane - 1; i++)
	tmp[i] = nazwa[i];
tmp[dane - 2] = '\0';

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