Sessions

FIX Antenna .NET Programmer's Guide
Creating Session

To create a session, call the following method:

FixEngineCreateSession

See the example below:

Session session = FixEngine.Instance.CreateSession("SenderCompID", "TargetCompID", FixVersion.FIX44);

If your application is going to create several sessions with the same Sender/Target pair, you first need to create com.b2bits.FIXAntennaSessionId object with unique identifier as 3rd argument of constructor and then pass it to FixEngineCreateSession

See the example below:

SessionId sid = new SessionId("SenderCompID", "TargetCompID", "Q1");
Session session = FixEngine.Instance.CreateSession(sid, FixVersion.FIX44);
Note Note

FixEngine should be properly initialized before you will be able to create a session. See FixEngine

Releasing Resources

By default resources assigned with all sessions are released after FixEngineStop. To dispose resources of the session implicitly, call the SessionDispose method.

Session session = FixEngine.Instance.CreateSession("SenderCompID", "TargetCompID", FixVersion.FIX44);
// ...
session.Dispose();
Establishing Session as Acceptor

To establish a session as an Acceptor, use the SessionConnectAsAcceptor method.

// FixEngine must be initialized before
Session acceptor = FixEngine.Instance.CreateSession("SenderCompID", "TargetCompID", FixVersion.FIX44);      
acceptor.ConnectAsAcceptor();
Note Note

Sender and Target IDs are strings that will allow to distinguish different senders and targets in your application. You can use any notation you like (for example it can be workstation name or GUID), but you should ensure that if you create more than one session, they should have different Target or Sender IDs

Establishing Session as Acceptor on Demand

If the CreateUnregisteredAcceptorSession parameter is switched on and the event listener is registered for the FixEngineUnregisteredAcceptor event, a session-acceptor will be established automatically, when a remote FixEngine is trying to establish a FIX session. If the mode is switched off, the connection with a remote FixEngine will be closed without establishing a session.

See also com.b2bits.FIXAntennaFixEngineUnregisteredAcceptorHandler

// Event Listener
class AcceptorsListener
{
    public void OnUnregisteredAcceptor(Object sender, FixEngine.UnregisteredAcceptorArgs e)
    {
        Console.WriteLine("\nOnUnregisteredAcceptor: " + e.Session);
    }   
}

AcceptorsListener listener = new AcceptorsListener();
FixEngine.Instance.UnregisteredAcceptor += new FixEngine.UnregisteredAcceptorHandler(listener.OnUnregisteredAcceptor);
Establishing Session as Initiator

To establish a session as an Initiator, use the SessionConnectAsInitiator method

See the example below:

FixEngine.Create("engine.properties");  // initialization
string sender = "Acceptor's CompID";
string target = "Initiator's CompID";   

Session acceptor = FixEngine.Instance.CreateSession(sender, target, FixVersion.FIX44);
acceptor.ConnectAsAcceptor();

Session initiator = FixEngine.Instance.CreateSession(target, sender, FixVersion.FIX44);

string host = "localhost"; // remote FIX engine's host name
int port = FixEngine.Instance.ListenPort; // remote FIX engine's port
int heartBtInt = 30; // Heartbeat interval (in seconds)

initiator.
(host, port, heartBtInt); // Establish the session as Initiator
Console.WriteLine("Current Role: " + initiator.Role.ToString());
Console.WriteLine(FixEngine.Instance.Statistics);

// ... - business logic 
initiator.Disconnect(); // Close the session

See "Hello, World!" Sample Walkthrough that illustrates the examples of initiator and acceptor sessions connecting to each other.

Custom Logon message

The method override SessionConnectAsInitiator(String, Int32, Int32, FixMessage) with com.b2bits.FIXAntennaFixMessagecustomLogonMsg parameter allows sending a custom logon message during logon.

See the example below:

string target = "Acceptor's CompID";
string sender = "Initiator's CompID";

Session initiator = FixEngine.Instance.CreateSession(target, sender, FixVersion.FIX44);

