• Welcome to Valhalla Legends Archive.
 

[VB] NetworkStream Help

Started by Spilled, January 17, 2006, 03:01 AM

Previous topic - Next topic

Spilled

Ok, in my .Net bot im attemping to create im using a NetworkStream for sending//recieving data, but I'm not doing it the right way obviously because its not working and I was wondering if someone could give me some help or show me an example of how its done.

Here I create the connection and a thread for the recieving.

    Private Sub mnuConnect_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles mnuConnect.Click
        Dim port As Int32 = 6112
        Dim Server As String = "asia.battle.net"
        AddChat(Color.Yellow, "Attemping to Connect.")
        Try
            wSock = New TcpClient(Server, port)
            Stream = wSock.GetStream()
            Dim pbyte(1) As Byte
            pbyte(0) = &H1
            Stream.Write(pbyte, 0, 1)

            InsertDWORD(0)
            InsertNonNTString("68XI")
            InsertNonNTString(sClient)
            InsertDWORD(&HCD)
            InsertDWORD(0)
            InsertDWORD(0)
            InsertDWORD(0)
            InsertDWORD(0)
            InsertDWORD(0)
            InsertNTString("USA")
            InsertNTString("United States")
            SendBNCSPacket(&H50)

            Dim t As Thread
            t = New Thread(AddressOf Recieve)
            t.Start()

        Catch f As SocketException
            AddChat(Color.Red, f)
        End Try
    End Sub


Here is the recieving loop that is not working...

        Dim tempBuff2(299) As Byte, pLen As Long, TotalBytes As Long, used As Long
        While Stream.CanRead
            Do While Stream.DataAvailable
                used = 0
                pLen = 0
                TotalBytes = Stream.Read(tempBuff2, 0, tempBuff2.Length)
                Dim tempBuff(TotalBytes - 1) As Byte
                Array.Copy(tempBuff2, 0, tempBuff, 0, TotalBytes)
                While used <> TotalBytes
                    pLen = tempBuff(used + 2)
                    Dim p1(pLen - 1) As Byte
                    Array.Copy(tempBuff, used, p1, 0, pLen)
                    Parsep(p1)
                    used = used + pLen
                End While
                Stream.Flush()
            Loop
        End While


Any ideas guys?

Also after every time I Write//Send bytes, should I be doing NetworkStream.Flush?

indulgence

#1
Quote from: MSDNNetworkStream.Flush Method

Flushes data from the stream. This method is reserved for future use.

Remarks

The Flush method implements the Stream.Flush method; however, because NetworkStream is not buffered, it has no affect on network streams. Calling the Flush method will not throw an exception.
    Function Receive() As String
        Dim Bytes(wSock.ReceiveBufferSize) As Byte
        Dim objSR As New System.IO.StreamReader(Stream, Encoding.ASCII)
        Receive = (objSR.ReadToEnd())
    End Function


Maybe loop calls to that looking for a terminator... not really into the "bot" thing
<3

MyndFyre

#2
The first thing I'm having an issue with is that you're not providing any information about what's wrong.  You're not giving us an error, you're not giving us a packet log, or any indication about what might be wrong.  We're just supposed to sift through a mound of code and determine what the problem is for you.

Here's one problem I see.  It's probably not the cause of your problems, but it can be a problem down the line:

Quote from: Spilled on January 17, 2006, 03:01 AM

    Private Sub mnuConnect_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles mnuConnect.Click
            Dim t As Thread
            t = New Thread(AddressOf Recieve)
            t.Start()
    End Sub

You're creating a thread in a local scope and not saving it to the global scope.  While this won't terminate the thread when you exit scope, it will prevent you from ever terminating the thread outside of your loop (Thread.CurrentThread.Stop()), which is programmatically a questionable thing to do.

Quote from: Spilled on January 17, 2006, 03:01 AM
Here is the recieving loop that is not working...

        Dim tempBuff2(299) As Byte, pLen As Long, TotalBytes As Long, used As Long
        While Stream.CanRead
            Do While Stream.DataAvailable
                used = 0
                pLen = 0
                TotalBytes = Stream.Read(tempBuff2, 0, tempBuff2.Length)
                Dim tempBuff(TotalBytes - 1) As Byte
                Array.Copy(tempBuff2, 0, tempBuff, 0, TotalBytes)
                While used <> TotalBytes
                    pLen = tempBuff(used + 2)
                    Dim p1(pLen - 1) As Byte
                    Array.Copy(tempBuff, used, p1, 0, pLen)
                    Parsep(p1)
                    used = used + pLen
                End While
                Stream.Flush()
            Loop
        End While

