Skinney Skrevet 1. november 2009 Del Skrevet 1. november 2009 Hepp! Skjønner ikke helt hvordan jeg skal overføre en .tar fil fra en server til en klient. Dette er det jeg har så langt. Server: import tarfile import os import socket import select #Lager .tar arkiv archive = tarfile.open('./archive.tar', 'w') print "Creating archive" for file in os.listdir('./'): archive.add(file) archive.close() #Instillinger for server-socket HOST = '' # Symbolic name meaning all available interfaces PORT = 50001 # Arbitrary non-privileged port CONNECTION_LIST = [] RECV_BUFFER = 4096 #Starter server-socket s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.bind((HOST, PORT)) s.listen(1) CONNECTION_LIST.append(s) print "Waiting for connection..." while 1: read_socket, test1, test2 = select.select(CONNECTION_LIST, [], [], 0) for socket in read_socket: if socket == s: conn, addr = s.accept() CONNECTION_LIST.append(conn) print "Connected by: (%s, %s) " % addr print "Sending update to client..." conn.send('U') #Send U til klient så den forstår at en fil er på vei archive = open('./archive.tar', 'r') data = archive.read() conn.sendall(data) print "Client updated..." archive.close() else: # Data recieved from client, process it try: #In Windows, sometimes when a TCP program closes abruptly, # a "Connection reset by peer" exception will be thrown data = socket.recv(RECV_BUFFER) except IOError.errno == 35: print "Client (%s, %s) is offline" % addr socket.close() CONNECTION_LIST.remove(socket) break except IOError.errno: pass if data: # The client sends some valid data, process it if data == "q" or data == "Q": print "Client (%s, %s) quits" % addr socket.close() CONNECTION_LIST.remove(socket) else: print data Klient: import tarfile import os import socket import select import string #archive = tarfile.open('./archive.tar', 'w:bz2') #print "Creating archive" #for file in os.listdir('./'): # archive.add(file) #archive.close() HOST = raw_input("Ip adress:") # Symbolic name meaning all available interfaces PORT = 50001 # Arbitrary non-privileged port RECV_BUFFER = 4096 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((HOST, PORT)) s.setblocking(0) data = "" while s: try: #In Windows, sometimes when a TCP program closes abruptly, # a "Connection reset by peer" exception will be thrown data = s.recv(RECV_BUFFER) except IOError.errno == 35: print "Server (%s, %s) is offline" s.close() break except: pass finally: # The client sends some valid data, process it if data == 'U': #Server har sendt U, det betyr at det neste som blir sendt er et .tar arkiv print "Receiving update..." s.setblocking(1) #Blokker andre hendelser til vi har mottatt hele fila archive = open('./archive.tar', 'w') data = s.recv(RECV_BUFFER) archive.write(data) #Lagre fila archive.close() print "Update successfully retrieved!" print "Extracting archive" archive = tarfile.open('./archive.tar', 'w') archive.extractall('./test') #Pakk ut innholdet i fila, for test... archive.close() print "Update successfully applied!" s.setblocking(0) if data != '': print data Når jeg kjører disse vil alt gå greit frem til Klienten mottar U fra server. Etter dette sier den at den har mottatt alt og etter et par sekunder spyr 'print data' setningen ut innholdet av .tar fila jeg prøver å sende... Er 100% fersk i python så er sikkert en del feil jeg har gjort her. Noen som vet hvordan jeg får sendt en .tar fil til en annen klient ved hjelp av socket? Lenke til kommentar
jonnor Skrevet 3. november 2009 Del Skrevet 3. november 2009 Er 100% fersk i python så er sikkert en del feil jeg har gjort her. Noen som vet hvordan jeg får sendt en .tar fil til en annen klient ved hjelp av socket? Ikke skriv din egen overføringspotokoll, og hvis du absolutt må gjøre det, ikke jobb med sockets direkte. Dette er ting 100 prosjekter har gjort før deg, bruk en av de, ikke finn opp hjulet på nytt. Lenke til kommentar
footnote Skrevet 4. november 2009 Del Skrevet 4. november 2009 Det er lærerikt å jobbe direkte med sockets, og dersom det er det som er meningen her så er vel dette en fin ting å prøve seg på. Håper ikke dette er ditt første forsøk, siden du bruker select. Du gjør flere feil her, og vi kan begynne med de enkleste. Du leser ikke all data som sendes fra tjeneren. Når du bruker socket.recv(BUFFER_SIZE), så leses maksimalt BUFFER_SIZE antall bytes fra socket. Her må du sjekke mengden data lest, og lese flere ganger fra socket for å lese all data. Det du gjør her er å bare lese de første 4096 bytene med data og bygger en tar fil fra disse. Jeg klarte ikke lage en .tar fil i linux som var mindre en 10K... Når du først sender en 'U' og deretter sender resten av dataene, er det helt tilfeldig, eller iallefall forskjellig fra os til os om dataene blir bufret opp og sendes i en melding eller ikke. Derfor kan du ikke på klientsiden stole på at i det første recv() kallet bare kommer en 'U' og deretter kan kalle recv() igjen for resten. Ofte kommer U'en med den første delen av dataene du skal sende. Du har satt timeout til 0 på select funksjonskallet. I linux resulterer det i at timeout er 0 sekunder og løkken i tjeneren kjøres hele tiden selv om det ikke er data og lese på noen sockets, det er litt mot hensikt til select. select blokker helt til det skjer noe på noen av de IO kildene du har registrert i kallet. Enten fjern det siste parameteret (ingen timeout), eller sett det til et høyere tall (f.eks. ett par sekunder) Du oppdager ikke hos tjeneren når klienten er ferdig å lese og lukker forbindelsen. Når klienten er ferdig havner dens socket i read_socket hos tjeneren. Så vidt jeg husker kan du sjekke her om du mottar en tom melding fra klienten som indikerer at den lukker forbindelsen. Da fjerner du klientens socket fra CONNECTION_LIST, ellers vil tjeneren stå å spinne i løkka igjen, da den ikke har fått gjort seg ferdig med socketen. Prøv å skriv ut dataene du mottar (siden de allikevel er tekstbaserte) og lengden på dataene du har lest, da ser du om du har mottat mindre en total størrelse på filen, og evt om du har mottatt mindre en bufferet (RECV_BUFFER). Du må også lagre dataene i et buffer, slik at du sitter igjen med all dataene i ett buffer til slutt. BUFFER = BUFFER + data i hver runde av løkka skulle være en begynnelse. Prøv å teste deler av programmet av gangen. Et godt tips er å bruke time.sleep() på strategiske punkter, for å forsinke programmet. Evt stoppe for å lese input fra tastaturet. Lenke til kommentar
Skinney Skrevet 4. november 2009 Forfatter Del Skrevet 4. november 2009 Det er lærerikt å jobbe direkte med sockets, og dersom det er det som er meningen her så er vel dette en fin ting å prøve seg på. Håper ikke dette er ditt første forsøk, siden du bruker select. Du gjør flere feil her, og vi kan begynne med de enkleste. Du leser ikke all data som sendes fra tjeneren. Når du bruker socket.recv(BUFFER_SIZE), så leses maksimalt BUFFER_SIZE antall bytes fra socket. Her må du sjekke mengden data lest, og lese flere ganger fra socket for å lese all data. Det du gjør her er å bare lese de første 4096 bytene med data og bygger en tar fil fra disse. Jeg klarte ikke lage en .tar fil i linux som var mindre en 10K... Når du først sender en 'U' og deretter sender resten av dataene, er det helt tilfeldig, eller iallefall forskjellig fra os til os om dataene blir bufret opp og sendes i en melding eller ikke. Derfor kan du ikke på klientsiden stole på at i det første recv() kallet bare kommer en 'U' og deretter kan kalle recv() igjen for resten. Ofte kommer U'en med den første delen av dataene du skal sende. Du har satt timeout til 0 på select funksjonskallet. I linux resulterer det i at timeout er 0 sekunder og løkken i tjeneren kjøres hele tiden selv om det ikke er data og lese på noen sockets, det er litt mot hensikt til select. select blokker helt til det skjer noe på noen av de IO kildene du har registrert i kallet. Enten fjern det siste parameteret (ingen timeout), eller sett det til et høyere tall (f.eks. ett par sekunder) Du oppdager ikke hos tjeneren når klienten er ferdig å lese og lukker forbindelsen. Når klienten er ferdig havner dens socket i read_socket hos tjeneren. Så vidt jeg husker kan du sjekke her om du mottar en tom melding fra klienten som indikerer at den lukker forbindelsen. Da fjerner du klientens socket fra CONNECTION_LIST, ellers vil tjeneren stå å spinne i løkka igjen, da den ikke har fått gjort seg ferdig med socketen. Prøv å skriv ut dataene du mottar (siden de allikevel er tekstbaserte) og lengden på dataene du har lest, da ser du om du har mottat mindre en total størrelse på filen, og evt om du har mottatt mindre en bufferet (RECV_BUFFER). Du må også lagre dataene i et buffer, slik at du sitter igjen med all dataene i ett buffer til slutt. BUFFER = BUFFER + data i hver runde av løkka skulle være en begynnelse. Prøv å teste deler av programmet av gangen. Et godt tips er å bruke time.sleep() på strategiske punkter, for å forsinke programmet. Evt stoppe for å lese input fra tastaturet. Takk for fyldig og god tilbakemelding. Er vanskelig å finne svar om dette på internett Har også oppdaget asyncore og asynchat nå også, og ved å studere disse to har jeg kommet frem til andre metoder å bruke (Som f.eks. terminator). Takk igjen, nå har jeg noe å leke med Lenke til kommentar
Anbefalte innlegg
Opprett en konto eller logg inn for å kommentere
Du må være et medlem for å kunne skrive en kommentar
Opprett konto
Det er enkelt å melde seg inn for å starte en ny konto!
Start en kontoLogg inn
Har du allerede en konto? Logg inn her.
Logg inn nå