Exit
  • Global community
    • Language:
      • Deutsch
      • English
      • Español
      • Français
      • Português
  • 日本語コミュニティ
  • 한국 커뮤니티
0

Establishing a socket connection between a .swf file and a socket-test program (TCP/IP builder - Windows), in AS3.

New Here ,
Aug 27, 2014 Aug 27, 2014

I have an issue with a college project I'm working on.

Using Actionscript 3, I made a simple .swf program, an animated, interactive smiley, that 'reacts' to number inputs in a input-box.

For the sake of the project, I now need to make the framework for establishing a socket connection with the smiley .swf, and another program.

This is where I encounter issues. I have very little knowledge of AS3 programming, so I'm not certain how to establish the connection - what's required code-wise for it, that is.

To test the connection, I'm attempting to use the "TCP/IP builder" program from windows, which lets me set up a server socket. I need to program the .swf file into a client - to recognize it, connect to it, then be able to receive data (so that the data can then be used to have the smiley 'react' to it - like how it does now with the input-box, only 'automatically' as it gets the data rather than by manual input).

My attempts at coding it are as follows, using a tutorial (linked HERE😞

//SOCKET STUFF GOES HERE

//****************************************************************

    var socket:XMLSocket;        

    stage.addEventListener(MouseEvent.CLICK, doConnect)

// This one connects to local, port 9001, and applies event listeners

    function doConnect(evt:MouseEvent):void 

{ 

    stage.removeEventListener(MouseEvent.CLICK, doConnect)

    socket = new XMLSocket("127.0.0.1", 9001);   

    socket.addEventListener(Event.CONNECT, onConnect)

    socket.addEventListener(IOErrorEvent.IO_ERROR, onError)

}

// This traces the connection (lets us see it happened, or failed)

    function onConnect(evt:Event):void 

    { 

        trace("Connected")

        socket.removeEventListener(Event.CONNECT, onConnect)

        socket.removeEventListener(IOErrorEvent.IO_ERROR, onError)

     

        socket.addEventListener(DataEvent.DATA, onDataReceived)

        socket.addEventListener(Event.CLOSE, onSocketClose);             

        stage.addEventListener(KeyboardEvent.KEY_UP, keyUp)

    } 

     

    function onError(evt:IOErrorEvent):void 

    { 

        trace("Connect failed")

        socket.removeEventListener(Event.CONNECT, onConnect)

        socket.removeEventListener(IOErrorEvent.IO_ERROR, onError)

        stage.addEventListener(MouseEvent.CLICK, doConnect)

    } 

   

// Here, the flash tracks what keyboard button is pressed.

// If 'q' is pressed, the connection ends.

        function keyUp(evt:KeyboardEvent):void 

    { 

        if (evt.keyCode == 81) // the key code for q is 81 

        { 

            socket.send("exit")

        } 

        else 

        { 

            socket.send(evt.keyCode)

        } 

    } 

// This one should handle the data we get from the server.

        function onDataReceived(evt:DataEvent):void 

    { 

        try { 

            trace("From Server:",  evt.data )

        } 

        catch (e:Error) { 

            trace('error')

        } 

    } 

     

    function onSocketClose(evt:Event):void 

    { 

        trace("Connection Closed")

        stage.removeEventListener(KeyboardEvent.KEY_UP, keyUp)

        socket.removeEventListener(Event.CLOSE, onSocketClose)

        socket.removeEventListener(DataEvent.DATA, onDataReceived);

Trying to connect to the socket gives me either no result (other than a 'connection failed' message when I click the .swf), or the following error:

Error #2044: Unhandled securityError:. text=Error #2048: Security sandbox violation: file:///C|/Users/Marko/Desktop/Završni/Flash%20documents/Smiley%5FTCP%5FIP%5Fv4.swf cannot load data from 127.0.0.1:9001.
    at Smiley_TCP_IP_v4_fla::MainTimeline/doConnect()[Smiley_TCP_IP_v4_fla.MainTimeline::frame1:12]

TOPICS
ActionScript
12.1K
Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines

correct answers 1 Correct answer

LEGEND , Aug 29, 2014 Aug 29, 2014

127.0.0.1 might be taken over via your HTTP software, I'm not familiar with the tool you're using. It also might have been repointed in your hosts file (in Windows you'll find that here: C:\Windows\System32\drivers\etc). Check to see if anything is overriding 127.0.0.1 (local loopback).

Outside that, I gave you source to a quick AIR server that just opens a listener at 127.0.0.1:8910 so you'd need no other tools to test the client, even though you have one. I just include the source and a produce

...
Translate
LEGEND ,
Sep 14, 2014 Sep 14, 2014

Select all frames, drag 5 frames forward, let go. Flash Pro is your friend. Just make sure you insert a script at the end of the timeline to loop back to the proper frame you choose as you saw me do.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
New Here ,
Sep 15, 2014 Sep 15, 2014

Moved the stuff 5 frames forward and added the end-frame loop, but it seemed to cause some issues with the animation - it would visibly reset (removing any input from the input box, boxes, and putting the smiley in its default state), as well as making an eye-unfriendly white flicker when it does so (due to frames lacking any of the animation visuals, I assume).


So then I moved the frames to be right next to the socket code frame (which caused the frames to look a bit off due to the previous dragging - see the picture below), and tested it again.

Untitled.png

Result: no flicker, no animation reset, and when run, the socket only went once, as well as transmitting the 5 minute message on both ends after 5 minutes, whilst the animation still seemed to function normally with its input box (no resetting). Success!

I think. It's actually weird, shouldn't this be bugging out again? I still have the end-keyframe-loop for the socket layer, and it's set to loop to frame 5 (not 1, where the frames of the animation start), but there don't seem to be any visible issues with the animation or the socket.

Here's are Dropbox links to this "latest" version of the client (and the server, though I didn't mess with it much since last time):

https://www.dropbox.com/s/epa888r2zoutcmw/Smiley_TCP_IP_v6.fla?dl=0

https://www.dropbox.com/s/big6n9otx37ktl1/Server2.fla?dl=0

Assuming there's nothing wrong with the loop, I can now start doing the actual data transfer via the 'send' box in the server and try to convert it within the client for the input box. What are the basic code snippets needed to do that (assuming the 'msg' method isn't feasible)?

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
Sep 16, 2014 Sep 16, 2014

Any frame that has ActionScript on it has a little letter in the frame box. You can see on frame 2 in the Input Box layer, there is some code there. That cod...

The server already has an example of ServerSocket.writeUTFBytes() sending 2 different messages to the client. That's how you do it. You just need to read the text out of the TextField when you press your button, and send it.

e.g. if your TextField was instance named 'tf' and your button was named 'btn', it'd be yet another listener such as:

btn.addEventListener(MouseEvent.CLICK, sendTextF);

function sendTextF(e:MouseEvent):void

{

     // remember I saved the active socket in the array clientSockets

     clientSockets[0].writeUTFBytes( tf.text );

     clientSockets[0].flush();

}

That's it.. The button is assigned a function to fire off when clicked named sendTextF(). That function immediately takes whatever String is in the TextField and writes it via the ServerSocket using the writeUTFBytes() function back to the client. You need to flush() to send it. Done.

Be sure to look at the previously linked ServerSocket and Socket references to see how to send data of different types. You should always use the correct type for your data. In other words, don't send a Number as a String or vice versa and you won't need to perform any type conversion on the data.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
New Here ,
Sep 18, 2014 Sep 18, 2014

After I've discussed the matter of the project with my college professor, it's come to conclusion that the AIR server unfortunately won't be adequate for the connection, outside of testing the thing. The client will eventually have to be capable of connecting to a robot, and the "TCP/IP builder" I've been provided is apparently the "most similar" they've got to it. The AIR server pretty much requires relevant adobe files, and that can't really be put on a machining robot, or requires an extra computer alongside the robot.

So I have to connect the client to that program specifically. Luckily, the connection as it is now, appears to be able to connect to the "TCP/IP builder", and sending data (textbox inputs) results in that data being sent to the compiler's log. Now I just need to have the smiley react to it.

In the picture below, I've connected to the 'builder' (create socket -> listen -> run the client), and sent a text message of "'testing..." to my client, which it received in the compiler.

The other window shown is the "help" window of the builder, indicating how the "send" functionality works, in case that helps.

Untitled.png

Unfortunately, I'm not quite sure what kind/format/type of data I'm sending with that (in relation to flash identifying it, that is), and I can't really 'code' the TCP/IP builder to find out.

If I'm getting messages in the compiler directly from sending, what kind of data type is it, and what code-type is related to it?

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
Sep 18, 2014 Sep 18, 2014

The AIR server was just for testing your local networking. It's definitely not to replace anything you need to use for school. What I was doing was eliminating any 3rd party interference in the socket connection to determine if you had "other issues" with your networking, because we know Flash and AIR will work in sockets perfectly together. There's no question.

Once you got the AIR server communicating with the client, you can throw away the server. We already knew you could connect to sockets.

Your issue was always that you were letting the Flash playhead loop on your main timeline, which hit frame 1, and ran all of the socket connect code over and over. The fix was making sure you did not run that code repeatedly (explaining the constant connect/disconnect/errors).

I'd encourage you to now only use your TCP/IP app to communicate with if that's your target.

Finally to answer you, the help docs should explain what format TCP/IP is sending back. If I were to wager a guess it'd be one of 2 things.

1) Auto-detect. If you put letters and numbers it will write it as a string. If just numbers and decimal, write it as a number (int/double/etc).