Where to begin?  You have a lot more loops in there than is necessary.  At most you need one loop, and that's the outer loop.  I'm not sure if "While stream.CanRead" is appropriate.  You might rather look at "stream.Socket.Connected" instead.

The nice thing about a NetworkStream as opposed to using something like a raw Socket is that you get the ability to parse data with stream reading tools like the StreamReader and BinaryReader.  Both of these classes work with streams.  Realistically though, to parse a single packet, each receive loop (the actual loop iteration, not the code construct) should receive 4 bytes out of the socket, parse the header, and then receive packet-length more bytes out of the stream.  Since the header is nice and tells you how long the packet is, you only need to read that much more data to get a complete packet, and wait until you're ready to parse the next packet.  That's how MBNCSUtil does it:

        /// <summary>
        /// Creates a new data reader with the specified stream as input.
        /// </summary>
        /// <param name="str">The stream from which to read.</param>
        public BncsReader(Stream str) : base(str)
        {
            if (str == null)
                Locales.ThrowNullArgExc(ResID.streamNull, ResID.param_str);

            using (BinaryReader br = new BinaryReader(str))
            {
                byte[] header = new byte[4];
                br.ReadByte();
                m_id = br.ReadByte();
                m_len = br.ReadUInt16();

                if (m_len > 4)
                {
                    int moreDataLen = m_len - 4;
                    int curIncIndex = 0;
                    m_data = new byte[moreDataLen];
                    while (moreDataLen > 0)
                    {
                        int tmpLen = br.Read(m_data, curIncIndex, moreDataLen);
                        curIncIndex += tmpLen;
                        moreDataLen -= tmpLen;
                    }
                }
            }
        }


