Avatar billede tetrix Nybegynder
30. marts 2010 - 21:48 Der er 58 kommentarer og
1 løsning

Fildeling -> VB.NET Client og Java Server

Hej eksperter.

Sagen er den, at jeg har lavet en chat server i Java, men selve klienterne til chatten er skrevet i VB.NET. Jeg vil nu prøve at implementere fildeling, så brugerne kan udveksle screenshots/billeder. Men det virker næsten umuligt at finde eksempler på VB.net client -> Java server -> VB.net client fildeling.

Søger råd til om det overhovedet er muligt, hvad jeg skal gøre osv - og meget gerne eksempler.

-tetrix
Avatar billede arne_v Ekspert
30. marts 2010 - 21:59 #1
Selvfoelgeligt er det muligt.
Avatar billede arne_v Ekspert
30. marts 2010 - 22:01 #2
Grundliggende er en fil overfoersel bare overfoersel af et stort antal bytes.
Avatar billede arne_v Ekspert
30. marts 2010 - 22:02 #3
Bruger du en binaer eller en tekst protokol?
Avatar billede tetrix Nybegynder
30. marts 2010 - 22:08 #4
Jeg vil tro svaret er tekstprotokol, da jeg bruger for eksempel bruger printstream.println(string); printstream.flush(); i min Java server. Har aldrig haft den helt store forstand på bytes.
Avatar billede arne_v Ekspert
30. marts 2010 - 22:14 #5
Jep - det lyder som tekst.
Avatar billede arne_v Ekspert
30. marts 2010 - 22:17 #6
Jeg vil tro at det nemmeste vil vaere at:

client1->server: FILE foobar.jpg
server->client2: FILE foobar.jpg
client1 aabner ny socket forbindelse til server
client2 aabner ny socket forbindelse til server
client 1 laeser fra fil og skriver til den nye socket
server laeser fra client1 socket og skriver til client2 socket
client2 laeser fra socket og skriver til fil
Avatar billede tetrix Nybegynder
30. marts 2010 - 22:31 #7
Altså nogenlunde client1 -> server -> client2, eller har jeg læst forkert?
Avatar billede arne_v Ekspert
30. marts 2010 - 22:37 #8
Det er slut effekten.

Men overnstaaende skulle saa ogsaa illustrere lidt hvordan man kommer dertil.
Avatar billede tetrix Nybegynder
30. marts 2010 - 22:50 #9
Men eftersom jeg bruger tekst protokol, skal jeg så konvertere bytesne fra billedet til et string og sende det fra client1, hvorefter client2 laver det om til bytes igen og smider det ind i en fil? Eller er jeg nødt til at bruge en binær protokol?
Avatar billede arne_v Ekspert
30. marts 2010 - 23:11 #10
Nej - mit forslag er at koere rent binaert paa den anden socket.
Avatar billede tetrix Nybegynder
02. april 2010 - 23:52 #11
Kan du give/linke nogle eksempler? Har desværre ikke den store kendskab til at køre med andre protokoller end tekst..
Avatar billede arne_v Ekspert
03. april 2010 - 01:52 #12
Da ideen er at bruge en ny connection for hver overførsel er protokollen meget simpel.

det der sends = bytes i fil

Men jeg kan nok finde nogle eksempler.
Avatar billede arne_v Ekspert
03. april 2010 - 01:55 #13
Java server:

import java.io.*;
import java.net.*;

public class Server {
  public static void main(String[] args) throws Exception {
      ServerSocket ss = new ServerSocket(9999);
      Socket s = ss.accept();
      InputStream is = s.getInputStream();
      OutputStream os = new FileOutputStream("C:\\z2.zip");
      byte[] b = new byte[10000];
      int n;
      while((n = is.read(b)) >= 0) {
        os.write(b, 0, n);
      }
      os.close();
      is.close();
  }
}
Avatar billede arne_v Ekspert
03. april 2010 - 01:58 #14
VB.NET client:

