The orginal CSocket & cSocket2 were designed to emulate the Microsoft Winsock Control. Data would be sent and recovered as variants. On input, the variant was converted to byte array, converted to string using StrConv, added and subtracted to a string buffer, converted back to byte array, and finally handed over to the Socket API. Receipt of data was similar. Verion 2 of NewSocket eliminated all the back and forth conversion, and interfaced using a single conversion of string to byte. Because the StrConv function caused problems with systems using a non-latin character set, it also was eliminated.
Version 2.5 sends and accepts both ASCII strings and byte arrays. Since the Socket API requires byte strings, it made sense to allow direct input and output of byte arrays. This meant converting the string buffers (m_strSendBuffer and m_strRecvBuffer) to byte arrays and writing routines to replace the simple string concatenation and string search functions. At the same time, the functions to send and receive data were changed from a single call which included the data as a string, to 2 separate calls; one to place the data in a buffer, and one to perform the actual function. This enabled the option of using ASCII string data or byte array data.
Code:
Old Way New Way
Socket.SendData strData Socket.sOutBuffer = strData '(ASCII String)
or Socket.bOutBuffer = bData '(Byte Array)
Socket.SendData
Socket.GetData strData Socket.RecoverData
strData = Socket.sInBuffer '(ASCII String)
or bData = Socket.bInBuffer '(Byte Array)
This posting just includes the "NewSocket.cls" and it's companion "mWinsock.bas", as well as a small program (prjTest.vbp) to test the pair. Once these have proved themselves, I will publish the corresponding OCX.
J.A. Coutts
Last edited by couttsj; May 19th, 2020 at 12:09 PM.
Now that we have the ability to use either strings or byte arrays, how do we decide which one to use? If you are sending/receiving ASCII text or Byte Arrays, the answer is obvious. But if you are assembling binary data, the answer is not quite so clear. For this task, I chose the first message sent when negotiating a TLS (Transport Layer Security) connection; the ClientHello message. This message consists of the following:
The SessionID is only used when re-establishing a previous connection, and the Compression Method is not currently used. The Extension that should always be used is the SNI (Server Name Indication), as this is required by servers that support more than one domain.
Currently, I use the following:
Code:
Private Function GetClientHello() As String
Call SecureSession.GenRandom(28&)
CLIENT_RANDOM = GetUnixTime & SecureSession.RndBuffer
'Cipher Suites recovered from Class
GetClientHello = Chr$(&H1) & Chr$(&H0) & Chr$(&H0) & Chr$(&H0) & Chr$(VERSION_MAJOR) & Chr$(VERSION_MINOR_3) _
& CLIENT_RANDOM _
& Chr$(&H0) & SecureSession.GetCiphers & Chr$(&H1) & Chr$(&H0) _
& Chr$(&H0) & Chr$(Len(SNI)) & SNI
Mid$(GetClientHello, 3, 1) = Chr$(Int((Len(GetClientHello) - 4) / 256))
Mid$(GetClientHello, 4, 1) = Chr$((Len(GetClientHello) - 4) Mod 256)
End Function
To perform the same function using byte arrays, I came up with the following:
Code:
Private Function GetClientHelloB() As Byte()
Dim UnixTimeB() As Byte
Dim CiphersB() As Byte
Dim SNIb() As Byte
Dim bTmp() As Byte
Dim lLen As Long
Dim lPntr As Long
Call SecureSession.GenRandom(32&)
CLIENT_RANDOMb = SecureSession.RndBufferB
UnixTimeB = GetUnixTimeB
SNIb = StrToByte(SNI)
CopyMemory CLIENT_RANDOMb(0), UnixTimeB(0), 4
CiphersB = SecureSession.GetCiphersB
lLen = 39 + GetbSize(CiphersB) + GetbSize(SNIb)
ReDim bTmp(lLen + 3)
bTmp(0) = &H1
bTmp(2) = Int(lLen / 256)
bTmp(3) = lLen Mod 256
bTmp(4) = VERSION_MAJOR
bTmp(5) = VERSION_MINOR_3
CopyMemory bTmp(6), CLIENT_RANDOMb(0), 32
lLen = GetbSize(CiphersB)
CopyMemory bTmp(39), CiphersB(0), lLen
lPntr = lLen + 39
bTmp(lPntr) = &H1
lPntr = lPntr + 3
lLen = GetbSize(SNIb)
bTmp(lPntr) = lLen
lPntr = lPntr + 1
CopyMemory bTmp(lPntr), SNIb(0), lLen
GetClientHelloB = bTmp
End Function
But that is only half the story. Which one provides the better performance? To answer that question, I ran each one 10,000 times, and averaged the resulting 5 execution times. The byte array example ran about 3.3% faster. But we need to eventually end up with a byte array, so when that function is added to the first example, the byte array ran about 4% faster.
The extra complexity required by the byte array example has to be balanced against the slight improvement in execution speed gained, and that will depend entirely on the individual situation. If there is little data manipulation needed to acquire the byte array, then obviously that would be the route to take. It's a judgement call.
As no problems have surfaced with Newocket 2.5, attached is the Control program NewSocket.ocx. Also included are 2 test programs; WebTest1 to test NewSocket/mWinsock and WebTest2 to test the OCX. ocxTest is included to assist with upgrading from an older version. Full instructions are located in the readme.txt file.
if i usde CSockerMaster & Plus.zip. may have bugs. for example if i send files . cont used send data for string ,must used bytarry. in your post zip file .i find
Code:
Case vbArray + vbByte Dim strArray As String strArray = StrConv(Data, vbUnicode) If GetLong(strArray) = 0 Then Exit Sub arrData() = StrConv(strArray, vbFromUnicode)
.may have bugs... CHines system and English system ,have some differents
Last edited by xxdoc123; Nov 14th, 2016 at 05:02 AM.
is there any differents between NewSock and CSocketMaster CSocketPlus by Emiliano Scavuzzo
There are many differences, not the least of which is that CSocketMaster does not support IPv6. The major problem you will experience using it with Chinese is the use of StrConv, which is not compatible with anything but the Latin character set (ie. it does not support Unicode).
There are many differences, not the least of which is that CSocketMaster does not support IPv6. The major problem you will experience using it with Chinese is the use of StrConv, which is not compatible with anything but the Latin character set (ie. it does not support Unicode).
J.A. Coutts
can you see my post
i used your 2.5 ocx .post picture ....have bugs .can not sent bytarrays
If you use the class directly instead of the OCX, you can troubleshoot the problem. I suspect that it has something to do with the size of the image, but I am just guessing as you have not supplied enough information. I have used NewSocket in JACMail to send images for years without a problem.
If you use the class directly instead of the OCX, you can troubleshoot the problem. I suspect that it has something to do with the size of the image, but I am just guessing as you have not supplied enough information. I have used NewSocket in JACMail to send images for years without a problem.
J.A. Coutts
because i have a demo project used mswinsk.ocx word well.so i replace it to you ocx . but can not work.
you means you ocx may have bugs.i will use the class later...
O,i mean if i post a picture or other files.i must post boutbuff.can not used soutbuff. because i used Chinese system . ~ but when i
when i send boutbuff. client can not receive data ......can you give me a example .how send boutbuff??? thanks
Last edited by xxdoc123; Nov 15th, 2016 at 01:30 AM.
because i have a demo project used mswinsk.ocx word well.so i replace it to you ocx . but can not work.
you means you ocx may have bugs.i will use the class later...
O,i mean if i post a picture or other files.i must post boutbuff.can not used soutbuff. because i used Chinese system . ~ but when i
when i send boutbuff. client can not receive data ......can you give me a example .how send boutbuff??? thanks
Send me a private message with your email address.
if i set imagen(1 to 1023) .. senddata may send 1024 to client .....not 1023
i think you set bytearray always LBound=0.but sometimes will not .
Code:
Public Function GetbSize(bArray() As Byte) As Long
On Error GoTo GetSizeErr
GetbSize = UBound(bArray) - LBound(bArray) + 1 ---------fixed
Exit Function
GetSizeErr:
GetbSize = 0
End Function
Code:
Public Function AddByte(bArray1() As Byte, bArray2() As Byte, Optional lLen As Long) As Boolean
Dim lLen1 As Long
Dim lLen2 As Long
lLen1 = GetbSize(bArray1)
lLen2 = GetbSize(bArray2)
If lLen2 = 0 Then GoTo Done
If lLen > 0 Then
If lLen2 > lLen Then
lLen2 = lLen
End If
End If
ReDim Preserve bArray1(lLen1 + lLen2 - 1)
CopyMemory bArray1(lLen1), bArray2(LBound(bArray2)), lLen2
Done:
AddByte = True
End Function
may be must have others need edit ,but i can not checked all~~
Last edited by xxdoc123; Nov 15th, 2016 at 07:16 PM.
I believe I know what your problem is. You are trying to send binary data (eg. image file). When you transfer data to the Winsock buffer, the API breaks it up into packets and sends it to the other end. Text data has a natural line break consisting of a CrLf. The sample programs I have provided process incoming data based upon receiving a line break. Binary data has no line break. There are a couple of ways around that. One is to Base64 encode the binary data with a header as the email system does, and decode it on the receiving end. The other way is to just process the data as it is received without waiting for a line break. In this case, you must add a header to the binary data to tell the receiver how much data to expect. My TLS programs do exactly that, as encrypted data is pure binary data.
There are many differences, not the least of which is that CSocketMaster does not support IPv6. The major problem you will experience using it with Chinese is the use of StrConv, which is not compatible with anything but the Latin character set (ie. it does not support Unicode).
J.A. Coutts
thank you for ur explaining
question 1:
if that u means, ur NewSock 2.5 support Unicode well?
question 2:
when i transfer Chinese string in the CSocketMaster author's demo, it seems all good.
i have found no problem, can u detail the problem for me and how can i fix it...
loquat
Last edited by loquat; Nov 16th, 2016 at 07:49 AM.
Reason: add one qustion
thank you for ur explaining
question 1:
if that u means, ur NewSock 2.5 support Unicode well?
question 2:
when i transfer Chinese string in the CSocketMaster author's demo, it seems all good.
i have found no problem, can u detail the problem for me and how can i fix it...
loquat
see my post!you sent a picture ,you may know this have bugs .you can search in vbgood .hh
that u means, ur NewSock 2.5 support Unicode well?
no!arraytostr and strtoarray function not well 。you can test string"vbgood好"!may used strconv to replace!
when i transfer Chinese string in the CSocketMaster author's demo, it seems all good.
i have found no problem, can u detail the problem for me and how can i fix it...
loquat
This problem is well documented in this forum. When Microsoft implemented Unicode in VB, they simply changed strings from 8 bit characters to 16 bit characters, instead of implementing 2 string versions. They try to make the conversion automatically in the background, and unfortunately don't do a very good job of it. ANSI characters (0 to 127) convert just fine, but some characters above &H7F do not convert properly. Like the standard Textbox, StrConv was developed to use ANSI characters. If your system settings are configured to support a non-Latin character set (eg. Chinese or Arabic), the operating system will change not only the value, but the length of these problem characters, and this creates no end of difficulties when trying to send binary data. The only fix is to not use the problem functions.
that u means, ur NewSock 2.5 support Unicode well?
no!arraytostr and strtoarray function not well...
That's true, these built-in conversion-functions are not Unicode-aware.
So you will have to avoid them, simply not using the SocketClass's Properties:
- sInbuffer
- sOutBuffer
@Coutts
the simplest fix for your functions (making them Unicode-aware) would be:
Code:
Public Function ByteToStr(bArray() As Byte) As String
ByteToStr = bArray
End Function
Public Function StrToByte(strInput As String) As Byte()
StrToByte = strInput
End Function
That's true, these built-in conversion-functions are not Unicode-aware.
So you will have to avoid them, simply not using the SocketClass's Properties:
- sInbuffer
- sOutBuffer
@Coutts
the simplest fix for your functions (making them Unicode-aware) would be:
Code:
Public Function ByteToStr(bArray() As Byte) As String
ByteToStr = bArray
End Function
Public Function StrToByte(strInput As String) As Byte()
StrToByte = strInput
End Function
Olaf
I have never had a problem with these functions, as long as they are used to convert ASCII/ANSI data. Coercing the data doesn't work:
String Data:
53 00 61 00 6D 00 70 00 6C 00 65 00
Coerced Byte Data:
53 00 61 00 6D 00 70 00 6C 00 65 00
Byte Data using StrToByte:
53 61 6D 70 6C 65
The whole reason for using 2 different methods of transferring data (ASCII vs Byte Array) was to allow for Unicode to be treated as binary data.
I have never had a problem with these functions, as long as they are used to convert ASCII/ANSI data. Coercing the data doesn't work:
String Data:
53 00 61 00 6D 00 70 00 6C 00 65 00
Coerced Byte Data:
53 00 61 00 6D 00 70 00 6C 00 65 00
Well, as the above output shows - it indeed *does* work correctly -
in an unicode-aware manner, just that the ByteArrays contain "the WChar-Content of the BString exactly".
Originally Posted by couttsj
Byte Data using StrToByte:
53 61 6D 70 6C 65
The whole reason for using 2 different methods of transferring data (ASCII vs Byte Array) was to allow for Unicode to be treated as binary data.
If you want to "allow for Unicode to be treated as binary data", there's two ways to do it:
1) the one I have shown (exact 16Bit-WChar-mapping to ByteArrays and vice versa)
2) using MultiByteToWideChar/WideCharToMultiByte with CP_UTF8, to work with "8Bits per char for at least the ASCII-range"
So in your case, you'd probably want to introduce #2) into your routines ByteToStr and StrToByte -
or alternatively leave the String-Properties out of your Socket-Class completely ...
(then offering only ByteArray-transfers, which would shift the Unicode-encoding-responsibilities to the user of your Socket-Class).
If you want to "allow for Unicode to be treated as binary data", there's two ways to do it:
1) the one I have shown (exact 16Bit-WChar-mapping to ByteArrays and vice versa)
2) using MultiByteToWideChar/WideCharToMultiByte with CP_UTF8, to work with "8Bits per char for at least the ASCII-range"
Olaf
Unfortunately, that won't work for the email system. It only accepts 7 bit ASCII data.
Unfortunately, that won't work for the email system. It only accepts 7 bit ASCII data.
That was probably true more than 20 years ago.
In the meantime (also already quite old) there's MIME -
supporting the normal 7Bit Transport-layer - e.g. over 64Bit encodings or quoted printable,
but also 8Bit-extension for the Transportlayer exist (supported by nearly all MailServers).
But now we are discussing the specifics of a concrete protocol (SMTP) -
so far I thought, your socket-component was written to support arbitrary transports.
Olaf
As you have pointed out, there are ways to transport any kind of data in the body of the message. But what I am talking about is the command structure itself. It is all 7 bit ASCII, and I am just using that as an example of the need for both kinds of data. I personally use both (ASCII and byte array), depending on the need. It is entirely up to the user.
...what I am talking about is the command structure itself. It is all 7 bit ASCII,...
No, not necessarily - there's 8BIT-extensions in the meantime (for the SMTP-commandlayer),
which many (most) of the current mail-servers support.
Originally Posted by couttsj
I personally use both (ASCII and byte array), depending on the need. It is entirely up to the user.
I'm only arguing from the point of a "potentially misleading interface" (for the Users of your Socket-Class).
Since your current StrToBytes/BytesToStr-functions are "lossy" (only supporting the ASCII-range) -
I would (for the sake of the User) rename them (on the outside of the Interface) probably to:
- sInbufferASCII -> StrToBytesASCII (this one raising an error, on the first found WChar which is larger than 127)
- sOutbufferASCII -> BytesToStrASCII
Then maybe add in addition, true Unicode-Codecs which are lossless (what's put in, will also come out exactly:
- sInbufferUnicode16BitLE -> WStrToBytes
- sOutbufferUnicode16BitLE -> BytesToWStr
That's not a bad idea Olaf. I will look at implementing that in SimpleSock, as it will probably replace NewSocket. From all appearances thus far, it is simpler and easier to use, and negates the need to use a control array. Are you willing to test Unicode on it, as I have a lot of difficulty testing that particular part.
That's not a bad idea Olaf. I will look at implementing that in SimpleSock, as it will probably replace NewSocket. From all appearances thus far, it is simpler and easier to use, and negates the need to use a control array. Are you willing to test Unicode on it, as I have a lot of difficulty testing that particular part.
J.A. Coutts
Well, since it is called "SimpleSock", I would keep it lean - and leave any String-Conversion-Functions out of it
(allowing only ByteArrays to be passed and retrieved).
And for the conversions of ByteArrays-to-(V)BString and vice versa, I'd provide an *additional* Codec-Class,
which supports several Methods:
- (V)BString to ASCII-ByteArray and vice versa
- (V)BString to ANSII-ByteArray and vice versa
- (V)BString to UTF8-ByteArray and vice versa
- (V)BString to UTF16-ByteArray and vice versa
maybe adding into that Codec-Class also (since that's often needed in protocols):
- Base64-Encoding/Decoding
- URL-Encoding/Decoding
In the RichClient-lib I have such a "separation of concerns" already:
- the cUDP/cTCPClient/cTCPServer-Classes only supporting ByteArrays
- all the String-conversion and Crypto-stuff sitting in a separate Class: cCrypt
if i used winsock to post files to web .i must post head (string ) and body (bytearray). i have convert head( string )to byterarray used strconv(str,vbformunicode),and combine the head and body .used winsock send all bytarry. have no questions.so i want to ask why not used STRconv ,is so easy to translate str and bytarray ~~ I 'M newbie.and amateur
if i used winsock to post files to web .i must post head (string ) and body (bytearray). i have convert head( string )to byterarray used strconv(str,vbformunicode),and combine the head and body .used winsock send all bytarry. have no questions.so i want to ask why not used STRconv ,is so easy to translate str and bytarray ~~ I 'M newbie.and amateur
Next
------------------------
206
210
49
50
51
--------------------------------------------------
if used your
Private Sub Form_Load()
Dim a() As Byte, b As Integer
a = StrToByte("我123")
For b = 0 To UBound(a)
Debug.Print a(b)
Next
End Sub
Public Function StrToByte(strInput As String) As Byte()
Dim lPntr As Long
Dim bTmp() As Byte
Dim bArray() As Byte
If Len(strInput) = 0 Then Exit Function
ReDim bTmp(LenB(strInput) - 1) 'Memory length
ReDim bArray(Len(strInput) - 1) 'String length
CopyMemory bTmp(0), ByVal StrPtr(strInput), LenB(strInput)
'Examine every second byte
For lPntr = 0 To UBound(bArray)
If bTmp(lPntr * 2 + 1) > 0 Then
'bArray(lPntr) = Asc(Mid$(strInput, lPntr + 1, 1))
StrToByte = bTmp
Exit Function
Else
bArray(lPntr) = bTmp(lPntr * 2)
End If
Next lPntr
StrToByte = bArray
End Function
---------------------------------
17
98
49
0
50
0
51
0
------------------
Private Sub Form_Load()
Dim b() As Byte, a As String, i As Integer
a = "我123"
b = a
For i = 0 To UBound(b)
Debug.Print b(i)
Next
End Sub
-------------------
17
98
49
0
50
0
51
0
Last edited by xxdoc123; Nov 21st, 2016 at 11:24 PM.
The problem occurs when you attempt to send encrypted data. Encrypted data is byte data that uses the entire ANSI range (0 to 255). If the system code page is a non-Latin character set, it will substitute a "?" for the problem characters listed in the page I referred you to. These are the functions I will probably use when I add Unicode as Olaf has suggested:
Code:
Public Function StrToByte(strInput As String) As Byte()
Dim lPntr As Long
Dim bTmp() As Byte
Dim bArray() As Byte
If Len(strInput) = 0 Then Exit Function
bTmp = strInput
ReDim bArray(Len(strInput) - 1) 'String length
'Copy every second byte
For lPntr = 0 To UBound(bArray)
bArray(lPntr) = bTmp(lPntr * 2)
Next lPntr
StrToByte = bArray
End Function
Public Function UniToByte(strInput As String) As Byte
UniToByte = strInput
End Function
I am evaluating newsocket.cls as winsock.ocx replacement.
Server application needs to signal (send data to) multiple clients and other servers in company network. All client/server ip addresses are known, as workstations resolve free port number and store the port number and ip address to database.
Question - how to use newsocket class to send/receive data from/to multiple clients.
Do i need to instantiate as many sockets dynamically, as there are clients listening or can i use ip address/port array to send multiple clients?
Thinking of using UDP protocol. Option is that clients acknowledge checksum of received data, back to server which sent it.
I am evaluating newsocket.cls as winsock.ocx replacement.
Server application needs to signal (send data to) multiple clients and other servers in company network. All client/server ip addresses are known, as workstations resolve free port number and store the port number and ip address to database.
Question - how to use newsocket class to send/receive data from/to multiple clients.
Do i need to instantiate as many sockets dynamically, as there are clients listening or can i use ip address/port array to send multiple clients?
Thinking of using UDP protocol. Option is that clients acknowledge checksum of received data, back to server which sent it.
Not sure I fully understand your requirement, but a server application using TCP would require each workstation to establish a connection with the server. Whether using MS Winsock or Newsocket would require using a control array. SimpleServer on the other hand will maintain multiple connections to a single port without resorting to a control array.
However, your description sounds like UDP would be more appropriate. The workstations would maintain an open UDP port, and the server would maintain a record of the targeted workstations, and send the data to each one. But because there is no established connection, the workstations would be required to send back an acknowledgement to verify receipt. SimpleSock should be able to handle that, but each time the targeted IP address changes, you will have to close the existing socket and reinitialize it.
Operation is like you wrote. There are couple of server applications (approximately 10-15), which acts also as a client application to other servers. Total client count is, all workstations acting as servers, plus few others consuming data clients, just refreshing changed database table data.
Connected workstation IP and port are stored in separate table. So there is no 'dedicated' server forwarding ip traffic to clients. Only certain workstations can acts as a server and when there is no servers online, clients just waits.
Purpose of all this is to signal database table changes to all applications (read workstation machines) connected.
Last edited by Tech99; Apr 25th, 2017 at 11:29 PM.