2) Always write it as a string.

That means it's up to you on the receiving end to handle the data validation yourself. If you expect a string then just keep reading it how you already are. If you expect a number, you can still read it how you already are but then convert (cast) it to a number.

e.g.

if (sock.bytesAvailable != 0)

{

     // read using socket string mode but convert to integer

     var myInteger:int = int( sock.readUTFBytes( sock.bytesAvailable ) );

     // do whatever you need

}

You can convert from one format to another but if what you received contained anything other than numbers and decimal points the convertion to int() will not work and you will get the value NaN (Not a Number).

Not to overwhelm you but you'll need to work on serialization. That's packaging a bunch of information together so you don't need to send a bunch of data in small pieces. A very common and simple example of serialization is CSV (comma separated values) like "1,2,3,hello,test,999". Sending that CSV string sent 6 values all at once making it more efficient if you have a ton of data to parse all at once. Or if you have sophisticated information to share back and forth, check out JSON and AS3s built in JSON functions for some automated advanced serialization.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
New Here ,
Sep 19, 2014 Sep 19, 2014

Tried adding that particular integer code, ended up with either errors ("use of unspecified variable" and "implicit coercion") , or no effect whatsoever (despite tracing it).

Noticed as well that the earlier socket code had the following for byte reading:

"sock.bytesAvailable > 0" (reads any positive number)

