Avatar billede zyke Nybegynder
12. maj 2002 - 10:17 Der er 21 kommentarer

Socket API

Vi har forsøgt og lave et klient/server ftp agtigt program. Problemet er når vi sender filer, så hvis det er et billed, så kommer der små prikker på billedet. Vi gør det at vi hakker filen op i 127 bytes pakker og sender en pakke ad gangen (vi bruger TCP). Er det en forkert måde at gøre det på? skulle vi istedet have brugt TransmitFile() funktionen?? Nogle bud?
Avatar billede laffe Nybegynder
12. maj 2002 - 10:21 #1
I princippet burde det i gør virke. Jeg tror, at i ikke få sat filen rigtig sammen igen. I har måske en fejl i en aller anden løkke, eller et sted, hvor i kopierer pakker over i resultat filen.
Avatar billede laffe Nybegynder
12. maj 2002 - 10:22 #2
Er det VC++ eller CBuilder i bruger ?
Avatar billede zyke Nybegynder
12. maj 2002 - 10:46 #3
Vi bruger VC++ 6.0 ... vi mener også det burde virke. Vi ved at når vi brækker filen op i 127 bytes bider på klient siden,så går det godt. Det er når vi sender pakkerne og samler dem igen det går galt. Der kommer en periodisk fejl i billedet (ligner en 1 bit fejl pr. pakke). Du kender ikke noget til den der transmitfile?
Avatar billede laffe Nybegynder
12. maj 2002 - 10:54 #4
Hvorfor bruger i ikke Transmitfile ? Virker det ikke eller har i ikke prøvet den endnu ?

Jeg har slået funktionen op på msdn. Den er beregnet til at sende filer.

Men den måde i gør det på, skal også virke.
Avatar billede laffe Nybegynder
12. maj 2002 - 10:55 #5
Må jeg se den kode, hvor i modtager data via socket ?
Avatar billede zyke Nybegynder
12. maj 2002 - 12:51 #6
Vi har ikke prøvet transmitfile endnu, da vi er igang med rapport skrivning. Her har du vores server kode

/* filnavn = server.cpp
  Denne kode repræsentere server siden af vores client/server applikation.
  Udviklet af Troels Aaberg Sørensen, Michael Nielsen og Henry Pedersen
*/

#include "server.h"

/*-----------------------------------------------------------------*/
//Implementering af SocketHjaelper metoderne.
/*-----------------------------------------------------------------*/

//Initalisere Winsock API'en, en socket, og sætter socketen op på en bestemt
//IP adresse og portnummer.
void SocketHjaelper::init(WSADATA &wsaData, SOCKET &sockeT, SOCKADDR_IN &sockAddr)
{
    //Requester WinSockAPI ver. 1.1.
    if(WSAStartup(MAKEWORD(1,1), &wsaData) != 0)
    {
        cout << "FEJL!: WinSockAPI ikke Initaliseret" << endl;
        exit(0);
    }

    //Initalisere socketen:
    sockeT = socket(AF_INET, SOCK_STREAM, 0);
    //AF_INET: Brug af IP protokollen. SOCK_STREAM = Brug af TCP protokollen.
    if(sockeT == INVALID_SOCKET)
    {
        cout << "FEJL!: Socket IKKE initaliseret." << endl;
        exit(0);
    }

    //Opsætning af en port:
    sockAddr.sin_port = 1060;

    //Opsætning af Internet type forbindelse (TCP/IP):
    sockAddr.sin_family = AF_INET;

    //Sætter serveren op på IP adressen: 10.20.10.198:
    sockAddr.sin_addr.S_un.S_un_b.s_b1 = 10;
    sockAddr.sin_addr.S_un.S_un_b.s_b2 = 20;
    sockAddr.sin_addr.S_un.S_un_b.s_b3 = 10;
    sockAddr.sin_addr.S_un.S_un_b.s_b4 = 198;
}

void SocketHjaelper::bindOgListen(SOCKET &Socket, SOCKADDR_IN &SockAddr)
{
    //Binder socketen til en specifik IP adresse:
    if(bind(Socket, (SOCKADDR *)(&SockAddr), sizeof(SockAddr)) == SOCKET_ERROR)
    {
        cout << "FEJL!: Fejl under binding." << endl;
        closesocket(Socket);
        exit(0);
    }

    //Lytter efter indkommende forbindelser, vi tillader kune en client forbindelse:
    listen(Socket, 1);

    //Venter på en inkommende forbindelse i en uendelig løkke, end til der kommer en
    //client forbindelse:
    SOCKET TempSock = SOCKET_ERROR;
    while(TempSock == SOCKET_ERROR)
    {
        TempSock = accept(Socket, NULL, NULL);
    }
    Socket = TempSock;
}

