[RESOLVED]Sending Images With Winsock
I am making a multi-user drawing program, when a client connects to the server, the server sends him the current picture as a BMP (I don't need any compression, it's a small image, and it's only downloaded once.) After that, the client sends data to the server telling it where to place a new line. The server then repeats that data to all the other connections.
So the only major problem I have is sending the data via Winsock. I can make multiple connections and such, but I cant send the picture. I've searched the forums here, and I've tried most of the suggestions, I have loaded the picture into a byte array with this code:
VB Code:
Private Function SendPic(Index As Integer)
Dim Size As Long
Dim Filenum As Integer
Dim AByte() As Byte
Dim i As Integer
'save pic
SavePicture picMain.Picture, "C:\SDraw.bmp"
Filenum = FreeFile
Open "C:\SDraw.bmp" For Binary Access Read As Filenum
ReDim AByte(FileLen("C:\SDraw.bmp") - 1)
Get #Filenum, , AByte
Close Filenum
Size = UBound(AByte)
WS(Index).SendData "Image:" & Size & ":" & Str(AByte())
WS(Index).SendData AByte
End Function
But I get all sorts of problems with that code, I don't think its even putting the entire file into the array to begin with. I don't even know how to go about receiving the data correctly. Can someone show me an easy way to transfer a file with Winsock, or a way to get this code working?
Thanks.
Re: Sending Images With Winsock
I know that the most efficient way is to use a Byte Array, but for simplicity (and since the picture is not large), do this:
VB Code:
Private Function SendPic(Index As Integer)
Dim Size As Long
Dim FileNum As Integer
Dim Buffer As String
SavePicture picMain.Picture, "C:\SDraw.bmp"
FileNum = FreeFile
Open "C:\SDraw.bmp" For Binary Access Read As FileNum
Buffer = String(LOF(FileNum), 0)
Get #FileNum, , Buffer
Close FileNum
Size = Len(Buffer)
WS(Index).SendData "Image:" & Size & ":" & Buffer
End Function
If this does not work, then it means that you might also have problems when receiving the data.
Re: Sending Images With Winsock
Thanks, CVMichael. I can now send the image, but only the first ~8 KB arrives, do I have to set up my code to handle data coming in chunks, or what?
Here is the receiving code:
VB Code:
Private Sub WS_DataArrival(Index As Integer, ByVal bytesTotal As Long)
Dim IncomingData As String
Dim BLine As LLine
Dim Splits() As String
Dim Filenum As Integer
'"image":length:data...
WS(Index).GetData IncomingData, vbString
Splits = Split(IncomingData, ":", 3, vbTextCompare)
If Splits(0) = "image" Then
'just... dump it all in a file
Filenum = FreeFile
Open "C:\Draw.bmp" For Binary Lock Write As Filenum
Len(Splits(0)) + Len(Splits(1)) + 2)
' put all data received into file, but make sure its only the stuff after "Image:length:"
Put Filenum, , Mid$(IncomingData, Len(Splits(0)) + Len(Splits(1)) + 3)
Close Filenum
'set pic as picturebox
picMain.Picture = LoadPicture("C:\Draw.bmp")
end if
end function
Re: Sending Images With Winsock
Quote:
Originally Posted by outcast24817
Thanks, CVMichael. I can now send the image, but only the first ~8 KB arrives, do I have to set up my code to handle data coming in chunks, or what?
Yes, that's exactly what you have to do, but I don't have time right now to write some code for you (I just arrived at work), I'll do it when i have some free time today.
But the main problem I see:
Actually, all the data gets sent, the data arrives in packets (4-8 KBytes/packet), the the DataArrival gets called several times.
Only the FIRST time you create the image file, after that you just have to APPEND data to it until you get all the data (you get the size of the file first time).
Re: Sending Images With Winsock
Quote:
Originally Posted by outcast24817
Thanks, CVMichael. I can now send the image, but only the first ~8 KB arrives, do I have to set up my code to handle data coming in chunks, or what?
Here is the receiving code:
VB Code:
Private Sub WS_DataArrival(Index As Integer, ByVal bytesTotal As Long)
Dim IncomingData As String
Dim BLine As LLine
Dim Splits() As String
Dim Filenum As Integer
'"image":length:data...
WS(Index).GetData IncomingData, vbString
Splits = Split(IncomingData, ":", 3, vbTextCompare)
If Splits(0) = "image" Then
'just... dump it all in a file
Filenum = FreeFile
Open "C:\Draw.bmp" For Binary Lock Write As Filenum
Len(Splits(0)) + Len(Splits(1)) + 2)
' put all data received into file, but make sure its only the stuff after "Image:length:"
[B][COLOR=Red]Put Filenum, , Mid$(IncomingData, Len(Splits(0)) + Len(Splits(1)) + 3)[/COLOR][/B]
Close Filenum
'set pic as picturebox
picMain.Picture = LoadPicture("C:\Draw.bmp")
end if
end function
Also, you're overwriting all pre-existing data in the file.
The 2nd argument of the Put statement is the offset (or starting byte) to put the data. The default is 1 (first byte).
Try this for starters:
VB Code:
Dim lonOffset As Long
lonOffset = FileLen("C:\Draw.bmp") + 1
Put Filenum, lonOffset, Mid$(IncomingData, Len(Splits(0)) + Len(Splits(1)) + 3)
Re: Sending Images With Winsock
Quote:
Originally Posted by DigiRev
Try this for starters:
VB Code:
Dim lonOffset As Long
lonOffset = FileLen("C:\Draw.bmp") + 1
Put Filenum, lonOffset, Mid$(IncomingData, Len(Splits(0)) + Len(Splits(1)) + 3)
2 things:
1) Don't use FileLen in the open statement, you might not get the correct size if the file is already opened... use LOF(FileNum), like this:
VB Code:
Put Filenum, [B]LOF(Filenum) + 1[/B], Mid$(IncomingData, Len(Splits(0)) + Len(Splits(1)) + 3)
2) That line should be used ONLY the first time because only the first time you have a header...
What I mean is:
VB Code:
' This line the first time:
Put Filenum, [B]LOF(Filenum) + 1[/B], Mid$(IncomingData, Len(Splits(0)) + Len(Splits(1)) + 3)
' after the first time, you don't have a header to strip off the string anymore
Put Filenum, [B]LOF(Filenum) + 1[/B], IncomingData
So... this code should be used instead:
VB Code:
If LOF(Filenum) = 0 Then
Put Filenum, , Mid$(IncomingData, Len(Splits(0)) + Len(Splits(1)) + 3)
Else
Put Filenum, LOF(Filenum) + 1, IncomingData
End If
Re: Sending Images With Winsock
Yea I kind of just scanned through the code and didn't really pay attention to the header, etc. Just noticed the Put statement was overwriting the file each time.
You're right about the LOF though, don't know how that slipped past me. :o ;)
Re: Sending Images With Winsock
There are 2 problems:
First, I don't know why you have an Index for the socket when for the client you should have only one connection. If this is for the server (instead of client) then the code should be diferent. If it's the server then you have to give each file a unique name because otherwise you will write data from all clients into one file, and I'm sure you don't want that...
Second: The next code you should use only for transfering the image file, if you transfer data other than the file, then you have to change the code for the other types of data. Since I don't know what else you transfer (how and what format), I could not write the code to support that also.
OK, here is the code, I did not test it, but it should work:
VB Code:
Private Sub WS_DataArrival(Index As Integer, ByVal bytesTotal As Long)
Dim sData As String, Pos As Long
' make the variales static so the data gets preserved between calls
' you can dim next variables in the
' General Declarations section also (but remove next line if you do so)
Static DataLength As Long, FileNum As Integer
'"image":length:data...
WS(Index).GetData sData, vbString
' first time, read header and open file
If DataLength = 0 And LCase(Left(sData, 6)) = "image:" Then
' get the total data length
DataLength = Val(Split(sData, ":")(1))
' find the second ":"
Pos = InStr(1, sData, ":")
Pos = InStr(Pos + 1, sData, ":")
' get only the bitmap data (stip off the header)
sData = Mid$(sData, Pos + 1)
FileNum = FreeFile
Open "C:\Draw.bmp" For Binary Lock Write As FileNum
End If
' save data into file
If DataLength > 0 And FileNum <> 0 Then
Put FileNum, LOF(FileNum) + 1, sData
' we received all the data that we are supposed to receive
If LOF(FileNum) >= DataLength Then
' close the file, and reset variables
Close FileNum
DataLength = 0
FileNum = 0
' load picture
picMain.Picture = LoadPicture("C:\Draw.bmp")
' delete temporary picture file
Kill "C:\Draw.bmp"
Else
End If
End Sub
Re: Sending Images With Winsock
Thanks, CVMichael. That code worked perfectly.
Sorry for the delayed reply.