...rather than your new:

"sock.bytesAvailable != 0" (reads any negative/positive number)

Any difference as far as stability/avoiding bugs goes?

So then, I tried something different: Have the program turn the "msg" string variable, into a "sentnumber" number variable. This seemed to work nicely, tracing a NaN for text (expected), or tracing the number of an actual number.

Untitled.png

I also did a few alterations to the input box - it now no longer needs the 'enter' key to do the calculation, it updates the animation after any key release.

Untitled2.png

With all this considered and the requirements of the project, I now have a few goals I want to achieve for the client, in the following order of priority:

1) Have the "sentnumber" number variable be recognized by the inputbox layer, so that it puts it into the input box. So in effect, it goes: Connect -> Send data that is number (NaN's ignored) -> number put into input box -> key press on client makes animation react. I optionally might need a way to limit the number of digits that the animation reacts to (right now it uses 1-3 digit numbers, so if I get sent a huge number, it might cause issues).

- If the NaN can't be ignored (breaks the math/calculus code or some other crash), I need some way of 'restricting' the data it reads to not include NaN's that might be sent.

- Or for simplicity, should I just detect the traced "NaN" output, reacting by setting the number variable to be "0" in such cases?

2) After achieving 1), I'll need to have the process be automatic - not requiring a keyboard presses from the client, but happening instantly once the data is sent during a working connection.

- Can this be done by copying the huge amounts of math/calculus code from the inputbox layer, into the socket layer, right under where I create the "sentnumber" variable, and modifying it delicately?

3) The connection still has some usability and user issues - since the connection happens only once, on frame 1, it only connects if I already have a listening server when I run the client, and client can't re-connect if the server socket doesn't restart itself.

I believe to do this, I need to make the connection happen on demand, rather than once at the start.

For the project's requirement, I also need to allow client users to define the IP / port it's going to connect to (since the only alternative so far is editing the client in flash pro).

In other words, I need to make a "Connect" button and two textboxes (for IP and port, respectively), which do the following:
- On pressing "Connect", the button sets whatever is in the text boxes as the address of the IP and port the socket will connect to, then connects to that address without issues (or with a error message if it can't due to wrong IP/port).

- The connection needs to work for non-local addresses. Not sure if it can yet.

- On re-pressing connect, the previous socket is closed/forcibly ended, then creates a new socket (with new IP/port, if that was altered)

It seems like making the button should be as simple as putting the existing socket code under the function of a button, but it also seems like it's going to cause issues similar to the 'looping frames' error.

4) Optional addition: Have a scrolling textbox like the AIR server has, to track what the connection is doing on-the-fly.

The end result would be a client that allows user to input IP/Port, connects on button press (optionally tracking/display what the socket is doing via scrollbox), automatically alters the smiley based on what numbers are sent whilst the connection lasts, and on subsequent button presses, makes a new connection after closing off the previous one.

Dropbox link to new client version:

https://www.dropbox.com/s/ybaa8zi4i6d7u6a/Smiley_TCP_IP_v7.fla?dl=0

So, starting from 1), can I, and how can I, get the number variable recognized by "inputbox" layer's code? It keeps giving me 'unrecognized variable' errors.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
Sep 19, 2014 Sep 19, 2014

#1, you are the master of the application. You should set up reliable, consistent communication. I think the easiest thing for you to do is "always send a string" from the server and have it be serialized. Make a simple format so when you receive data there is absolutely no question on what to do with it. For example if you're getting a number back it can be as simple as sending the string "i:123" indicating an integer by the 'i'. You could use 'd' for double (float), 's' for String, or more personalized prefixes like 'cmd:something' to know the data is meant to trigger a command, yada. Your imagination is the limits but by prefixing the data you are absolutely certain to handle it correctly.

#2 Flash is Event-based. A keyboard or data being received over the socket are both 'events'. There's no difference if you trigger something to happen based on either of them. So simply use the data handler to fire off the function you want when you receive data rather than or in addition to the keyboard.

#3 That's all you. Make a button that triggers the connection and add a few more TextFields for IP and port. This is all the same stuff you're already doing. If you want more automation to testing network connectedness then perhaps add a Timer that fires every so often to check the connected property of the Socket. If it's not connected when the timer fires off you can try connecting again.

On the final note where you ask "get the number variable recognized by 'inputbox' layers code", I'm not really sure I follow along. Are you asking about a number received over a socket that you added into a TextField you have on the timeline? If so then get the TextFields contents via the .text property, same way you set it.

If you're asking how to get at the number the socket sent over, you just need a global variable (say, set on frame 1: var lastNumber:Number) and then inside the data received function, if you get a number, you can set that global variable just by doing: lastNumber = Number(msg); and the value will be available globally in your Flash app. If you start making a ton of global variables, it's better to make a single object to hold the values rather than littering with global variables. e.g. on frame 1: var settings:Object = {}; then when you get data: settings.lastNumber = Number(msg); and just append any other properties to settings that you want. settings.lastString, settings.totalReceivedNumbers, settings.iLikeTacos, etc.. Keeps it all clean.