string host = "localhost"; // remote FIX engine's host name
int port = FixEngine.Instance.ListenPort; // remote FIX engine's port
int heartBtInt = 30; // Heartbeat interval (in seconds)
// create a Logon message framework
FixMessage logonMsg = FixMessage.Create(FixVersion.FIX44, "A");
logonMsg.SetField(Tag.MaxMessageSize, 2000);
Console.WriteLine("Custom Logon Message: " + logonMsg);

// Establish the session as Initiator using Custom Logon Message
initiator.ConnectAsInitiator(host, port, heartBtInt, logonMsg);

In Benchmark custom logon messages were used to inform acceptor about the number of messages we are going to send from initiator. This was done by adding a custom field to the logon message and storing the number of messages in this field.

Closing Session

To close the session, use the following methods:

SessionDisconnect

SessionDisconnectNonGracefully

The difference between these methods is the State of the session after disconnect, that will be either CORRECTLY_TERMINATED or NON_GRACEFULLY_TERMINATED, respectively. (see enum com.b2bits.FIXAntennaSessionState).

Disposing resources of a connected session also forces disconnect. If you call FixEngineStop or SessionDispose it will cause the session to disconnect non gracefully.

Forcedly Setting Sequence Numbers

To forcedly set session's message sequence numbers use the following properties:

SessionInSeqNum

SessionOutSeqNum

Information about Session State

To obtain a session current state report, use the SessionState property.

Below you can see the list of most important states (please see com.b2bits.FIXAntennaSessionState for the complete list).

SessionState enumDescription
INITIALThe session was created, but is not connected yet.
WAIT_FOR_FIRST_LOGONThe session was connected as an Acceptor and waits for the first Logon message.
WAIT_FOR_CONFIRM_LOGONThe session was connected as an Initiator, the first Logon message was sent and it waits for the confirming Logon message.
ESTABLISHEDThe session is fully established.
RECONNECTThe session-initiator detected the telecommunication link error and is trying to re-establish the link.
CORRECTLY_TERMINATEDThe session was correctly terminated.
NON_GRACEFULLY_TERMINATEDThe session was non-gracefully terminated.
Note Note

When FixAntenna retrieves session state, it locks this property to prevent its changing from another thread. When you develop a multithreaded application, please ensure that you will not put into lock {} sections both code that gets current session state and code that at the same time changes session state in another thread (by calling Connect or Desconnect). This may cause deadlocks in your application and the program will hang up.

In case when you want to display actual session state in your application we recommend you to subscribe to SessionNewStateEvent. Session events will also be discussed below, in section.

Sending Messages

To send outgoing application-level messages, use the SessionPut(FixMessage) method.

FixEngine also automatically sends all session-level messages, defined by the FIX Protocol, like Logon, Logout and Heartbeat messages.

FixMessage msg = FixMessage.Create(FixVersion.FIX44, "D"); // New Order - Single (MsgType = D)
msg.SetField(Tag.ClOrdID, "90001008"); 
msg.SetField(Tag.Side, "1");             
msg.SetField(Tag.TimeInForce, "0");
msg.SetField(Tag.HandlInst, "1");
msg.SetField(Tag.Symbol, "IBM");
msg.SetField(Tag.OrderQty, 10);
msg.SetField(Tag.OrdType, "1");
msg.SetField(Tag.TransactTime, "20060101-10:00:00");
//...
Console.WriteLine("Msg: " + msg);            

initiator.Put(msg); // send the message
System.Threading.Thread.Sleep(1000); // wait for message processing

All FIX sessions are bi-directional. So, once 2 applications establish a connection and loggen on, they can send messages and receive messages from each other using the same session.

Note Note

Sending messages is performed by FixAntenna as an asyncroneous operation. That means that when you call the Put method and it returns the control flow to your program, the message is not actually sent at this moment. FixAntenna queues and processes messages in multiple working threads, that allows boosting message sending performance.

If you gracefully close the session right after you call Put, the session will not be closed until all messages from buffer are sent.

However, if you want to terminate non-gracefully or call FixEngineStop you should wait until all messages are delivered to the acceptor.

Processing Incoming Messages