//Modtager noget data over socketen (/netværks forbindelsen):
int SocketHjaelper::modtag(SOCKET &Socket, char data[], int antal, ofstream *ud)
{
    int RetVal = SOCKET_ERROR;

    do
    {
        RetVal = recv(Socket, data, antal, 0);
    }
    while(RetVal==SOCKET_ERROR);
   
    //Tester for fejl ved forbindelsen:
    if((RetVal == 0)||(RetVal == WSAECONNRESET)||(RetVal == WSAECONNABORTED))
    {
        cout << "Forbindelsen blev lukket fra client siden." << endl;
        ud->close();
        closesocket(Socket);
        exit(0);
    }

    return RetVal;
}

/*-----------------------------------------------------------------*/
//Implementering af FilHjaelper metoderne.
/*-----------------------------------------------------------------*/

//Åbner en fil, og initaliserer fildescripteren som holder styr på hvor i filen der skrives:
ofstream* FilHjaelper::aaben(ofstream *ud, char fil[], SOCKET sockeT)
{
    ud = new ofstream(fil, ios::binary);
    if(!ud)
    {
        cout << "FEJL!: Kan ikke skrive til fil." << endl;
        ud->close();
        closesocket(sockeT);
        exit(0);
    }

    return ud;
}

//Skriver til filen.s
ofstream* FilHjaelper::print(int taeller, char Buffer[], ofstream *ud)
{
    for(int j=0; j<=taeller; j++)
    {
        ud->write(&Buffer[j],1);
    }

    return ud;
}

/*-----------------------------------------------------------------*/
//Server programmet:
/*-----------------------------------------------------------------*/
int main()
{
    //Erklærer nogle socket variabler:
    WSADATA wsaData;
    SOCKET sockeT;
    SOCKADDR_IN sockAddr;
    SocketHjaelper forbindelsen;

    //Erklærer nogle fil variabler:
    ofstream *ud = 0;
    char filnavn[] = "ud.bmp"; //Filnavnet på ud filen.
    char Buffer[bufSize]; //Bruges til indlæsning af fil til RAM.
    int taeller = 0; //antal af data blokke. Bruges til at indexere med i Buffer.
    FilHjaelper fil;
   
    //Sætter serveren op på adresse 10.20.10.198 port 1060
    forbindelsen.init(wsaData, sockeT, sockAddr);
    forbindelsen.bindOgListen(sockeT, sockAddr);

    //Åbner ud-filen:
    ud = fil.aaben(ud, filnavn, sockeT);


    do
    {
        //Modtager et array af chars, taeller sættes lig med antallet af modtaget data:
        taeller = forbindelsen.modtag(sockeT, Buffer, bufSize, ud);

        //Skriver modtaget data til fil:
        ud = fil.print(taeller, Buffer, ud);
    }while(sockeT);//så længe clienten ikke lukker for forbindelsen (socketen).

    ud->close(); //lukker for filstreamen.
    closesocket(sockeT); //lukker socketen ned.

    return 0;
}

//server.h

#include <iostream>
using std::cout;
using std::cin;
using std::ios;
using std::cerr;
using std::endl;

#include <fstream>
using std::ofstream;
using std::ifstream;

#include <winsock.h> //Bruges til Socket programmering i Windows

const int bufSize = 128;//Størelsen på datapakerne.

//Bruges til håndtering af socket forbindelsen:
class SocketHjaelper
{
    public:
        void init(WSADATA &wsaData, SOCKET &socket, SOCKADDR_IN &SockAddr);
        void bindOgListen(SOCKET &Socket, SOCKADDR_IN &SockAddr);
        int modtag(SOCKET &Socket, char data[], int antal, ofstream*);
};

//Bruges til håndtering af filer.
class FilHjaelper
{
    public:
        ofstream* aaben(ofstream*, char[], SOCKET sockeT);
        ofstream* print(int taeller, char Buffer[], ofstream*);
};
Avatar billede laffe Nybegynder
12. maj 2002 - 13:42 #7
Jeg kan ikke lige umiddelbart se noget der er forkert.

Det jeg ville prøve er at udskrive det antal byte's i modtager, for hver blok i læser over socket, for at se om i også modtager det antal pakker som i mener der burde komme. Det kunne jo være, at der har snydt sig en "skrammel pakke" imellem.

I jeres motdag metode checker i for recv fejl, men i checker ikke på alle typer fejl, kun om clienten har lukket for forbindelsen, eller om i har modtaget 0 bytes.