You know enough where I don't need to jump in your FLA to do this for you. You already know enough with what you've done to get the rest of this done anyhow. You just distrust yourself . Get in there and get your hands dirty. You'll need to when it's your job.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
New Here ,
Sep 24, 2014 Sep 24, 2014

I kept fiddling with it, and got everything from "1)" and "2)" to work as I want it (sent data is responded to automatically, it identifies NaN or numbers larger than 999...) but I hit a new snag with the looping as I went to make the button.

What I did was I added textboxes for IP/Port input on the left, textboxes for output on the right (displays what Port/IP you've inputted), as well as a button symbol to connect to the socket (and read the text boxes), all on the socket code's layer, as shown below:

Untitled.png

Dropbox link for file reference:

Dropbox - Smiley_TCP_IP_v9.fla

My new problem is this: the button only functions 'properly' for the first few seconds (before first animation/timeline loop) - afterwards, a new loop happens, the button stops working (both for connecting and the IP/Port text boxes), and any text in the IP/port boxes clears (and keeps clearing with each loop). This happens with the "GotoAndStop(5)" command I've added to the final keyframe, to fix the old loop issue.

So how do I fix this new loop issue? I need the button (which now does the socket connection + IP/Port textboxes) and text boxes to not loop or reset with the rest of the animation, remaining functional (and the connection stable) regardless of loops.

- I tried adding a stop() to the end keyframe, but that just makes the button and text boxes in the layer to vanish.

- Changing the gotoAndStop command to frame 1, or removing the command, just makes it have the same infinite loop issue I had before.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
Sep 24, 2014 Sep 24, 2014

Let's play a bit of cleanup here. You have code on frames where symbols exist. To make it simple, make a new layer and name it 'code' or 'actionscript'. Do not put anything but frame scripts on that layer. Now move all the frame code you have into the same frames on that layer. That alone should feel much cleaner. Lock the layer so you don't accidentally try to put a symbol on it.

After you do this your problem with the inputs disappearing can be solved by making sure the inputs do not stop at frame 84 when you're looping on 85. What's happening here is since your objects are missing from the timeline, Flash is literally disposing them completely. You then loop back to frame 2 and it's as if those controls never existed and they get reinitialized via the frame script on frame 2. That may sound good, but it's not.

You have the same issue going on here. You're looping back to a frame which contains code in a frame script. The reason you're already looping to frame 2 is so the code on frame 1 is not executed every time you loop. That's exactly what you're doing looping to frame #2. You're running that code over and over.

After you stretch the symbols on the "Socket" layer to frame 85 so they always exist, adjust your last script to loop to frame #3, where there is no code. So gotoAndPlay(3);. That should be enough to keep you moving for now.

Your timeline should resemble this at that point (do note you have a broken tween on the Smly Body layer, no keyframe at the end, the dotted line tells you that):

timeline.png

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
New Here ,
Sep 24, 2014 Sep 24, 2014

Not sure what you mean exactly by "Frame code": all the code from frame1 of "Socket" + frame2 of "Input Box", or just the loop command at the final keyframe?

If it's the full code, won't I get errors ("referenced unspecified X") because the referenced symbols (buttons/text boxes) and code using it are on different layers? I know I had some difficulties with such for the 'eyes' of the animation (needing to add layer/object/frame names as a prefix)...

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
Sep 24, 2014 Sep 24, 2014

There's your disconnect. Flash is a lot more "global" than you may think with code. Any code placed on frame 1 is available (in the same scene) from frame 1 to 999999(...). Otherwise the socket code on frame 1 would no longer work as soon as you hit frame 2.

No, you do not need to have the code on the same layer as the objects you interact with. A "frame script" is code you place in a keyframe. You can add keyframes anywhere on the timeline and all of those scripts (like in the picture above on frame 1, 2 and 85) are all "frame scripts". This is as opposed to you writing all of this code in a separate file (something advanced Flash developers always do). Flash supports both. You can place code on your timeline, or keep it in external files. For most simple applications like yours it's perfectly fine to use frame scripts.

So feel free to add as many layers as you like and separate out your corresponding elements. Rest assured the code you write in frame scripts can access anything in that frame as long as it is on the timeline. So keeping a dedicated layer for just scripts is a common practice.

Where it will get complicated is if you start putting scripts inside nested elements. Then you need to dig through complex symbols containing even more symbols to find code and it makes it a bit of a nightmare to debug. So try to keep all your code on your main timeline.

Lastly, frame scripts only execute when you're on the exact keyframe they appear in. So even though there's no keyframes between the script on frame 2 and 85, the script on frame 2 will not execute again from frame 3 to 84 (85 has a script on it). It will only execute directly on frame 2. That's why I said to gotoAndPlay(3), so the code on 2 is not run again and again when the animation loops.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
New Here ,
Sep 25, 2014 Sep 25, 2014

Works like a charm, and the text boxes now alter the IP/Port for the connection as well. There still aren't any 'closed connection' messages, but the client still seems to work fine with just connecting to new/same sockets. Thanks very much for your patience!

borat.png

I'm pretty much done with the thing (so far - will probably have much more to do for the robot itself when my project lead looks it up...), though I still want to know two things:

1) What's a good way to test this socket for non-local/online connections? E.g. having the .swf run via Firefox, to myself (my TCP/IP builder - it won't do the 127.0.0.1, connection, need another address), or via Firefox to some reliable online address for testing these sockets.