To process incoming messages, subscribe for the SessionIncomingMessageEvent event.

See the example below:

// Event Listener
class IncomingMessagesListener
{
    public void OnIncomingMessage(Object sender, Session.IncomingMessageEventArgs e)
    {
        Console.WriteLine("\nOnIncomingMessage: " + e.IncomingMessageMsg);
    }
};

IncomingMessagesListener listener = new IncomingMessagesListener();
acceptor.IncomingMessageEvent += new Session.IncomingMessageEventHandler(listener.OnIncomingMessage);
Note Note

IncomingMessageEvent is fired when an application-level event is received (i.e. when a counterpart application sent it using SessionPut(FixMessage) method). Other event handlers are responsible for session-level events, please see section below.

Session Events Monitoring

The Session class has several events that can be subscribed by client applications.

See the complete list of events here: SessionSession

The example below demonstrates how to subscribe for all session events and log their execution to console.

// Session's events listener 
class SessionEventsListener
{
    public void OnLogon(Object sender, Session.LogonEventArgs e)
    {
        Console.WriteLine("OnLogon: " + e.LogonMsg);       
    }

    public void OnLogout(Object sender, Session.LogoutEventArgs e)
    {
        Console.WriteLine("OnLogout: " + e.LogoutMsg);
    }                  

    public void OnSessionLevelReject(Object sender, Session.SessionLevelRejectEventArgs e)
    {
        Console.WriteLine("OnSessionLevelReject: " + e.SessionLevelRejectMsg);
    }

    public void OnSequenceGap(Object sender, Session.SequenceGapEventArgs e)
    {
        Console.WriteLine("OnSequenceGap: " + e.Message + ", expected: " + e.ExpectedSeqNum + ", received: " + e.ReceivedSeqNum);
    }

    public void OnHeartbeatWithTestReqID(Object sender, Session.HeartbeatWithTestReqIDEventArgs e)
    {
        Console.WriteLine("OnHeartbeatWithTestReqID: " + e.HeartbeatMsg + ", id: " + e.TestReqID);                
    }

    public void OnResendRequest(Object sender, Session.ResendRequestEventArgs e)
    {
        Console.WriteLine("OnResendRequest: " + e.ResendRequestMsg + ", beginSeqNo=" + e.BeginSeqNo + ", endSeqNo=" + e.EndSeqNo);                
    }   

    public void OnNewStateEvent(Object sender, Session.NewStateEventArgs e)
    {
        Console.WriteLine("NewStateEvent received." );
    }
}

SessionEventsListener event_listener = new SessionEventsListener();

acceptor.LogonEvent += new Session.LogonEventHandler(event_listener.OnLogon);
acceptor.LogoutEvent += new Session.LogoutEventHandler(event_listener.OnLogout);
acceptor.SessionLevelRejectEvent += new Session.SessionLevelRejectEventHandler(event_listener.OnSessionLevelReject); 
acceptor.SequenceGapEvent += new Session.SequenceGapEventHandler(event_listener.OnSequenceGap);     
acceptor.HeartbeatWithTestReqIDEvent += new Session.HeartbeatWithTestReqIDEventHandler(event_listener.OnHeartbeatWithTestReqID);
acceptor.ResendRequestEvent += new Session.ResendRequestEventHandler(event_listener.OnResendRequest);
acceptor.NewStateEvent += new Session.NewStateEventHandler(event_listener.OnNewStateEvent);
Note Note

Usually you may wish to subscribe for all session events in order to do logging. However OnLogon, OnLogout or OnNewStateEvent events are also very important to implement any logic in your program that should rely on the fact that session is already in a certain state.

For example if you want to send messages directly after logon, you should wait until session signals you that logon is really completed. SessionConnectAsInitiator and SessionConnectAsAcceptor are asynchronous functions, so even when they both return control flow to the application, some time will still be required for both sessions to exchange with Login and Login Confirmation messages through a TCP/IP network.

Please see "Hello, World!" Sample Walkthrough for an example of how session events can be used to syncronize main execution thread with the actual session state.

See Also

Reference

Other Resources