Also, you might be getting the "Changes to the appearance of Windows controls must take place on the same thread as they were created" problem.  For example, if you're setting text in a rich text box in the Parsep function, you're doing that on the child thread.  That causes a Windows error and consequently a runtime .NET exception (sometimes; the RTB has a weird problem in that it doesn't always throw an exception, but freezes the program).

Quote from: Spilled on January 17, 2006, 03:01 AM
Also after every time I Write//Send bytes, should I be doing NetworkStream.Flush?
See:
Quote from: MSDNRemarks
The Flush method implements the Stream.Flush method; however, because NetworkStream is not buffered, it has no affect on network streams. Calling the Flush method will not throw an exception.

Indulgence, I suggest you take a look at that last sentence before you try to look cool.
QuoteEvery generation of humans believed it had all the answers it needed, except for a few mysteries they assumed would be solved at any moment. And they all believed their ancestors were simplistic and deluded. What are the odds that you are the first generation of humans who will understand reality?

After 3 years, it's on the horizon.  The new JinxBot, and BN#, the managed Battle.net Client library.

Quote from: chyea on January 16, 2009, 05:05 PM
You've just located global warming.

indulgence

#3
Quote from: MyndFyre on January 17, 2006, 01:03 PM
See:
Quote from: MSDNRemarks
The Flush method implements the Stream.Flush method; however, because NetworkStream is not buffered, it has no affect on network streams. Calling the Flush method will not throw an exception.

Indulgence, I suggest you take a look at that last sentence before you try to look cool.

Sheesh sorry I edited that part in if you would have noticed - only b/c I, obviously, misread.  My initial statement was that the calls were un-neccessary...
<3

dxoigmn

Quote from: MyndFyre on January 17, 2006, 01:03 PM
Realistically though, to parse a single packet, each receive loop (the actual loop iteration, not the code construct) should receive 4 bytes out of the socket, parse the header, and then receive packet-length more bytes out of the stream.  Since the header is nice and tells you how long the packet is, you only need to read that much more data to get a complete packet, and wait until you're ready to parse the next packet.  That's how MBNCSUtil does it:

            byte[] header = new byte[4];
            str.Read(header, 0, 4);
            m_id = header[1];
            m_len = BitConverter.ToUInt16(header, 2);

            if (m_len > 4)
            {
                m_data = new byte[m_len - 4];
                str.Read(m_data, 0, m_len - 4);
            }


You need to be careful with that call to Read because it does not guarantee it will read 4-bytes. Checking the return value would be wise.

MyndFyre

Quote from: dxoigmn on January 17, 2006, 03:18 PM
You need to be careful with that call to Read because it does not guarantee it will read 4-bytes. Checking the return value would be wise.

Yeah that is old code, I've already switched it over to BinaryReader-based code.  But it's the same idea: it should block until the specified data comes in.
QuoteEvery generation of humans believed it had all the answers it needed, except for a few mysteries they assumed would be solved at any moment. And they all believed their ancestors were simplistic and deluded. What are the odds that you are the first generation of humans who will understand reality?

After 3 years, it's on the horizon.  The new JinxBot, and BN#, the managed Battle.net Client library.

Quote from: chyea on January 16, 2009, 05:05 PM
You've just located global warming.

Spilled

Ok, ive switch my NetWorkStream receive sub to BinaryReader and all is fine until after i receive 0x25 and 0x50

Heres my code:

   
Public Sub Receive(ByVal str As NetworkStream)
        Dim br As New BinaryReader(str)
        Dim header(4) As Byte, m_Read As Long, m_ID As Byte, pLen As Short
        While Stream.CanRead
            br.ReadByte()
            m_ID = br.ReadByte()
            pLen = br.ReadInt16
            If pLen > 4 Then
                Dim moreData As Short
                moreData = pLen - 4
                Dim p1(pLen - 1) As Byte
                Dim curIndex As Integer = 4
                p1(0) = &HFF
                p1(1) = m_ID
                Array.Copy(BitConverter.GetBytes(pLen), 0, p1, 2, 2)
                While moreData > 0
                    Dim tmpLen As Integer
                    tmpLen = br.Read(p1, curIndex, moreData)
                    curIndex += tmpLen
                    moreData -= tmpLen
                End While
                Parsep(p1)
            End If
        End While
        AddChat(Color.Red, "Connection Lost..")


Ok the error Occurs here:

br.ReadByte()


I think its because it's trying to read a byte and there is no data, what would i put into the while statement to keep it from erroring but not exiting the loop? Thanks in advance guys!

MyndFyre

NetworkStream.CanRead will always return true because it is a stream that supports reading.  Please read the documentation to learn these kinds of things. 
QuoteEvery generation of humans believed it had all the answers it needed, except for a few mysteries they assumed would be solved at any moment. And they all believed their ancestors were simplistic and deluded. What are the odds that you are the first generation of humans who will understand reality?

After 3 years, it's on the horizon.  The new JinxBot, and BN#, the managed Battle.net Client library.

Quote from: chyea on January 16, 2009, 05:05 PM
You've just located global warming.

Spilled

hrmm well when I do Stream.Socket.Connected there is no .Socket property, Could this have something to do with the .Net Framework? I'm using the 1.1 Framework currently.

MyndFyre

Quote from: Spilled on January 24, 2006, 10:17 AM
hrmm well when I do Stream.Socket.Connected there is no .Socket property, Could this have something to do with the .Net Framework? I'm using the 1.1 Framework currently.

Nope, there *is* a Socket property on the networkstream class.  I think it has to do with the fact that you're using a braindead case-insensitive language that doesn't know you're referring to the local identifier "stream" as opposed to the System.IO identifier "Stream".  It doesn't help that your naming isn't preventing this collision, either.
QuoteEvery generation of humans believed it had all the answers it needed, except for a few mysteries they assumed would be solved at any moment. And they all believed their ancestors were simplistic and deluded. What are the odds that you are the first generation of humans who will understand reality?

After 3 years, it's on the horizon.  The new JinxBot, and BN#, the managed Battle.net Client library.

Quote from: chyea on January 16, 2009, 05:05 PM
You've just located global warming.

Spilled

#10
hrmm, I never really thought of that. Well im at school right now so when I get home ill take a look, thanks again myndfyre and check back for my edit if your not too busy later.

Edit:

It's saying that the Socket propertie is Protected ReadOnly. Would I have to do some kind of Sub Classing? on top of that, im not using a socket im using a tcpClient.