XaeroDegreaz / SmartSocket

SmartSocket is an extensible open source, Java and PHP socket server engine. Its aim is to make creating multi-user applications as quick and painless as possible. With SmartSocket, you don't have to worry about keeping track of users, writing server code, managing threads, etc. All you have to do is use the simple communication protocol to send method call back and forth between the server and the client!
http://www.smartsocket.net
15 stars 4 forks source link

Server force connection close? #3

Closed Gadsoc closed 9 years ago

Gadsoc commented 9 years ago

I'm looking for a way to destroy a connection if the client has sent invalid info. It looks like the "destroySession" method in TCPClient is what I'm looking for but the function is private. Is there another way to trash the client object or do I need to edit the source code to expose this function?

EDIT: I'm working with the v2 sources now and remote calls from the as3 client result in a java.lang.OutOfMemoryError exception when running TCPClient.getFileBytes.

I'm constructing my call from the client like so:

var call:RemoteCall = new RemoteCall("greeting", "main");
call.message = "Client greeting!";
SmartSocketClient.send(call);

When tracing the issue I found a curious result of the above client sent call to the server: TCPClient -> read() -> getFileLength() = fileLength: 2480750516282419045

This value seems very wrong to me given that the client call doesn't even include a file. The client-side trace statement when sending the call is the following: SmartSocketClient => Sending {"message":"Client greeting!","fileBytes":null,"method":"greeting","directTo":"main"}

I realize this project hasn't been touched in a while. Please point me in the right direction if I should be looking elsewhere, or if there is something I can do to work around this issue.

XaeroDegreaz commented 9 years ago

Hello :)

it looks like you may be using the binary version of RemoteCall. I cant remember off the top of my head, but I don't believe that was ever fully compatible with Flash clients. I built that protocol out of necessity when needing to transfer files to a Java client at the time.

No clue as to why you'd be getting a file length like that though =\

Anyhow, according to the docs located here:

https://github.com/XaeroDegreaz/SmartSocket/blob/master/SmartSocket%20v2/src/net/smartsocket/serverclients/TCPClient.java#L274

... you should use the JSON RemoteCall.

