I write a piece of software that runs inside banner ads which generates millions of session IDs every day. For a long time I've known that the random number generator in Flash is't random enough to generate sufficiently unique IDs, so I've employed a number of tricks to get even more random numbers. However, in ActionScript 2.0 it's not easy, and I'm seeing more and more collisions, so I wonder if there is something I've overlooked.
As far as I can tell the problem with Math.random()
is that it's seeded by the system time, and when you have sufficient numbers of simultaneous attempts there are quite a few collisions.
In ActionScript 3.0 I use the value returned by System.totalMemory
as a bit of extra randomness, but there's no equivalent in ActionScript 2.0. AS3 also has Font.enumerateFonts
, and a few other things that are different from system to system.
What I need isn't something perfectly random, just something that is random enough to dilute the randomness I get from Math.random()
. Think of it this way: there is a certain chance that two people will generate the same random number sequence using only Math.random()
, but the chance of two people generating the same sequence and having, say, the exact same list of fonts is significantly lower.
I cannot rely on having sufficient script access to use ExternalInterface
to get hold of things like the user agent, or the URL of the page. I don't need suggestions of how to do it in AS3, or any other system, or server side, only AS2 -- using only what's available in the standard APIs.
On the server side I also add the IP address to the session ID, but even that isn't enough (for example, many large companies use a single proxy server and that means that thousands of people all have the same IP -- and since they tend to look at the same sites, with the same ads, roughly at the same time, there are many session ID collisions). Doing more on the server side is, for various reasons, not practical. I can, for example, not generate random numbers on the server side and send them to the client, even if I very much would like to be able to solve it that way.
The best I've come up with so far is to use the list of microphones (Microphone.names
), but I've also tried to make some fingerprinting using some of the properties in System.capabilities
, I'm not sure how much randomness I can get out of that though so I'm not using that at the moment. I hope I've overlooked something.
I'm sorry to come off as arrogant in my comments to your answers, but please, if you don't know A开发者_运维百科ctionScript 2.0, or know how a pseudo random number generator works, don't try to answer, it won't help and I will give downvotes. I really appreciate proper answers, though.
I think you are over thinking it and trying to be too "tricky"!
What you are after is a GUID (globally unique identifier). Basically you need a longer number, and it would help if used letters as well.
There are already a few classes and scripts out there for generating a GUID in AS2, but Adi Reddy Mora's one from www.designscripting.com is really good.
P.S Lets do the math! Math.random spits out a float with an precision of 15 decimal places. That is a huge number. That works out to a one in one thousand billion chance of two people getting the same number (if it was a truly random number, but even half of that is a pretty slim chance). On the other hand, any of the other methods you mentioned would have considerably less variation. Such as basing it off the users font-list. What are the odds that two people have the same fonts install? I would say close to 1:20, because most people use windows and only have the default fonts installed!
It's been a while since I've last coded in AS 2.0, but following the System.totalMemory idea, a possible approach could be measuring performance and / or connection speed. This have some variation from system to system, so perhaps if you combine a few of these values you can randomize Math.random further.
I'm thinking along the lines of something like this:
var init_ms:Number = getTimer();
var dummy:LoadVars = new LoadVars();
dummy.onData = function(success:Boolean):Void {
trace(init_ms);
trace(getTimer());
var elapsed_ms:Number = getTimer() - init_ms;
trace("elapsed_mc: " + elapsed_ms);
}
dummy.load("http://www.example.com/dummy");
var counter:Number = 0;
this.onEnterFrame = function():Void {
counter++;
if(counter >= 20) {
var elapsed_ms:Number = getTimer() - init_ms;
trace("elapsed_mc: " + elapsed_ms);
this.onEnterFrame = null;
}
};
I don't remember exactly how cross domain policies work in AS 2.0, but I think the code above will at least try to download the crossdomain.xml; Not sure if you'll be allowed to load external content from a banner, though.
The other one could also give you some randomness, since the time elapsed between frames is not all that precise and has some variation from machine to machine and even considering the same machine.
Hope this helps.
I think that chances of two people ending up with the same seed for random() sequence is negligable. Adobe doesn't disclose the method used, but if they use system clock (as you suggest), that should ensure that the collisions are truly rare (number of milliseconds since January 1, 1970 0:00:000 should be pretty damn random).
If you're getting collisions anyways, I would start looking at the rest of the algorhythm that crunches the number that random() spits out and look for randomness-reducing operations there. It doesn't help that random() returns 1 in 2 billion number if your algorhythm maps it to a 1 in 10 domain, for example. If you provide some more info about what your algorhythm is doing, maybe I could be more specific.
Also, number of fonts, microphones or things like that are surely a number of orders of magnitude less random than the value returned by random().
There are, as far as I can see three possibilities:
- Implement and use another pseudo random number generator algorithm so that the seed can be specified (but then the question is how to seed it properly, the system time probably isn't sufficient). There's one called Mersenne Twister that is supposed to be good.
- Use all possible properties like screen resolution, microphone names, etc., and generate a fingerprint by adding and multiplying their characters and character positions. This will, hopefully, yield a somewhat unique number, that in combination with
Math.random()
be sufficient. - Exploit the timing properties of the client, for example, set a timeout for X milliseconds and measure the actual delay, which will be dependent on the circumstances. It might be enough if combined with
Math.random()
, or it could be used as a seed for a custom generator.
If I understand your question correctly, you don't want a random number but a unique id for each pc. Have you considered the MAC address of the network card ?
I don't know if you can get it in AS2, but that will give you a unique id for each machine.
Maybe? another idea would be
Math.random() * Math.random()
? Or
Math.random().toString() + (Math.random() * Math.random()).toString()
don't know, just an idea ...
精彩评论