2) How do I code in a scrolling textbox that pops out like a new window when I press 'connect', and automatically displays anything the flash compiler displays (including errors & trace messages)? It's so I can keep track of the connection's trace messages without having flash pro (e.g. when run via Firefox), and to make a simple 'help' window button with relevant instructions for any users.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
Sep 26, 2014 Sep 26, 2014

Local connections are going to follow known LAN naming schemes. 10.0.x.x, 192.168.x.x or as you said 127.0.0.1 so it should be easy to search the IP being entered for anything in LAN range. Either just simple string comparison (using substr(ing) or regular expressions, a whole different topic I'll avoid for ease).

e.g, add a TextField to the stage and give it the instance name of "status_txt".

status_txt.appendText("\n" + bIsLocalIP('1.2.3.4')); // false (not local)

status_txt.appendText("\n" + bIsLocalIP('8882222.2218789712.872872.625462')); // false, even if junk

status_txt.appendText("\n" + bIsLocalIP('192.168.0.1')); // true (local LAN, almost always your router)

status_txt.appendText("\n" + bIsLocalIP('10.0.0.255')); // true (local LAN machine)

status_txt.appendText("\n" + bIsLocalIP('127.0.0.1')); // true (localhost)

// return true or false based on if the IP is local

function bIsLocalIP(ip:String = ''):Boolean // properly type the response expected

{

  // no IP given, return invalid immediately

  if (ip == '') return false;

  // simple substr string tests, season to taste

  status_txt.appendText("\n" + 'Testing bIsLocalIP(' + ip + ')');

  // 10.0.x.x? 192.168.x.x? 127.0.0.1?

  if (ip.substr(0,5) == '10.0.') return true;

  else if (ip.substr(0,8) == '192.168.') return true;

  else if (ip == '127.0.0.1') return true;

  // no need to even validate a valid 255.255.255.255 IP,

  // it is not local so:

  // no matches, return false

  return false;

}

That said, to my knowledge there is no way to get access to the clients actual local LAN IP without using AIR, which means you'd need to convert to Apache FLEX to get it working in a browser. Flash Pro AIR only exports to desktop applications (.air or captive runtime/installer .exe). If you use AIR for Desktop you can use flash.net.InterfaceAddress, NetworkInfo and NetworkInterface to get all local NIC card information. See this Adobe article with a sample AIR script for iterating over the local NIC interfaces.

On #2, I just used a ScrollPane component with a fixed width multiline word wrap TextField inside it in my server example. You can see the component and code used to put the TextField inside it in there. At that point the ScrollPane will only scroll when the content inside it exceeds its bounds.

The ScrollPane should have an instance name. You could easily set the .visible property to false on the whole ScrollPane. Then make a button simply toggle the ScrollPane's visibility on and off. Just make sure it's on the top layer so it's not covered.

e.g.

myBtn.addEventListener(MouseEvent.CLICK, toggleLogPane);

function toggleLogPane(e:MouseEvent):void

{

     // say the instance name of ScrollPanel is sp_com

     // set the visibility of it to the opposite of what it is

     sp_com.visible = !sp_com.visible;

     // enable mouse events/selection based on visibility (it's all just booleans)

     sp_com.enable = sp_com.visible;

}

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
New Here ,
Sep 26, 2014 Sep 26, 2014

You kinda got me completely lost on the browser connectivity - where do I even start for such a conversion?

I'm starting to worry that the client won't be able to run on computers without AIR-identifying adobe tools or similar stuff (outside of flash players) - my project lead doesn't have most of the Adobe programming tools or applications (for example, he can't run the AIR.exe server we used earlier, nor could I before I installed the flash pro and such), and like me, has limited knowledge of how the stuff works, and he has to be able to see the results (he couldn't connect to anything when I sent it to him, though the smiley worked otherwise).

In other words, I need the client to be able to run on a computer's browser (or just on the desktop via a desktop flash player, but still connecting to online sockets), without needing to have costly or difficult-to-download-and-install adobe/AIR tools pre-installed to run it properly. This excludes common or simple stuff like the flash player, though, or other simple 'file reading' stuff that's simple/free to install.

Can my current client do that (after tweaking the code appropriately), and what's the simplest way to achieve such?

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
Sep 26, 2014 Sep 26, 2014

Yes, the SWF itself (without AIR) can connect to any IP/port whether it's localhost, LAN or on the internet. Here's the thing you need to keep in mind. Flash is sandboxed. It requires permission to connect to any kind of resource that is not on the same domain it's running from and is set to the network sandbox. Make sure you don't have your client set to "Local with Filesystem" in the publish settings. Here's a pic:

client.png

Highlighted in yellow is Local playback security. Make sure you have it set to "Access network only" or you will be restricted from socket use.

A Socket policy is required to connect however. Even on the same host. From the docs:

In Flash Player 9.0.124.0 and later, a socket policy file is required for any socket connection. That is, a socket policy file on the target host is required no matter what port you are connecting to, and is required even if you are connecting to a port on the same host that is serving the SWF file.

Consult the linked references for Adobe code examples of connecting and what socket policy files look like:

Adobe Flash Platform * Loading data

A SWF itself is nothing without Flash Player. That's the runtime Adobe created to play SWF content.

AIR is a completely different runtime that has far more capabilities than Flash Player For a user to run your AIR content they must have the AIR runtime installed, same as SWF needs Flash Player. However, just like you can create a SWF projector .EXE that runs with an embedded Flash Player, you can create an AIR .EXE that installs the Adobe AIR runtime (called a Captive Runtime) in the users system.

The main reason why I'm even mentioning this is, again from the Socket reference:

In AIR, a socket policy file is not required for content running in the application security sandbox. Socket policy files are required for any socket connection established by content running outside the AIR application security sandbox.

So if it's ok with your teacher, you can just flip the target to AIR and make sure you choose to export your client as a self installer .EXE with AIR embedded in it. Then your teacher does not have to have anything pre-installed. Here's a pic of AIR publish settings and the required choice:

clientexe.png

That will generate a complete product, AIR runtime included with a self installer. No pre-requisites. Also the great added advantage of all of Flash's capabilities, but AIRs as well. Including the freedom to use the Socket class without requiring a server socket policy file. Something to consider if you can't figure out how to send the policy file from the target you're connecting to.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
New Here ,
Sep 29, 2014 Sep 29, 2014

Added the scrolling log and the help-window, working nicely.

Made the thing into an AIR installer, and installed it, and it runs normally... However, it still can't seem to connect, even when I try a local connection on the TCP/IP builder (127.0.0.1 / 8888) - it doesn't provide the usual error messages for a failed connection either. Not sure if I'm doing something wrong...

- Using a wrong/invalid address?

- Messed up the AIR conversion?

- Still need some security file?

- Interference from Security.allowDomain() in the code?

Dropbox links to the .fla and the AIR installer below.

https://www.dropbox.com/s/wl88dbknoamxjx1/Smiley_TCP_IP_v11.exe?dl=0

https://www.dropbox.com/s/9b27ub6vr1jld5c/Smiley_TCP_IP_v11.fla?dl=0

Dropbox - Smiley_TCP_IP_v11.p12

Password for the .p12 is 'jimmy', I believe.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
Sep 30, 2014 Sep 30, 2014

You're getting out of my comfort zone unfortunately. Flash via SWF or AIR are both showing you that they're working perfectly fine. In fact you can make any other kind of app that talks to sockets, read and use the spec (FTP, Telnet, HTTP, etc), as I have, and use other software to connect to your AIR server and you will have no issues. I made a generic HTTP server on port 80 with AIR a while ago just to learn some of the HTTP spec, as well as a telnet server on 23, and both worked with a browser and putty telnet client. So I know AIR works and requires nothing special. Your SWF is proving that to you which communicates with it.

What I see a lot of here is you mentioning the TCP/IP client always causing trouble. While some of it works you always end up getting snagged by it. So either you have some other simple fundamental issue like the past issues we solved or that TCP/IP app isn't playing nicely. I don't want to install anything on my system (even if Microsoft if the author) that intercepts my TCP/IP streams. So I can't help you diagnose that one specific app.

All I can say is AIR works, doesn't require socket policy files and SWF proved it communicates just fine. You can set it to listen on port 21 and use a FTP client to connect to it and just spit out the data it sends, or 23 for a telnet client, or 80 for a browser. The AIR server will accept the connection and (depending on the protocol) it should spit out information, or wait for you to send a properly formatted response for the spec.

I also would try to stick with your actual LAN IP as much as possible to get around any TCP intercepting apps from snagging your communication on local loopback (e.g. don't use 127.0.0.1).

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
New Here ,
Oct 02, 2014 Oct 02, 2014

I think the socket security is what's causing the troubles. When I run the smiley on browser (as a .html) and try to connect to the builder (on a local IP/port), I get the following sent to the builder:

<policy-file-request/>\0

As far as I understand it, the client does connect, but is then requesting a policy file before it can proceed, which I'm fairly certain can't be sent with the text box the builder uses, unless there's a set of string messages the client can 'identify' as a policy file, or some settings I can put into the client that makes it accept 'anything' sent to it (e.g. gibberish text) as a valid policy file, or that auto-sends its own policy file to itself, negating the need for the other party to send a policy file.

Assuming the above can't be done, I might have to try with turning the whole smiley into a server (and have the builder act as a client instead), but I'm not sure if it would have the same result (builder unable to send/show policy file to server, even if it allows any)...

The AIR sever, on testing further, gives no responses to anything I tried to connect it to.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
Oct 02, 2014 Oct 02, 2014

That is correct. As I explained above (or a page ago), a SWF needs a socket policy file. You can see the SWF requesting it as soon as you establish a connection. Read the page I linked previously for an example of a socket policy file. It has no special encoding, it's just plain text. If you can have your tool auto-send that text on connect back to Flash with the proper settings as outlined in the example page then the SWF will dutifully accept the connection. Then you're free to transmit away.

The AIR (installed) client will not send anything upon connect (like a policy request). It doesn't need to. It's an application so it already has the sandbox restrictions removed from it. Once you connect, nothing will happen. You would need to send data to the AIR server for it to respond (of course having the code in place in the AIR server to read that response and do something with it).

It seems you're telling me that you did in fact make an AIR server, are connecting to it using your TCP/IP tool and any data you send to it is being ignored by the AIR server. Is that correct? If so, I'd make sure the connection still exists (I don't know if your tool indicates that or not).

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
New Here ,
Oct 02, 2014 Oct 02, 2014

I didn't make a AIR smiley server yet, just have the 'client' of it installed (basically what you get when you publish the .fla as it is now), and the previous 'server2' used to test the stuff before.

The AIR-smiley-client (which I run as an .exe on the desktop) doesn't connect to the builder (no responses/reactions, can't send data), not sure why. Tried both the 127 IP and the actual local IP with no result.

You say that AIR doesn't need a security file, tho the socket info page says this about AIR's security:
"In AIR, a socket policy file is not required for content running in the application security sandbox. Socket policy files are required for any socket connection established by content running outside the AIR application security sandbox."

What counts as part of the AIR app security sandbox? I don't think that running the AIR as a desktop .exe, then connecting it to a non-adobe program (the TCP/IP builder) counts for that.


The TCP/IP builder sadly doesn't have any 'auto/macro response' stuff (it's just for testing), but will try and see if I can manually text a security response to get the connection working. Then I'll see if I can make the smiley into a server rather than a client...

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
Oct 02, 2014 Oct 02, 2014

The sandbox is mobile desktop extendedDesktop, etc. You should be using desktop or extendedDesktop (all out access) so no policy file is needed. I use desktop.

That said I finally just broke down to show you there's no issue with AIR receiving sockets and data from TCP/IP Builder. I downloaded it off c|net download.com so I sort of trust it, against my better judgement .

I ran an AIR server on 127.0.0.1 port 8910 that would auto-greet with a "Connected." string. It then echos strings back to the client. The one addition I made is sniffing out possible numbers. I use a very simple regular expression to look for data that ONLY contains numbers, commas and decimal points. Although I don't actually validate the number is correctly formatted or a legit number, it just must only contain any of those 3 (and I demonstrate that). Here is a picture of the received data which you know is cleared after I disconnect:

TCP/IP Builder Received Data:

receive.png

I see this thing doesn't even word wrap so it's a pain to test with but you get the general idea. It sends "Echo string" when it senses any data that is not just numbers, commas and decimal points. But when I sent only 123,456,789.10 it sent back "Number echo" because that's a number. Just showing you how you can detect numbers (but my code needs a lot more validation, it's just the point).