Imports System
Imports System.IO
Imports System.Net
Imports System.Net.Sockets

Public Class Client
    Public Shared Sub Main(args As String())
        Dim cli As New TcpClient("localhost", 1234)
        Dim nstm As Stream = cli.GetStream()
        Dim fstm As Stream = New FileStream("C:\z.1", FileMode.Open, FileAccess.Read)
        Dim b As Byte() = New Byte(9999) {}
        Dim n As Integer
        While (n = fstm.Read(b, 0, b.Length)) > 0
            nstm.Write(b, 0, n)
        End While
        nstm.Close()
        fstm.Close()
        cli.Close()
    End Sub
End Class
Avatar billede arne_v Ekspert
03. april 2010 - 02:00 #15
Har du iøvrigt læst:

http://www.eksperten.dk/guide/515

?
Avatar billede tetrix Nybegynder
03. april 2010 - 23:32 #16
Tak for svarene. Så du mener altså at jeg skal åbne en ny forbindelse for hver fildeling der kører binært, men samtidig holde min tekstprotokol åben?

Har desuden læst noget om peer to peer teknologi. Vil det være muligt at åbne en kortvarig 'server' på min modtagende klient? Altså ligesom MSN gør, når der sendes billeder frem og tilbage.
Avatar billede arne_v Ekspert
03. april 2010 - 23:45 #17
Ja. Det vil være det nemmeste.

Det er iøvrigt den måde som FTP virker på.
Avatar billede arne_v Ekspert
03. april 2010 - 23:46 #18
Hvis server siden har en firewall vil TCP ikke kunne bruges. Der er visse muligheder med UDP.
Avatar billede tetrix Nybegynder
04. april 2010 - 00:21 #19
Det vil ikke være noget problem. Hvor kan jeg læse/se eksempler på hvordan det ville fungere i VB.NET? Og når man deler filer over MSN og scanner sine packets, kan man se at modparten og en selv bruger en tilfældig port, hvad er det for noget?
Avatar billede arne_v Ekspert
04. april 2010 - 00:58 #20
TCP eller UDP ?
Avatar billede tetrix Nybegynder
04. april 2010 - 01:02 #21
Helst TCP, hvis det altså er muligt.
Avatar billede arne_v Ekspert
04. april 2010 - 02:35 #22
Så skal den ene bruger lytte på en port med TcpListener og den anden connecte til den port med TcpClient.
Avatar billede tetrix Nybegynder
04. april 2010 - 16:02 #23
Hmm, vil det så sige at serversiden skal åbne den port i deres NAT? Det jeg tænkte på var, at den automatisk fandt en åben port. Da jeg kørte en CSS server, kunne jeg ikke få åbnet den port jeg ville have åbnet, 27015, men i stedet endte porten med at være 64117, et højt og tilfældigt tal.. Er det kun muligt med UDP?
Avatar billede arne_v Ekspert
04. april 2010 - 16:07 #24
Ja.

Tror jeg.
Avatar billede tetrix Nybegynder
04. april 2010 - 16:15 #25
Hvad så hvis jeg gør følgende:

1. Åbner en ny forbindelse på en ny port.
2. Ber begge parter om at connecte.
3. Får senderen til at sende det der skal sendes og omdirigerer alt data til modtageren.

- og kører alt binært, vil det så virke? :S
Avatar billede arne_v Ekspert
04. april 2010 - 16:48 #26
Ja.

Det er modellen jeg beskriver tilbage i #6.
Avatar billede tetrix Nybegynder
04. april 2010 - 18:08 #27
Okay, vil forsøge at lave det senere. Tak for alle svarene.
Avatar billede arne_v Ekspert
04. april 2010 - 19:25 #28
så vil jeg smide et rigtigt svar
Avatar billede tetrix Nybegynder
04. april 2010 - 21:59 #29
Som en forhåbentlig afslutning på det hele:
Jeg har forsøgt at lave det uden om Java serveren, altså simpelthen bare fra VB.NET -> VB.NET.

