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.
- main.rar (2 KB) - ściągnięć: 39
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.
#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, ©Set, 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;
}
std::vector
, tylko bawisz w ręczne zarządzanie pamięcią?
Sprawdź errno to będziesz wiedział co jest powodem błędu https://www.tutorialspoint.com/cprogramming/c_error_handling.htm
perror("Co robiłem")
jest przyjemniejsze.
Value of errno: 22
Error printed by perror: Invalid argument
Error opening file: Invalid argument
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
.
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");
}
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".
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?
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';