Now here's the code, AIR client and TCP/IP Builder next to it. I forgot to run update() on the scrollpane so I couldn't see the bottom text haha. Oops, doesn't matter, point is proven this TCP/IP Builder and AIR have no problem talking back and forth. The screenshot has the "Receive data" portion clear because it does that when I disconnect, and I wanted you to see me disconnect and have AIR sense it and output the disconnect in the log:

tcpip.png

This is just me writing a string and disconnecting essentially. And there you see in the AIR log that I pressed destroy socket and the socket was closed.

So there it is, an AIR server working perfectly fine with your TCP/IP app. Consider just using AIR to get around the socket policy file, or find a way to send a valid policy file automatically on connect. The Flash/AIR side of it works perfectly fine. My number sniffing code is in the screenshot, again, a very poor and simple regular expression match example.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
New Here ,
Oct 03, 2014 Oct 03, 2014

Remodeled the smiley to be a server. Don't think I need the number sniffing for now, since I already got the smiley to turn sent strings, NaN's and numbers into specific values.

Dropbox link:

https://www.dropbox.com/s/g7qogkox34o4t8v/Smiley_TCP_IP_server_v12.fla?dl=0

Testing it on desktop with AIR finally had it working with the TCP/IP builder (127.0.0.1 and random ports) - it properly connects and sends messages between each other, tracks a 5 minute timer successfully, the smiley responds properly for sent messages, and most activity of the connection is logged on both side. Should be okay for my project lead to try it out, though there are other issues with browser use and the socket itself. 