Burde Buffer ikke være et array af unsigned char istedet for char.
Avatar billede zyke Nybegynder
12. maj 2002 - 14:26 #8
hvorfor et array af unsigned chars?
Avatar billede laffe Nybegynder
12. maj 2002 - 14:33 #9
char går fra:        -127..127
unsigned char går fra:  0..255
Avatar billede zyke Nybegynder
12. maj 2002 - 15:37 #10
hvad skulle det ændre at bruge unsigned chars istedet?
Avatar billede laffe Nybegynder
12. maj 2002 - 16:01 #11
Jeg tror ikke, at det er problemet, men i sender jo en binær fil. Hver byte kan have en værdi fra 0..255, men i har defineret en buffer, hvor hver entry kan antage en værdi fra 0..127. Så når i sender en byte med værdien 150, så vil der i princippet opstå en fejl i jeres modtage buffer, Dette sker dog ikke, da unsigned char og char har samme størrelse, nemlig 1 byte.

Når man som i har et problem, som ikke lige er til at forklare, så gælder det vel om at udelukke enhver lille detalje - ikke :).
Avatar billede zyke Nybegynder
12. maj 2002 - 16:11 #12
ok, efter rapport skrivning prøver vi lige den der transmitfile(), vi kan ikke finde fejlen med den send() metode
Avatar billede siz23 Nybegynder
12. maj 2002 - 23:40 #13
k, det skal lige siges inden jeg begynder, at jeg kun har kikket på koden et par minuter, så det er langt fra sikkert det er det her, der er problemmet.

du siger at i splitter pakken op i 127 bytes, men når i modtager henter i 129 (0..128)

det her er jeres "hente kode".
-------------------------------------------------------------
do
    {
        //Modtager et array af chars, taeller sættes lig med antallet af modtaget data:
***        taeller = forbindelsen.modtag(sockeT, Buffer, bufSize, ud);

        //Skriver modtaget data til fil:
        ud = fil.print(taeller, Buffer, ud);
    }while(sockeT);//så længe clienten ikke lukker for forbindelsen (socketen).

    ud->close(); //lukker for filstreamen.
-------------------------------------------------------------

den linje med de 3 *** ville jeg nok lige prøve at erstatte bufsize med (bufsize-1, eller er det 2??)

jeg ved ikke om det har noget med det at gøre da jeg ikke kender diffinitionen på "forbindelsen.modtag();"

og fejlen kunne vel også ligge i klient programmet, og ikke i server delen.
Avatar billede laffe Nybegynder
12. maj 2002 - 23:43 #14
Hvor få du 129 fra ?
Avatar billede siz23 Nybegynder
12. maj 2002 - 23:56 #15
const int bufSize = 128;//Størelsen på datapakerne.
char Buffer[bufSize];

buffer=129 bytes.  [0..128]

men jeg har ikke kikket det ordenligt igennem, så jeg er ikke sikker ;)
Avatar billede laffe Nybegynder
13. maj 2002 - 10:45 #16
>siz23. Det passer ikke.

const int bufSize = 128;//Størelsen på datapakerne.
char Buffer[bufSize];

Giver 0..127.
Avatar billede laffe Nybegynder
13. maj 2002 - 10:46 #17
0..127 = 128 entry's
Avatar billede siz23 Nybegynder
13. maj 2002 - 15:55 #18
hvad er der galt med Bufer[128], er der en speciel grund til du ikke vil have den med?
det er jo ikke strenge vi arbejder med har, så du har ikke en "\0" til sidst, derfor kan du bruge alle dem du har alloceret.

btw: hvis det giver 128 entry's, ville det stadig værer 1 for meget, hvis han på klient siden deler dem op i 127, og der ville medfører en pixel fejl vær 128 bytes.
Avatar billede laffe Nybegynder
13. maj 2002 - 16:04 #19
>Siz23. Det vi taler om her, er at når du har et Array, f.eks:

Buffer[10], så siger du at der er 11 entry's i dette array 0..10.

DET PASSER IKKE

Der er kun 10, nemlig fra 0..9.

I C er alle arrays 0 based.
Avatar billede laffe Nybegynder
13. maj 2002 - 16:05 #20
Ja der er en speciel grund til at jeg ikke vil have Buffer[128] med. Den findes nemlig ikke, da den sidste entry i arrayet er Buffer[127] !!!!!
Avatar billede siz23 Nybegynder
13. maj 2002 - 18:46 #21
hehe, jeg nu blev jeg jo lige nødtil at teste det, og desværer havde du ret.

men det ændre ikke på det faktum, at han har en bug der hvor jeg sagde, hvis han splitter sine pakker op i 127 bytes.


og lige en sidste ting, buffer[128], der ligger stacken, så den er der, men du kan ikke skrive i den, hvis jeg husker rigtigt ligger den op [0] i delphi, når men nok om det, du havde ret og det må jeg vel leve med. ;)


you can't win ém all, but you sure can try.
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester