I am using vb6 to retrieve an image from a camera through TCP-IP, Now the receiving the image in bytes and writing it to text and convert to image format takes roughly about 9 seconds. The total image size is around 1.6 mb and each packet size is 8192 bytes. The another problem is the CPU utilisation which is 100%.
Now I am finding a way to make the image displaying faster and to reduce the CPU processing. Since VB cannot support multithreading. I have left with only few options.
I tried to increase the socket receive size from 8192 bytes to 16384 bytes by changing the DefaultReceiveWindow in the registry (http://smallvoid.com/article/winnt-winsock-buffer.html)
[HKEY_LOCAL_MACHINE \SYSTEM \CurrentControlSet \Services \Afd \Parameters]
DefaultReceiveWindow = 16384
DefaultSendWindow = 16384
But there is no difference. I run on windows xp with pentium processor. Is there any other effective way to make the image receiving faster?
EDIT:
This is the receiving code
Private Sub DataArrival(ByVal bytes As Long)
Dim str As String
' check the socket for data
camera.GetData str
Dim str As String
While InStr(str, Terminator) <> 0
**Do some processing and put only the data in the variable str
str = Mid(str, index, 1000)
lImgSize = lImgSize + Len(str)
strImg = strImg + str
If lImageSize >= 1614414 Then
Dim fileno As Integer
fileno = FreeFile()
Open ".\Imagefile.txt" For Output As #intFileNo
Print #fileno , strImg
Close #fileno
End If
End Sub
this is my other related question How to read the end of image file stream in VB6
Related
I have some old code that writes binary data to the Response object's BinaryWrite() method (Classic ASP). It sends the data in 4MB chunks to BinaryWrite(), but now I'm wondering whether that ever worked and whether BinaryWrite() is even designed to handle serial chunks of data (or whether it should only be called, at most, once per page request).
I found this link that describes how the "Response Buffering Limit" should be increased, and increasing it seems to have solved the issues I was seeing (without using my chunking code at all).
https://learn.microsoft.com/en-us/troubleshoot/iis/http-500-response-binarywrite
This is the old code in question:
HRESULT STDMETHODCALLTYPE CQVMActiveHost::WriteData (const VOID* pcvData, DWORD cbData, __out DWORD* pcbWritten)
{
HRESULT hr;
DISPPARAMS dispParams = {0};
VARIANT vWrite = {0}, vResult = {0};
Check(LoadResponseObject());
dispParams.cArgs = 1;
dispParams.rgvarg = &vWrite;
if(m_fSupportsBinary)
{
SAFEARRAYBOUND Bound;
DWORD cbRemaining = cbData;
Bound.lLbound = 0;
vWrite.vt = VT_ARRAY | VT_UI1;
while(0 < cbRemaining)
{
PVOID pbPtr;
Bound.cElements = min(cbRemaining, 4 * 1024 * 1024);
vWrite.parray = SafeArrayCreate(VT_UI1, 1, &Bound);
CheckAlloc(vWrite.parray);
SafeArrayAccessData(vWrite.parray, &pbPtr);
CopyMemory(pbPtr, pcvData, Bound.cElements);
SafeArrayUnaccessData(vWrite.parray);
VariantClear(&vResult);
Check(m_pResponse->Invoke(m_dispidBinaryWrite, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD, &dispParams, &vResult, NULL, NULL));
SafeArrayDestroy(vWrite.parray);
vWrite.parray = NULL;
pcvData = reinterpret_cast<const BYTE*>(pcvData) + Bound.cElements;
cbRemaining -= Bound.cElements;
}
vWrite.vt = VT_EMPTY;
}
else
I've seen a couple different behaviors with the old code. In some tests, the first call to BinaryWrite() succeeded, but subsequent calls failed with the "exception occurred" HRESULT. In other tests, the calls seemed to succeed, but the browser didn't receive any data.
Are there any scenarios where it would make sense to make multiple calls to BinaryWrite() with chunked data?
Or should I always increase the "Response Buffering Limit" value to more than 4MB and just make a single call to BinaryWrite() with the full data?
Thanks!
I have to wonder whether the Response.Buffer property was false when I originally wrote the code above. What I've found is the following:
The Response.BinaryWrite() method MAY be called multiple times per page request.
If a large amount of data is to be returned to the client, then split the data into multiple calls to Response.BinaryWrite().
The "Response Buffering Limit" value in IIS (for ASP) is 4MB by default.
If Response.Buffer is true, then multiple calls to Response.BinaryWrite() may be made until the total data reaches the "Response Buffering Limit" value. At that point, Response.Flush() MUST be called. Otherwise, attempting to send more data results in error 0x80020009.
If Response.Buffer is false, then do NOT call Response.Flush(), but do split the data into multiple (smaller) calls to Response.BinaryWrite().
As an example, I was trying to send a 12MB file using multiple calls to Response.BinaryWrite() with each chunk being 4MB. Buffering was enabled, so the first call succeeded, but the next call failed. Raising the "Response Buffering Limit" to 16MB "solved" the issue but increased the buffering allocation for ASP.
Ultimately, I've modified my chunking code to first query the Response.Buffer property. The data is always sent in smaller fragments to Response.BinaryWrite(), but Response.Flush() is also called if buffering is enabled.
Finally, don't set the Content-Length header. The browser may not know how many bytes will be downloaded, but it will receive the file correctly without manually setting that header. Setting that header breaks the download.
And the final ASP script:
function GoDownloadFile (strPath)
{
var idxName = strrchr(strPath, '/');
var strFolder = left(strPath, idxName + 1);
var strFile = right(strPath, len(strPath) - (idxName + 1));
var oFS = Security.GetChannel().OpenFileSystem();
oFS.Folder = strFolder;
Response.ContentType = Host.GetContentType(strFile);
Response.AddHeader("Content-Disposition", "attachment; FileName=\"" + strFile + "\"");
Host.BinaryWrite(oFS.ReadFile(strFile));
}
When I try to initialize(ReDim) Byte array with long data type then I am getting Run-time error : Out of memory exception.
I have tried many ways but still no luck. It is Throwing Out of memory error if I ReDim Byte > 200000000
Dim bArr() As Byte
Dim lSize As Long
lSize = 210000000
ReDim bArr(0 To lSize) 'This statement is throwing out of memory error
I want the Byte Array to accept the range of Long variable but getting Out of Memory error
this is mostly a ruby question.
I'm stuck trying to parse some bytes from an i2c device to a float value on ruby.
Long story:
I'm trying to read a float value from an i2c device with raspberry pi and an AtTiny85 (the device). i'm able to read its value from console through i2ctools
Example:
i2cset -y 0 0x25 0x00; sleep 1; i2cget -y 0 0x25 0x00; i2cget -y 0 0x25 0x00; i2cget -y 0 0x25 0x00; i2cget -y 0 0x25 0x00
Gives me:
0x3e
0x00
0x80
0x92
that means 0.12549046, which is a value in volts that i'm able to check with my multimeter and is ok. (the order of the bytes is 0x3e008092)
Now i need to get this float value from a ruby script, I'm using the i2c gem.
A comment on this site suggest the following conversion method:
hex_string = '42880000'
float = [hex_string.to_i(16)].pack('L').unpack('F')[0]
# => 68.0
float = 66.2
hex_string = [float].pack('F').unpack('L')[0].to_s(16)
# => 42846666
But i haven't been able to get this string of hex values. This fraction of code:
require "i2c/i2c"
require "i2c/backends/i2c-dev"
#i2c = ::I2C.create("/dev/i2c-0")
sharp = 0x25
#i2c.write(sharp, 0)
sleep 1
puts #i2c.read(sharp, 4).inspect
Puts on screen
">\x00\x00P"
Where the characters '>' and 'P' are the ASCII values of the byte in that position, but then i cannot know where/how to split the string and clean it up to at least try the method showed above.
I could write a C program to read the value and printf it to console or something and run it from ruby, but i think that would be an awful solution.
Some ideas on how can this be done would be very helpful!
Greetings.
I came with something:
bytes = []
for i in (0..3) do
bytes << #i2c.read_byte(sharp).unpack('*C*')[0].to_s(16)
bytes[i] = "00" unless bytes[i] != "0"
end
bytes = bytes.join.to_s
float = [bytes.to_i(16)].pack('L').unpack('F')[0]
puts float.to_s
Not shure about unpack(' * C * ') though, but it works. If it's a better way to do it i'd be glad with another answer.
Greetings!
You probably just need to use unpack with a format of g, or possible e depending on the endianness.
#i2c.read(sharp, 4).unpack('g')[0]
The example you are referring to is taking a string of hex digits and first converting it to a binary string (that’s the [hex_string.to_i(16)].pack('L') part) before converting to an integer (the L directive is for 32 bit integers). The data you have is already a binary string, so you just need to convert it directly with the appropriate directive for unpack.
Have a read of the documentation for unpack and pack.
I would like to know if the performance is better in case I am storing the string length
in a temporary variable when I am using a loop of at list 10,000 loops instead of calculating it in every loop?
Code example calculating the string length:
'--
Dim I
Dim str : str = "Lets say this string length is around 50,000"
'--
For I=0 To 100000
Response.Write Len(str) & "<br>"
Next
Code example using a temporary variable:
'--
Dim I
Dim str : str = "Lets say this string length is around 50,000"
Dim temp : temp = Len(str)
'--
For I=0 To 100000
Response.Write temp & "<br>"
Next
What do you think is better?
Thanks!
Here's an idea: Why don't you just measure it?
Dim start: start = Timer
...<code here>...
Response.Write FormatNumber(Timer - start, 8)
To measure is to know. Having said that: You might want to read the story about Shlemiel the Painter.
Eventually the Response.write will probably be the most expensive operation; if you really want to measure the "cost" of Len() vs. a temp variable (even though both methods output the same amount of data) you should probably do something like this:
Dim I, J, X
Dim start
Dim str : str = String(50000, "-")
Dim tmp : tmp = Len(str)
Response.Write "Temp var:<br>"
For J = 0 to 10
start = Timer
X = 0
For I=0 To 100000
x = x + tmp
Next
Response.write FormatNumber(Timer - start,8) & "<br>"
Next
Response.Write "Len:<br>"
For J = 0 to 10
start = Timer
X = 0
For I=0 To 100000
x = x + Len(str)
Next
Response.write FormatNumber(Timer - start,8) & "<br>"
Next
In my case, the output is:
Temp var:
0,03125000
0,03125000
0,04687500
0,03125000
0,03515625
0,02734375
0,03125000
0,03125000
0,03515625
0,02734375
0,03125000
Len:
0,04687500
0,04687500
0,03125000
0,04687500
0,04687500
0,04687500
0,05078125
0,02734375
0,04687500
0,05078125
0,04687500
As you can see, using Len() every iteration is measureably slower (even though it isn't that much, about 35%). Using a temp-variable will be a good idea, but you could've guessed that without this knowledge or measuring at all, didn't you?
I am unsure about VBScript but many languages (and their compilers/JIT'ers) do optimize this stuff at compile/JIT-time on their own. The compiler/runtime/JIT usually "notices" these kinds of patterns and will introduce a "temp variable" automatically.
But then: why would you be doing tens-of-thousands of iterations on such a large chunk of data in (classic) ASP at all? Do you really have to output this much data? Can't the processing be done (more) by the backend or something? Are you doing actually 10.000 iterations on 50Kb strings? Or is this just a theoretical discussion? If you're doing one, or a handful, iterations, on "simple, short strings" I wouldn't bother with an extra variable at all. This introduces other issues; for example having to keep the variable "in sync" should the str variable change etc. Also readability (and "understandability) would be improved just using Len(foo) where you need the length. If you do introduce a variable, which is justified and sometimes an optimization worth the "hassle", I would at least make sure it is named correctly (not tmp but foolength for example).
If you just follow the simple rule "Never do in a loop what you can do before it" you don't have to waste time on benchmarks.
(It's bitter to have to read such a question, and I want to batter a programmer who does not know on which side the toast is buttered.)
I have unicode string passed to vbscript procedure (not visual basic 6, but vbscript). I want to iterate unicode string char by char, get code for every symbol, truncate code to byte range [0..255] and create array of bytes.
This way new array of bytes should be twice smaller in memory compared to original unicode string. I am going save this array to file via ADODB.Stream object further
How can I convert unicode string to bytes array with symbol code truncated to byte range?
Thank you in advance!
Firstly, translating unicode to ascii will only work if your string only contains ascii characters. Since unicode contains ascii, it is just a matter of removing every second character.
Look up unicode on the internet for details.
EDIT: In unicode, every ascii character is proceeded with a NULL (0) byte. Remove this byte to convert the string to ASCII.
It seems there is no way to create array of bytes in vbs (though it's very straightforward in visual basic) -- all arrays are arrays of variants.
The task was to send binary stream from server to vbs script via string type. I have found the solution by creating Xml Document on the server with CDATA section that contains base64 coded array of bytes as string data.
Client (vbs) do the following:
set xmlDoc = CreateObject("Microsoft.XmlDom")
xmlDoc.loadXML(dataFromServer)
base64str = xmlDoc.DocumentElement.Text ' it's base64 coded binary stream
arrayOfBytes = decodeBase64(base64str)
Function decodeBase64(base64)
set dm = CreateObject("Microsoft.XMLDOM")
set el = dm.createElement("tmp")
el.DataType = "bin.base64"
el.Text = base64
decodeBase64 = el.NodeTypedValue
set dm = Nothing
End Function
This function creates an array of bytes:
' http://www.motobit.com/tips/detpg_binarytostring/
Function MultiByteToBinary(MultiByte)
'� 2000 Antonin Foller, http://www.motobit.com
' MultiByteToBinary converts multibyte string To real binary data (VT_UI1 | VT_ARRAY)
' Using recordset
Dim RS, LMultiByte, Binary
Const adLongVarBinary = 205
Set RS = CreateObject("ADODB.Recordset")
LMultiByte = LenB(MultiByte)
If LMultiByte>0 Then
RS.Fields.Append "mBinary", adLongVarBinary, LMultiByte
RS.Open
RS.AddNew
RS("mBinary").AppendChunk MultiByte & ChrB(0)
RS.Update
Binary = RS("mBinary").GetChunk(LMultiByte)
End If
MultiByteToBinary = Binary
End Function
This function creates a multi-byte string.
' http://www.motobit.com/help/regedit/pa26.htm
'Converts unicode string to a multibyte string
Function StringToMB(S)
Dim I, B
For I = 1 To Len(S)
B = B & ChrB(Asc(Mid(S, I, 1)))
Next
StringToMB = B
End Function