Project Title: AS3 Networking System
Development: AS3 / AIR
My Role: Network Programmer
This project initially began when there was a necessity for a local networking system to be built within a number of legacy AS3 projects. Having worked a bit with networking in C++, C#, and Java, AS3 was not exactly the ideal language to implement a system within. However, without knowing much about the potential for AIR sockets, I opted to take the challenge an upgrade some of the older networking systems for various projects to a more streamlined version built from scratch.
AIR offers a few different sockets for local networking. ServerSockets act as the primary Socket for receiving and managing connections. Sockets are a more generalized version best applied for Clients seeking to connect to a primary Server. DatagramSockets allow for UDP networking, and are optimized for runtime applications, which can include games and interactive experiences. Within this particular networking system, given the necessity for intermittent data transfers, I opted to begin with ServerSockets and Sockets with a TCP basis, and seek to incorporated DatagramSockets as an optional parameter at a later time.
The architecture was built around having applications simply add a Server or Client object based on their given identity, which means the implementation only requires the applications to utilize the object's static EventDispatcher to send and receive data messages. As a result, the actually process for both the Server and Client are very similar, with the only difference relating to the Server's requirement for distinguishing between Clients upon sending and receiving data.
The Server object in particular is responsible for listening for ongoing Client connections and disconnections, managing known ClientSockets, and sending and receiving data from specific Clients. When data is received from any source, the socket is matched to a known ClientSocket, and the Server parses data based on the ByteArray received. It does this by simply acquiring the network message type and length from the start of the ByteArray. Depending on the length of the expected message, it will then create a new NetworkMessage, and read data until the length requirements are met. This ensures that data requiring several event retrievals, or corrupted data, can be caught and managed accordingly. Once complete, the data received can be simplified, and dispatched with its network message type, network message ByteArray, and corresponding Client UID.
When sending data out to Clients, the Event_ServerNetworkMessage takes a network message type, network message ByteArray, and Client UID in order to transfer the data to the correct Client. The network message type is simply a user defined enum to determine how the application needs to handle data when received, which conveys how to deconstruct the ByteArray. If no Client UID is provided, the Server will automatically send the message top all active Clients, which can assist with simplify the process of universal notifications.
The Client object essentially just simplifies the Server's methods, as it only ever needs to handle data transfers from the Server. The Event_ClientNetworkMessage works in the same manner, including a network message type and network message ByteArray. However, it does not require a UID, since it is always determined to submit the data to the Server. Furthermore, on retrieving data, it parses its data and creates NetworkMessages in the same manner. However, while the Server manages a collection of ClientSockets, the Client only needs to worry about parsing data from one source. Therefore, when reading and resolving data, it does not include UIDs in the same manner that the Server would provide.While the application can receiving and manually handle network message types by listening for the Event_ServerNetworkMessage or Event_ClientNetworkMessage, I've also included NetworkMessageManager classes to automatically decouple messages for the application. These classes have minor differences for the Server and Client, which is mainly due to the inclusion of the client UID in the NetworkMessageManager_Server class. The NetworkMessageManager classes allow for a collection of NetworkMessageCalls to be initialized at the start of the application. Each NetworkMessageCall incorporates a network message type, as well as a callback function. Each callback function takes a network message ByteArray to be parsed depending on the message type received, and the Server version also includes to client UID to determine which connection has sent the data.
Overall, this architecture underwent several revisions in order to refine the internal functionality. With large data transfers, stress testing was required to make sure the system would be able to handle packages received in several parts, as well as packages received that have been automatically flushed and compressed together. This is largely how the parsing system came into existence. I also added functionality to allow the application to determine when data should be send immediately, or when it should be held for a later flushing period. This is helpful in situations for small amounts of ByteArray data is being constructed, and there is not a necessity for releasing it individually.