0

I thought the most easiest thing to help with my problem would be to simply post the project here. But that isn't going to work.

So here are the parts where I think it is going wrong:

public class ItemQuoteDecoderText : ItemQuoteDecoder
{
    //Character encoding
    public Encoding encoding;

    public ItemQuoteDecoderText() : this(ItemQuoteTextConst.DEFAULT_CHAR_ENC) { }

    public ItemQuoteDecoderText(string encodingDesc)
    {
        encoding = Encoding.GetEncoding(encodingDesc);
    }

    public ItemQuote decode(Stream wire)
    {
        string itemNo, description, quant, price, flags;

        byte[] space = encoding.GetBytes(" ");
        byte[] newline = encoding.GetBytes("\n");

        itemNo = encoding.GetString(ItemQuoteFramer.nextToken(wire, space));
        description = encoding.GetString(ItemQuoteFramer.nextToken(wire, newline));
        quant = encoding.GetString(ItemQuoteFramer.nextToken(wire, newline));
        price = encoding.GetString(ItemQuoteFramer.nextToken(wire, newline));
        flags = encoding.GetString(ItemQuoteFramer.nextToken(wire, newline));

        return new ItemQuote(Int64.Parse(itemNo),
                                description,
                                Int32.Parse(quant),
                                Int32.Parse(price),
                                (flags.IndexOf('d') != -1),
                                (flags.IndexOf('s') != -1));
    }

    public ItemQuote decode(byte[] packet)
    {
        Stream payload = new MemoryStream(packet, 0, packet.Length, false);
        return decode(payload);
    }
}

At the decoder the incoming stream is decoded to form a read-able outcome. Unfortunately the error that occurs at:

price = encoding.GetString(ItemQuoteFramer.nextToken(wire, newline));

With the message:

An exception of type 'System.ArgumentNullException' occurred in mscorlib.dll but was not handled in user code

Additional information: Array cannot be null.

The ItemQuoteFramer:

    public class ItemQuoteFramer
{
    public static byte[] nextToken(Stream input, byte[] delimiter)
    {
        int nextByte;

        //If the stream has already ended, return null
        if ((nextByte = input.ReadByte()) == -1)
            return null;

        MemoryStream tokenBuffer = new MemoryStream();
        do
        {
            tokenBuffer.WriteByte((byte)nextByte);
            byte[] currentToken = tokenBuffer.ToArray();
            if (endsWith(currentToken, delimiter))
            {
                int tokenLength = currentToken.Length - delimiter.Length;
                byte[] token = new byte[tokenLength];
                Array.Copy(currentToken, 0, token, 0, tokenLength);

                return token;
            }
        }
        while ((nextByte = input.ReadByte()) != -1);

        return tokenBuffer.ToArray();
    }

    static bool endsWith(byte[] value, byte[] suffix)
    {
        if (value.Length < suffix.Length)
            return false;

        for (int offset = 1; offset <= suffix.Length; offset++)
            if (value[value.Length - offset] != suffix[suffix.Length - offset])
                return false;

        return true;
    }
}

Will skip it's delimiter after the variable "quant" in ItemQuoteDecoderText is filled. Which leaves the last part of the send packet: "1000 12999 d" as a whole in "quant" and will return null for the last two ("price" & "flags") variables.

    public class SendUdp
{
    public SendUdp(string[] args)
    {
        SendUdpMethod(args);
    }

    void SendUdpMethod(string[] args)
    {
        //Check for correct amount of arguments
        if ((args.Length < 2) || (args.Length > 3))
            throw new ArgumentException("Parameters: <Destination> <Port> [<Encoding>]");

        string server = args[0];
        int destPort = Int32.Parse(args[1]);

        //Make an item to quote
        ItemQuote quote = new ItemQuote(12345678909876554L, "5mm Super Widgets", 1000, 12999, true, false);

        UdpClient client = new UdpClient();

        ItemQuoteEncoder encoder = ((args.Length == 3) ? new ItemQuoteEncoderText(args[2]) : new ItemQuoteEncoderText());
        byte[] codedQuote = encoder.encode(quote);

        client.Send(codedQuote, codedQuote.Length, server, destPort);
        client.Close();
    }
}