- If I run the .swf or the .html I get from publishing it, on a browser (firefox), it runs normally until I enter a IP/Port code and press connect - then it freezes/crashes, displaying a blank screen on switching windows/tabs, and stays that way until refreshed/reset. I tried entering the 127.0.0.1. IP and my actual local IP, with random ports (400, 500, 80...) for this, both causing crashes. What's causing this?

- There appear to be some lingering connections left by the server. I get an AIR error when I attempt to re-connect to the same socket, and sometimes after trying to connect to a socket I disconnected from on the TCP/IP builder (I get the message of 'connection closed' in the server). Obviously, the connection isn't closing on the server side. I tried to enter in the close():void command as the first command after the button is pressed (so that the button press cancels the previous server socket, then re-initiates new one as normal) to fix it, but I keep getting the "Label must be a simple identifier" error.

What's the proper command/syntax to get it to close/remove the server socket (so that it can be 'reused'), and how do I get the same command to run when I forcibly exit/close the server application?

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
Oct 03, 2014 Oct 03, 2014

I got the same issue and I think it has nothing to do with AIR. AIR doesn't care what port your socket starts on and is properly telling you that it closed the connection. I think TCP/IP Builder is actually at fault here since I also had to chance my local socket sometimes. I noticed that during rapid code changes, stop and restarting it all. But it didn't happen instantly.