Det eneste problem jeg har er at den modtagne fil fylder 8 KB mens den sendte fil fylder 27 KB. Jeg går ud fra at det skyldes, at jeg mangler et loop ved min modtagelse.

Dim c As TcpClient = server.AcceptTcpClient
Dim s As NetworkStream = c.GetStream

Dim inStream(c.ReceiveBufferSize) As Byte
s.Read(inStream, 0, c.ReceiveBufferSize)
FilePut(1, inStream)

FileClose(1)

Dog giver et loop som "While NetWorkStream.CanRead" en fil der bliver ved med at vokse og dermed aldrig slutter. Hvilket loop skal jeg placere der for at få netop den fil jeg forsøger at modtage?

-tetrix
Avatar billede arne_v Ekspert
04. april 2010 - 22:13 #30
Den her konstruktion er meget normal:

        n = instm.Read(b, 0, b.Length)
        While n > 0
            oustm.Write(b, 0, n)
            n = instm.Read(b, 0, b.Length)
        End While
Avatar billede tetrix Nybegynder
04. april 2010 - 22:31 #31
Nu ender jeg med en absolut tom fil på 0 bytes.

Min modtager:
                Dim c As TcpClient = server.AcceptTcpClient
                Dim s As NetworkStream = c.GetStream
                FileOpen(1, filePath, OpenMode.Binary)
                Dim b As Byte() = New Byte(9999) {}
                Dim n As Integer
                n = s.Read(b, 0, b.Length)
                While n > 0
                    n = s.Read(b, 0, b.Length)
                    FilePut(1, b)
                End While

Min sender:
            Dim cli As New TcpClient("localhost", 1300)
            Dim nstm As Stream = cli.GetStream()
            Dim fstm As Stream = New FileStream(filePath, FileMode.Open, FileAccess.Read)
            Dim b As Byte() = New Byte(9999) {}
            Dim n As Integer
            While (n = fstm.Read(b, 0, b.Length)) > 0
                nstm.Write(b, 0, n)
            End While

Hvor ligger fejlen? Som sagt har jeg ikke den store forstand på binært. Jeg beklager alle disse spørgsmål. Hvis du ønsker det kan jeg tildele flere point for al din hjælp.
Avatar billede arne_v Ekspert
04. april 2010 - 22:39 #32
Prøv og udskriv n inde i de to løkker for at se i hvilken ende det går galt.
Avatar billede arne_v Ekspert
04. april 2010 - 22:39 #33
Den sidste while løkke gør det samme som den første bare lidt smartere men kræver også en nyere VB.NET version.
Avatar billede tetrix Nybegynder
04. april 2010 - 22:44 #34
Har forsøgt at udskrive i begge løkker, men ingen af dem udskriver noget overhovedet. De bliver åbenbart aldrig taget i brug. Hvad vil det sige?
Avatar billede arne_v Ekspert
04. april 2010 - 22:48 #35
Kommer du overhovedet ind i den kode?

På server siden skal du nok starte en ny tråd til det.
Avatar billede tetrix Nybegynder
04. april 2010 - 22:54 #36
Ja, både serversiden og klienten kommer til det stykke kode.
Der opstår ingen exceptions under forløbet.
Både klienten og serveren starter en ny tråd til forbindelserne, så det ikke påvirker mit UI.
Avatar billede arne_v Ekspert
04. april 2010 - 22:59 #37
Prøv og lad sender lave noget Flush.
Avatar billede arne_v Ekspert
04. april 2010 - 23:00 #38
Og prøv og lad sender udskrive

(New FileInfo(filePath)).Length
Avatar billede tetrix Nybegynder
04. april 2010 - 23:10 #39
Sender udskriver:
30423

Fandt dette stykke kode:
    Public Sub TransferData(ByVal FromStream As IO.Stream, ByVal ToStream As IO.Stream, ByVal BufferSize As Integer)
        Dim buffer(BufferSize - 1) As Byte
        Do While True
            Dim bytesRead As Integer = FromStream.Read(buffer, 0, buffer.Length)
            If bytesRead = 0 Then Exit Do
            ToStream.Write(buffer, 0, bytesRead)
            ToStream.Flush()
        Loop
    End Sub

