Valhalla Legends Forums Archive | .NET Platform | [VB] NetworkStream Help

AuthorMessageTime
Spilled[DW]
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.
[code]
    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
[/code]

Here is the recieving loop that is not working...
[code]
        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
[/code]

Any ideas guys?

Also after every time I Write//Send bytes, should I be doing NetworkStream.Flush?
January 17, 2006, 9:01 AM
indulgence
[quote author=MSDN]NetworkStream.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.[/quote]
[code]    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[/code]

Maybe loop calls to that looking for a terminator... not really into the "bot" thing
January 17, 2006, 6:56 PM
Myndfyr
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 author=Spilled link=topic=13937.msg142136#msg142136 date=1137488503]
[code]
    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
[/code]
[/quote]
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 author=Spilled link=topic=13937.msg142136#msg142136 date=1137488503]
Here is the recieving loop that is not working...
[code]
        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
[/code]
[/quote]
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:
[code]
        /// <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;
                    }
                }
            }
        }
[/code]

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 author=Spilled link=topic=13937.msg142136#msg142136 date=1137488503]
Also after every time I Write//Send bytes, should I be doing NetworkStream.Flush?
[/quote]
See: [quote author=MSDN]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.[/quote]

Indulgence, I suggest you take a look at that last sentence before you try to look cool.
January 17, 2006, 7:03 PM
indulgence
[quote author=MyndFyre link=topic=13937.msg142168#msg142168 date=1137524639]
See: [quote author=MSDN]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.[/quote]

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

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...
January 17, 2006, 7:15 PM
kamakazie
[quote author=MyndFyre link=topic=13937.msg142168#msg142168 date=1137524639]
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:
[code]
            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);
            }
[/code]
[/quote]

You need to be careful with that call to [tt]Read[/tt] because it does not guarantee it will read 4-bytes. Checking the return value would be wise.
January 17, 2006, 9:18 PM
Myndfyr
[quote author=dxoigmn link=topic=13937.msg142182#msg142182 date=1137532727]
You need to be careful with that call to [tt]Read[/tt] because it does not guarantee it will read 4-bytes. Checking the return value would be wise.
[/quote]

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.
January 17, 2006, 9:21 PM
Spilled[DW]
Ok, ive switch my NetWorkStream receive sub to BinaryReader and all is fine until after i receive 0x25 and 0x50

Heres my code:

[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..")
[/code]

Ok the error Occurs here:
[code]
br.ReadByte()
[/code]

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!
January 20, 2006, 6:47 AM
Myndfyr
NetworkStream.CanRead will always return true because it is a stream that supports reading.  Please read the documentation to learn these kinds of things. 
January 24, 2006, 4:13 PM
Spilled[DW]
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.
January 24, 2006, 4:17 PM
Myndfyr
[quote author=Spilled link=topic=13937.msg142954#msg142954 date=1138119440]
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.
[/quote]

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.
January 24, 2006, 4:23 PM
Spilled[DW]
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.
January 24, 2006, 4:29 PM

Search