However another reason could be that garbage collection in Flash/AIR isn't forced. Just because you close/null a socket doesn't mean it's instantly garbage collected and thus persists in memory until the next reference sweep. You can attempt to ask Flash/AIR to garbage collect by running (flash.system) System.gc(); but it's still only "asking" for garbage collection, it isn't guaranteed:

System - GC - Adobe ActionScript® 3 (AS3 ) API Reference

So who knows which side the problem lies on.

As for the browser freezing, that must be an unhandled exception. Every time a SWF goes unresponsive it's almost always an unhandled exception. If you have a general idea where the error is occuring, surround it by try {} catch() {} blocks and see if an error is caught. e.g.:

try

{

     // code that might fail here

}

catch (e:Error) // catch a generic error

{

     // visually display the error in the 'e' event object.

     // check the e.type and further investigate whatever

     // type by replacing e:Error with the proper type, like

     // e:SecurityErrorEvent. Then explore that 'e' event

     // for better details on the exact error

}

By doing try/catch you're letting your code fail, catching it and can handle it rather than lock up.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
New Here ,
Oct 07, 2014 Oct 07, 2014

I have no clue where the error could be (besides 'within the button'), or what it is.

Could you elaborate further on the 'catch' part? I don't know how to visually display the error(s) before it freezes. It just runs normally when run in the flash tools, and freezes on the browser (tested via 'publish preview' as html), giving me no info whatsoever.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
Oct 07, 2014 Oct 07, 2014

That's where you'll find yourself often when you learn to program. You learn to set up code in ways that will give you hints where it's failing.

That said, if you don't need to debug in the browser and you can debug directly from Flash Pro (CTRL+SHIFT+ENTER) then the error will show up in the debugger along with all variables in memory at that time, a line of code that caused it and much more useful information. This is where you can learn to use breakpoints too but that's another discussion.

If you must debug in the browser then you must install the browser debug versions of Flash Player or just visually give yourself something to see in the browser with useful info about the error you caught.

try/catch is a very aggressive way of debugging. It's asserting that you think the code in the try { // code here } block may fail. If it does, that's where catch (e:Error) { // code here } comes in. It's just as you would say it in English. Try 'to do this' but catch any error 'and do this'.

Where to use try/catch is up to you. It's just one of many tools in the ActionScript toolbox. I'm sure you know networking is a real pain because it can bring an application to its knees or crash it completely. How many times have you tried to access a network drive you mapped but it wasn't on or responding. Windows halts windows explorer to this day with no way to stop windows explorer. You watch it helplessly for 30 seconds struggle pointlessly to connect only to report what you know. The drive is offline or inaccessible. The point here is, explorer will crash if there is no error handling involved when it can't access that network resource, but they added error handling and a dialog I'm sure you've seen, simply reporting it can't connect. Not why or "what failed", it just can't connect.

It's up to you to do what "you want" when your application fails, AND, up to you to provide fallback to all your code in the event something doesn't work. That doesn't mean you literally wrap everything in a big try/catch, but start adding them in places you know it freezes. For example during socket connect, disconnect, data events, a specific button is pressed, etc. Every one of those things already has event handlers on them. Start wrapping the code in them with try/catch.

If it wasn't clear from what I just said or the code comment in the example I gave above, the catch (e:Error) { // code here } portion is where you put "what you want to do" when any kind of error happens. You should write the error to the screen so you can visually see it. If you're adding to a scrollable TextField then dump that error in there. Once you have a try/catch hit a failure and the catch fires off, you know where your problem is. Start adding in more try/catch either nested or as siblings in the code. For example:

// wrap a bunch of lines that belong together (like all socket code, etc)

try

{

     // code line 1

     // code line 2

     // code line 3

}

catch (e:Error)

{

     // say somewhere in those 3 lines it failed and add the error itself

     someTextField.appendText("\nFailed in code block, error: " + e);

}

So say that catch block fired off and you added text on screen to see that error happened. Now you know one of those 3 lines is a problem but you don't know which. Now you can add in more try/catch like so:

try

{

     // code line 1

}

catch (e:Error)

{

     // ok so line 1 was the issue..

     someTextField.appendText("Failed on line 1!");

    

     // stop running the function this code is in by returning early

     // (no code below will execute)

     return;

}

// ok I got here so line 1 didn't break, try 2

try

{

     // code line 2

}

catch (e:Error)

{

     // ok so line 2 was the issue..

     someTextField.appendText("Failed on line 2 of code!");

    

     // stop running the function this code is in by returning early

     // (no code below will execute)

     return;

}

// etc for line 3...

This can be tedious but if you have very rare or hard to track down issues, this is one way to go about it.

First try a bunch of code and if any of it fails, start singling out parts of the failing code until you narrow it down right to the exact point of failure.

What's important here is if the code is running in a function that's not vital to your applications function then you can just return; from that function and your app can warn you of the issue and it doesn't freeze. You can see here I put the return; statement in right after I warned if the block of code or even which line number of code was failing. This is just general, albeit time consuming debugging.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines