0

I'm trying to make a simple UDP socket server for a Unity3D game I'm making, and I've got it mostly working. I can send messages to it and read the messages. But when I'm trying to send the message back to the client (for testing purposes, at the moment), I get a BufferOverFlowException.

Before sending the data back, I'm converting it to json using groovy.json.JsonBuilder. The data has a very simple structure:

[data: "Hello World"]

But for whatever reason, JsonBuilder is building it as

{ "data": "Hello World\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\..." }

the \u0000's go on for a while. Long enough to make my 1024 byte long ByteBuffer overflow.

This is the class that's responsible for sending the data back to the client:

import groovy.json.JsonBuilder
import groovy.transform.CompileStatic
import groovyx.gpars.actor.DynamicDispatchActor

import java.nio.ByteBuffer
import java.nio.channels.DatagramChannel

@CompileStatic
class SenderActor extends DynamicDispatchActor{

    //takes message of type [data: Object, receiver: SocketAddress]
    void onMessage(Map message){

        println(message.data) //prints "Hello World"
        def json = new JsonBuilder([data: message.data]).toString()
        println("Sending: $json") //prints '{"data": "Hello World\u0000\u0000..."}'

        def channel = DatagramChannel.open()
        channel.connect(message.receiver as SocketAddress)

        def buffer = ByteBuffer.allocate(1024)
        buffer.clear()
        buffer.put(json.getBytes())
        buffer.flip()

        channel.send(buffer, message.receiver as SocketAddress)
    }
}

And this is the stack trace I get:

An exception occurred in the Actor thread Actor Thread 2
java.nio.BufferOverflowException
    at java.nio.HeapByteBuffer.put(HeapByteBuffer.java:189)
    at java.nio.ByteBuffer.put(ByteBuffer.java:859)
    at Croquet.Actors.SenderActor.onMessage(SenderActor.groovy:28)
    at Croquet.Actors.SenderActor$onMessage.call(Unknown Source)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:45)
    at Croquet.Actors.ProcessorActor$onMessage.call(Unknown Source)
    at groovyx.gpars.actor.impl.DDAClosure$_createDDAClosure_closure1.doCall(DDAClosure.groovy:38)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:90)
    at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:324)
    at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:292)
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1016)
    at groovy.lang.Closure.call(Closure.java:423)
    at groovy.lang.Closure.call(Closure.java:439)
    at groovyx.gpars.actor.AbstractLoopingActor.runEnhancedWithoutRepliesOnMessages(AbstractLoopingActor.java:293)
    at groovyx.gpars.actor.AbstractLoopingActor.access$400(AbstractLoopingActor.java:30)
    at groovyx.gpars.actor.AbstractLoopingActor$1.handleMessage(AbstractLoopingActor.java:93)
    at groovyx.gpars.util.AsyncMessagingCore.run(AsyncMessagingCore.java:132)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)

The data in question is encoded as UTF-8, if that helps.

This is the client code that is responsible for sending data to the server (written in C#):

void sendTestMessage(UdpClient udpClient, UdpState udpState){
        byte[] data = Encoding.UTF8.GetBytes("Hello World");
        udpClient.BeginSend(
            data, 
            data.Length, 
            udpState.e, //IPEndPoint
            result =>{
                messageSent = true;
                Debug.Log(string.Format("Message '{1}' Sent to {0}", udpState.e, Encoding.UTF8.GetString(data)));
                udpClient.EndSend(result);
            }, 
            udpState);
    }
Fiberwire
  • 55
  • 1
  • 8
  • Does the non-pretty version work correctly? (In general the prettified version isn't the greatest idea in terms of performance anyway.) – Dave Newton Sep 03 '15 at 15:27
  • @Dave No, the regular toString() still adds the \u0000's. Also, good to know about the performance thing :) – Fiberwire Sep 03 '15 at 15:30
  • it may be possible that the character for which `\u0000` is the escape sequence is actually in your source data but you do not see it because it's a whitespace (or some other, special) character, and it's not escaped in whatever viewer you use to see your input data? – Michal M Sep 03 '15 at 15:38
  • @Michal I'm not really sure how that could have happened. I'll add the client code responsible for sending the data to my question, though. – Fiberwire Sep 03 '15 at 15:43
  • I dunno, I've never seen this behavior; sorry. – Dave Newton Sep 03 '15 at 15:56
  • Oh right, I don't mean to sound overly mistrustful, but you actually do something to the lines of: `assert message.data.toString() == 'Hello World'`? – Michal M Sep 03 '15 at 15:57
  • @MichalM That assertion failed. `An exception occurred in the Actor thread Actor Thread 2 Assertion failed: assert message.data.toString() == "Hello World" | | | | | Hello World` – Fiberwire Sep 03 '15 at 16:02
  • I'm not really sure why those characters are being added, but I solved my problem by adding `.replace("\\u0000", "")` to the end of `def json = new JsonBuilder([data: message.data]).toString()`. I'll be adding it as an answer. – Fiberwire Sep 03 '15 at 16:05
  • Is the UDP socket server currently echoing what the client sends to it? If so, maybe it's the client that's appending all that extra data. – Emmanuel Rosa Sep 03 '15 at 20:37
  • @Emmanuel Yeah, it is. I think you're probably right. – Fiberwire Sep 03 '15 at 20:39
  • Where's the code that reads the data from the UDP socket and puts it in the message Map? – Emmanuel Rosa Sep 04 '15 at 02:30

1 Answers1

0

I solved my problem by changing

def json = new JsonBuilder([data: message.data]).toString()

to

def json = new JsonBuilder([data: message.data]).toString().replace("\\u0000", "")

Fiberwire
  • 55
  • 1
  • 8
  • That's not solving the problem, that's just hiding it. Your string is packed with null chars for some reason, that's why it's padding the end with utf null char representations – tim_yates Sep 03 '15 at 20:48
  • @tim_yates How would you go about solving this particular problem? – Fiberwire Sep 03 '15 at 20:52
  • Remove the null characters from the end of `message.data`. I'm not sure how it's being generated, you don't say – tim_yates Sep 03 '15 at 21:36
  • It's generated in the second line of the client code at the end of the question. It's just a hardcoded string, which is what had me confused about how the null characters are being generated. – Fiberwire Sep 03 '15 at 21:49