Får dog fejl når jeg bruger det, eftersom serveren åbenbart ikke vil modtage noget, og den hopper direkte til server.close().
Avatar billede tetrix Nybegynder
04. april 2010 - 23:12 #40
Problem løst, brugte det samme stykke kode ved min modtager:
                Dim c As TcpClient = server.AcceptTcpClient
                Dim s As NetworkStream = c.GetStream
                FileOpen(1, filePath, OpenMode.Binary)
                Dim buffer(1024 - 1) As Byte
                Do While True
                    Dim bytesRead As Integer = s.Read(buffer, 0, buffer.Length)
                    If bytesRead = 0 Then Exit Do
                    FilePut(1, buffer)
                Loop
                FileClose(1)

Forstår dog stadig ikke hvorfor dit eksempel ikke virkede, det er nogenlunde det samme.
Avatar billede arne_v Ekspert
05. april 2010 - 00:32 #41
Ups.

              While n > 0
                    n = s.Read(b, 0, b.Length)
                    FilePut(1, b)
                End While

skal være

              While n > 0
                    FilePut(1, b)
                    n = s.Read(b, 0, b.Length)
                End While

ellers mister den første læsning (og det er eneste data ved en lille fil !)
Avatar billede arne_v Ekspert
05. april 2010 - 00:33 #42
n = s.Read(b, 0, b.Length)
            While n > 0
                    FilePut(1, b)
                    n = s.Read(b, 0, b.Length)
            End While