/* * The RemoteCall message to send to this client. This method should no longer be used unless * your client is a Flash client using the ActionScript 3.0 SmartSocket Client API, or you need * text-only data transfers. * @param message * @see net.smartsocket.protocols.json.RemoteCall * @deprecated Use send(net.smartsocket.protocols.binary.RemoteCall call) for non-Flash clients. / public void send( net.smartsocket.protocols.json.RemoteCall message )

As far as disconnecting the client, you're correct -- it seems as though I didn't expose that for some reason. Now that I look, I can't imagine why. But yeah, you'll want to recompile and set that public. I'd even accept a pull request if you wanted to fork it.

If you're looking for some more examples of how to use SmartSocket, I'd suggest checking out SmartLobby as a reference point: https://github.com/XaeroDegreaz/SmartSocket/tree/master/SmartSocket%20v2/src/net/smartsocket/smartlobby . you should note that extension is still using the JSON RemoteCall.

All in all, SmartSocket is a damn old creation of mine. It was my first real Java project, so there are lots of things that I can look back as a professional software engineer and laugh about :D

There are certainly more up-to-date technologies available. While SmartSocket is supposed to be super easy to setup, I think something like Websockets, or some other JavaEE framework that supports these types of connections would deserve some looking at.

Gadsoc commented 9 years ago

Greetings,

First, thanks for this library. It may be old news to you but it's simplicity is what made it my first choice.

As for the issue. The as3 client sources do not contain a binary RemoteCall. The only thing that changed afaik in the as3 class is a new class variable "fileBytes" was added, but the SmartSocketClient class hasn't changed to utilize it (that I can tell).

The problem is server side. Inside the TCPClient class the read() method changed from:

private void read() {
        String input = null;

        try {
            while ( !(input = _in.readLine()).equals( null ) ) {
                //# TODO - Add some different processing method calls here (xml, raw). Add some try/catch blocks to go down the line.
                process( input );
            }
        } catch (Exception e) {
            Logger.log( "Client " + Thread.currentThread().getId() + " disconnected." );
        }

    }

To:

private void read() {
        String input = null;
        byte[] bytes = null;
        int red;
        try {
            while ( (red = in.read()) != -1 ) {
                Logger.log( "Client input stream open." );

                long fileLength = getFileLength();
                byte[] fileBytes = getFileBytes( fileLength );
                String jsonHeader = getJsonHeader();

                Logger.log( "Server message: " + fileLength + " / " + jsonHeader );

                process( jsonHeader, fileBytes );
            }
            Logger.log( "Client input stream closed." + red );
        } catch (Exception e) {
            Logger.log( "Client " + Thread.currentThread().getId() + " disconnected." + e.getMessage() );
            e.printStackTrace();
        }

    }

In this new read() method the getFileLength() method returns 2,480,750,516,282,419,045 when the as3 client sends a RemoteCall. Whether fileBytes is null or an empty byteArray the result is the same impossible number that obviously runs until you're out of memory and then throws an exception. So the problem is (I think) that the server TCPClient.java doesn't know how to handle the as3 RemoteCall json object. The reasons are over my head, but I'm fairly certain this is where the problem lies.

My solution is simply to use the old files (which fortunately I still have, I am not sure if they can be obtained on github). Using the old files as a starting point I have exposed the destroySession() method (simply made it public) and it seems to work fine.

In general I love the simplicity of this library, and unless there is something fundamentally inferior about it when compared to more popular implementations of things like WebSockets, I would prefer to simply modify it where needed. Basically, are the inner functions of this library sound enough to use them as a base for an enterprise application, or is there a flaw that you are aware of?

I have looked at other communication implementations and tbh this one "made the most sense" to me. I'm not overly concerned with how popular it is, as long as that isn't an indication of some serious design flaw. But I also don't know enough about this area to judge. I trust that you do. So if you think I should use something else for a serious project, please let me know, otherwise I'll continue to tweak your library, because I honestly love it.

XaeroDegreaz commented 9 years ago

Well thanks for the kind words :) I'm really happy to hear some feedback after all of this time.

I can't tell you for sure what is happening with the file length. I remember updating the Flash client so that it would still at least function with sending basic data back and forth.

There were some fundamental changes that needed to be made in order for SmartSocket to support sending files; SmartSocket used to only send text data back and forth.

I had to engineer a way for packing information into bytestream to let the server / client know whether or not there was file data in the stream. This is what you see happening with the new read and write methods.

I pack the stream with information such as file length, the file bytes, and lastly some UTF (text) payload. If there is no file length written to the front of the byte stream, SmartSocket server skips trying to do anything with a file in the process method.

You said you're using the v2 sources, are you talking about SmartSocket v2 (server), or the ActionScript 3.0 v2 client? Or both? If you are not using both v2 versions, then I'm pretty sure that your problem lies there.

To be clear, make sure you are using both v2 server AND v2 client.

The v2 client dissasembles the binary sends from the server as seen here:

        protected function onJSON(event:ProgressEvent):void {           
            var incoming:String;

            if(useZlib) {
                //# Create a byteArray to hold our data
                var byteArray:ByteArray = new ByteArray();              
                //# Read the ByteArray data sent from the server into byteArray
                readBytes(byteArray);               
                //# Uncompress the ZLIB string.
                byteArray.uncompress();             
                //# Read the JSON string that was uncompressed.
                incoming = byteArray.readUTFBytes(byteArray.bytesAvailable);                
            }else {
                incoming = this.readUTFBytes(this.bytesAvailable);
            }

            //# Trash byte
            this.readByte();

            //# File length bytes
            var fileLength:int = this.readInt();

            //# Setup a ByteArray to hold the file data
            var fileBytes:ByteArray = new ByteArray();

            //# Loop through the buffer, and write these bytes to the fileBytes array
            for(var ii:int = 0; ii < fileLength; ii++) {
                fileBytes.writeByte( this.readByte() );
            }

            //# Read the rest of the bytes as UTF -- this is the RemoteCall
            incoming = this.readUTF();
.................

It also assembles it's payload in a binary format, and sends it to the SmartSocket server in a way that it should be able to understand o_O

If the v2 sources are simply not working for you, perhaps something has changed in the newer Flash players since my time working on this. I think I last played with flash around FP 10 or 11.

If neither of these suggestions work for you, it seems like you have a solution by simply hacking the sources.

I'm not directly aware of any specific inferiorities (except your issue I guess ^^), but I'm sure that in several years of new web framework developments, there's something that has this beat.

Gadsoc commented 9 years ago

I created a new client and server from the master zip file just to be sure. The code you posted is in my SmartSocketClient class. Unfortunately the error still happens with simple greeting/onGreeting methods like you used in the tutorial videos. The reasons why are above my head, but the v2 version throws this error every time an ActionScript 3.0 v2 client sends a call to the server.

You said... "If there is no file length written to the front of the byte stream, SmartSocket server skips trying to do anything with a file in the process method." But this is the problem I believe, because getFileLength() is returning that huge number (above) even with a fileBytes value of null or an empty "new ByteArray()". So the server isn't skipping reading the file. Instead it thinks there is a file so huge that it burns through available memory trying to read it.

I will just continue using the older version. Thanks a lot for your responses. I'll close this issue.