This is the code that will handle how the packet will be received:

    public class ReceiveUdp
{
    public ReceiveUdp(string[] args)
    {
        ReceiveUdpMethod(args);
    }

    void ReceiveUdpMethod(string[] args)
    {
        //Check for correct amount of arguments
        if ((args.Length < 1) || (args.Length > 2))
            throw new ArgumentException("Parameters: <Port> [<Encoding>]");

        int port = Int32.Parse(args[0]);
        UdpClient client = new UdpClient(port);

        byte[] packet = new byte[ItemQuoteTextConst.MAX_WIRE_LENGTH];
        IPEndPoint remoteIPEndPoint = new IPEndPoint(IPAddress.Any, port);

        packet = client.Receive(ref remoteIPEndPoint);
        ItemQuoteDecoderText decoder = ((args.Length == 2) ? new ItemQuoteDecoderText(args[1]) : new ItemQuoteDecoderText());

        ItemQuote quote = decoder.decode(packet);
        Console.WriteLine(quote);

        client.Close();
    }
}

ItemQuoteFramer likes to skip the delimiter and I think that's where it goes wrong. But I have no idea what to do about it. Would anyone be so kind to take the time to help me figure it out?

Thank you very much,
Farcrada

Farcrada
  • 75
  • 1
  • 6
  • Check to see if number of bytes received match the sent byte count. Usually the issue is not getting all the received data. UDP is not reliable so some datagrams can get dropped. Try TCP instead. – jdweng Jan 14 '16 at 15:19
  • The Tcp version works fine, indeed, though it is not a matter of bytes being dropped or not arriving. They all arrive, but for some reason the delimiter in ItemQuoteFramer is being skipped in it's loop and won't report the token it has just made, @jdweng. – Farcrada Jan 14 '16 at 15:21
  • How can you skip data and still have the same number of bytes? Most stream classes default to ASCII encoding which will remove any non printable characters. Use need to specify all streams to be UTF8 to prevent character from being dropped. – jdweng Jan 14 '16 at 17:11
  • You're either not reading my problem/comment correctly, @jdweng, or you're on about something entirely different. – Farcrada Jan 17 '16 at 16:13
  • You are receiving a null. Normally nulls in steams (TCP is a stream) occurs because you are trying to decode data before all the data is received. The first question I have is how do you know that you have received all the data? Second, how is data being skipped if you received all the data? The byte count will change if data is being dropped. – jdweng Jan 17 '16 at 16:36
  • Read the snippets posted above. Everything I give and could receive is in those snippets. The ***code*** "skipped" a delimiter because the delimiter parsed was not a newline in the decode (Check the answer below.) and thus it seemed like it received a null when asking for a new token. At which point you would be right if it wasn't for the fact the delimiter parameter should've been a space instead of a newline. The whole point wasn't data being skipped, but the delimiter not working as intended. Only it did, but I just needed to use the correct delimiter. Which it does now. – Farcrada Jan 18 '16 at 22:28

1 Answers1

0

The answer lies in the way the delimiter is given. The variable "quant" holds (at the time of the error) the following: "1000 12999 d".

If you look at which delimiter has been given through, it gives: "newline". If we change that to: "space", we fix our problem.

To clarify, the following in ItemQuoteDecoderText:

    itemNo = encoding.GetString(ItemQuoteFramer.nextToken(wire, space));
    description = encoding.GetString(ItemQuoteFramer.nextToken(wire, newline));
    quant = encoding.GetString(ItemQuoteFramer.nextToken(wire, newline));
    price = encoding.GetString(ItemQuoteFramer.nextToken(wire, newline));
    flags = encoding.GetString(ItemQuoteFramer.nextToken(wire, newline));

Should become:

    itemNo = encoding.GetString(ItemQuoteFramer.nextToken(wire, space));
    description = encoding.GetString(ItemQuoteFramer.nextToken(wire, newline));
    quant = encoding.GetString(ItemQuoteFramer.nextToken(wire, space));
    price = encoding.GetString(ItemQuoteFramer.nextToken(wire, space));
    flags = encoding.GetString(ItemQuoteFramer.nextToken(wire, newline));

I would like to thank everyone that took their time to take a look at this.

Thank you very much,
Farcrada

Farcrada
  • 75
  • 1
  • 6