kan jo så også laves som:
           
            While (n = s.Read(b, 0, b.Length)n > 0
                    FilePut(1, b)
            End While

i en nyere VB.NET
Avatar billede arne_v Ekspert
05. april 2010 - 00:34 #43
Og så ville jeg altid bruger .NET FileStream og ikke de der VB'istiske FileOpen og FilePut !
Avatar billede tetrix Nybegynder
05. april 2010 - 01:18 #44
Okay. Jeg tester i øjeblikkeligt binær kommunikation fra vb.net -> java.

Jeg sender et string således:
Public Sub sendString(ByVal str As String)
s.Write(Encoding.ASCII.GetBytes(str), 0, Encoding.ASCII.GetBytes(str).Length)
s.Flush()
End Sub

Har læst den guide du linkede til, min java server ser således ud:
dis = new DataInputStream(socket.getInputStream());
dos = new DataOutputStream(socket.getOutputStream());

byte firstPacket = dis.readByte();

For at afkode bytes til strings ville jeg i vb.net bruge Encoding.ASCII.getString(byte), hvad skal jeg i java? Eller skal jeg tage hensyn til det med big og little endian? -tetrix.
Avatar billede tetrix Nybegynder
05. april 2010 - 01:28 #45
Planen var jo at sende data modtaget fra klient1 direkte til klient2, men jeg er nødt til at få information som brugernavn fra klienterne først.
Avatar billede arne_v Ekspert
05. april 2010 - 01:46 #46
Min ide var at sende al meta information: modtager, filnavn, filstørrelse, vindretningen etc. på den permanente tekst socket forbindelse og kun sende filens bytes over den binære engangs socket.

Men hvis du vil mixe, så:

Encoding.UTF8.GetString(ditbytearray)
Encoding.UTF8.GetBytes(dinstring)

svarer til Java:

new String(ditbytearray, "UTF-8")
dinstring.getBytes("UTF-8")
Avatar billede tetrix Nybegynder
05. april 2010 - 01:46 #47
Har fundet en løsning på overstående problem.
            byte[] buffer = new byte[1024];
            boolean r = true;
            while(r){
                int n = dis.read(buffer, 0, buffer.length);
                if(n==0)r=false;
                String str = new String(buffer, "UTF-8");
                if(str.contains("alias,")) logLine(str);
            }


Efter det data jeg skal modtage kommer der dog en masse whitespace, hvad skal jeg gøre for at slippe af med det?
Avatar billede arne_v Ekspert
05. april 2010 - 01:47 #48
Men husk at sender du tekst strenge over en binær forbindelse, så bør du prefixe data bytes med længden f.eks. 2 bytes længde først.

Husk at ved heltal > 1 bytes, så er der noget som hedder big endian og little endian. Java's Data*Stream bruger big endian !
Avatar billede arne_v Ekspert
05. april 2010 - 02:00 #49
byte[] buffer = new byte[1024];
            int n;
            while((n = dis.read(buffer, 0, buffer.length) > 0){
                String str = new String(buffer, 0, n, "UTF-8");
                if(str.contains("alias,")) logLine(str);
            }
Avatar billede tetrix Nybegynder
05. april 2010 - 15:17 #50
Har fået sat forbindelserne sammen, og kører nu rent binært. Det har lykkedes mig at sende dele af et billede i visse tilfælde, men jeg mangler en færdig løsning. Har brugt dit eksempel som Java server, og i mine vb.net klienter de dele jeg brugte til vb.net -> vb.net, som beskrevet i #29.

dis (datainputstream) = sender af filen
dos (dataoutputstream) = modtager af filen

                byte[] buffer = new byte[1024];
                int n;
                while((n = dis.read(buffer, 0, buffer.length)) > 0){
                    dos.write(buffer, 0, n);
                    dos.flush();
                }
Avatar billede tetrix Nybegynder
05. april 2010 - 17:08 #51
OK, fik filen overført.

Problemet er at Java serveren ikke kan se hvornår jeg stopper med at modtage, men det kan senderen til gengæld.

Derfor får modtageren aldrig brugt FileClose(*), før jeg altså lukker programmet.. Mener at jeg har hørt noget om Java og bytes der ikke ville returne e.l. et sted.. Skal jeg igen blande tekst og binær for at få senderen til at fortælle hvornår den er sendt? Tak.
Avatar billede tetrix Nybegynder
05. april 2010 - 20:42 #52
Har fået det til at virke. Det er lidt buggy, men vi får at se om det virker.
Avatar billede arne_v Ekspert
06. april 2010 - 01:09 #53
Hvis du sender over en permanent socket skal du starte med at sende længden således at modtager ved hvornår det hele er ankommet.

Hvis du bruger en ny forbindelse per fil overførsel, så kan du bruge end of file som markering af at filen er slut.
Avatar billede tetrix Nybegynder
06. april 2010 - 14:21 #54
Får begge parter til at connecte til min "binary server". Når begge parter er forbundet, bliver senderen bedt om at sende.

Siden senderen kan se hvornår filen er sendt, lukker den forbindelsen efter det hele er sendt. På den måde kan serveren også følge med.
Ved ikke om det er en helt god metode, men det virker.

Og hvordan kan jeg "markere" længden? Går også ud fra, at det er her delen om big og little endian kommer ind.
Avatar billede tetrix Nybegynder
06. april 2010 - 14:24 #55
Hov, fik vist ikke lige læst dit tidl. svar helt igennem.

Hvordan benytter jeg mig af EOF?
Avatar billede arne_v Ekspert
06. april 2010 - 19:17 #56
EOF = end of file

Hvis den sendende ende lukker forbindelsen, saa vil modtagers read returnere -1 eller 0 (check docs).
Avatar billede arne_v Ekspert
06. april 2010 - 19:18 #57
Alternativet er at sende laengden inden selve data'ene. Med en binaer forbindelse skal man vaere enige om endianess.
Avatar billede tetrix Nybegynder
06. april 2010 - 19:48 #58
#56 lyder nogenlunde som det jeg netop har gjort.

Læg venligst svar:
http://www.eksperten.dk/spm/906377

:-)
Avatar billede arne_v Ekspert
06. april 2010 - 19:56 #59
done
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