Sessions |
A FIX-session (see FIX Sessions) is represented by the com.b2bits.FIXAntennaSession class.
This topic contains the following sections:
Note |
---|
To compile the samples below, please declare the usage of com.b2bits.FIXAntenna namespace |
To create a session, call the following method:
See the example below:
Session session = FixEngine.Instance.CreateSession("SenderCompID", "TargetCompID", FixVersion.FIX44);
Dim session_ As Session = FixEngine.Instance.CreateSession("SenderCompID", "TargetCompID", FixVersion.FIX44)
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);
Dim sid_ As SessionId = New SessionId("SenderCompID", "TargetCompID", "Q1") Dim session_ As Session = FixEngine.Instance.CreateSession(sid_, FixVersion.FIX44)
SessionId ^ sid = gcnew SessionId("SenderCompID", "TargetCompID", "Q1"); Session^ session = FixEngine::Instance->CreateSession(sid, FixVersion::FIX44);
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();
Dim session_ As Session = FixEngine.Instance.CreateSession("SenderCompID", "TargetCompID", FixVersion.FIX44) ' ... session.Dispose()
Session^ session = FixEngine::Instance->CreateSession("SenderCompID", "TargetCompID", FixVersion::FIX44); // ... delete session;
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();
// FixEngine must be initialized before Dim acceptor As Session = FixEngine.Instance.CreateSession("SenderCompID", "TargetCompID", FixVersion.FIX44) acceptor.ConnectAsAcceptor()
// FixEngine must be initialized before Session^ acceptor = FixEngine::Instance->CreateSession("SenderCompID", "TargetCompID", FixVersion::FIX44); acceptor->ConnectAsAcceptor();
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 |
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);
Private Class AcceptorsListener ' Methods Public Sub OnUnregisteredAcceptor(ByVal sender As Object, ByVal e As FixEngine.UnregisteredAcceptorArgs) Console.WriteLine((ChrW(10) & "OnUnregisteredAcceptor: " & e.Session.ToString())) End Sub End Class Dim listener1 As New AcceptorsListener AddHandler FixEngine.Instance.UnregisteredAcceptor, New FixEngine.UnregisteredAcceptorHandler(AddressOf listener1.OnUnregisteredAcceptor)
// Event Listener ref class AcceptorsListener { public: void OnUnregisteredAcceptor(Object^ sender, FixEngine::UnregisteredAcceptorArgs^ e) { Console::WriteLine("\nOnUnregisteredAcceptor: {0}", e->Session->ToString()); } }; AcceptorsListener^ listener = gcnew AcceptorsListener(); FixEngine::Instance->UnregisteredAcceptor += gcnew FixEngine::UnregisteredAcceptorHandler(listener, &AcceptorsListener::OnUnregisteredAcceptor);
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
FixEngine.Create("engine.properties") ' initialization Dim sender As String = "Acceptor's CompID" Dim target As String = "Initiator's CompID" Dim acceptor As Session = FixEngine.Instance.CreateSession(sender, target, FixVersion.FIX44) acceptor.ConnectAsAcceptor() Dim initiator As Session = FixEngine.Instance.CreateSession(target, sender, FixVersion.FIX44) Dim host As String = "localhost" ' remote FIX engine's host name Dim port As Integer = FixEngine.Instance.ListenPort ' remote FIX engine's port Dim heartBtInt As Integer = 30 ' Heartbeat interval (in seconds) initiator.ConnectAsInitiator(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
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->ConnectAsInitiator(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.
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);
Dim target As String = "Acceptor's CompID" Dim sender As String = "Initiator's CompID" Dim initiator As Session = FixEngine.Instance.CreateSession(target, sender, FixVersion.FIX44) Dim host As String = "localhost" ' remote FIX engine's host name Dim port As Integer = FixEngine.Instance.ListenPort ' remote FIX engine's port Dim heartBtInt As Integer = 30 ' Heartbeat interval (in seconds) ' create a Logon message framework Dim logonMsg As FixMessage = FixMessage.Create(FixVersion.FIX44, "A") logonMsg.SetField(Tag.MaxMessageSize, 2000) Console.WriteLine("Custom Logon Message: " & logonMsg.ToString()) ' Establish the session as Initiator using Custom Logon Message initiator.ConnectAsInitiator(host, port, heartBtInt, logonMsg)
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: {0}", 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.
To close the session, use the following methods:
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.
To forcedly set session's message sequence numbers use the following properties:
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 enum | Description |
---|---|
INITIAL | The session was created, but is not connected yet. |
WAIT_FOR_FIRST_LOGON | The session was connected as an Acceptor and waits for the first Logon message. |
WAIT_FOR_CONFIRM_LOGON | The session was connected as an Initiator, the first Logon message was sent and it waits for the confirming Logon message. |
ESTABLISHED | The session is fully established. |
RECONNECT | The session-initiator detected the telecommunication link error and is trying to re-establish the link. |
CORRECTLY_TERMINATED | The session was correctly terminated. |
NON_GRACEFULLY_TERMINATED | The session was non-gracefully terminated. |
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. |
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
[VB] Dim msg As FixMessage = 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.ToString()) initiator.Put(msg) ' send the message Threading.Thread.Sleep(1000) ' wait for message processing
[C++/CLI] 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: {0}", 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 |
---|
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. |
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);
Private Class IncomingMessagesListener ' Methods Public Sub OnIncomingMessage(ByVal sender As Object, ByVal e As Session.IncomingMessageEventArgs) Console.WriteLine((ChrW(10) & "OnIncomingMessage: " & e.IncomingMessageMsg.ToString())) End Sub End Class Dim listener As New IncomingMessagesListener AddHandler acceptor.IncomingMessageEvent, New Session.IncomingMessageEventHandler(AddressOf listener.OnIncomingMessage)
// Event Listener ref class IncomingMessagesListener { public: void OnIncomingMessage(Object^ sender, Session::IncomingMessageEventArgs^ e) { Console::WriteLine("\nOnIncomingMessage: {0}", e->IncomingMessageMsg); } }; IncomingMessagesListener^ listener = gcnew IncomingMessagesListener(); acceptor->IncomingMessageEvent += gcnew Session::IncomingMessageEventHandler(listener, &IncomingMessagesListener::OnIncomingMessage);
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. |
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);
' Session's events listener Private Class SessionEventsListener ' Methods Public Sub OnHeartbeatWithTestReqID(ByVal sender As Object, ByVal e As Session.HeartbeatWithTestReqIDEventArgs) Console.WriteLine(String.Concat(New Object() {"OnHeartbeatWithTestReqID: ", e.HeartbeatMsg, ", id: ", e.TestReqID})) End Sub Public Sub OnLogon(ByVal sender As Object, ByVal e As Session.LogonEventArgs) Console.WriteLine(("OnLogon: " & e.LogonMsg.ToString)) End Sub Public Sub OnLogout(ByVal sender As Object, ByVal e As Session.LogoutEventArgs) Console.WriteLine(("OnLogout: " & e.LogoutMsg.ToString)) End Sub Public Sub OnNewStateEvent(ByVal sender As Object, ByVal e As Session.NewStateEventArgs) Console.WriteLine("NewStateEvent received.") End Sub Public Sub OnResendRequest(ByVal sender As Object, ByVal e As Session.ResendRequestEventArgs) Console.WriteLine(String.Concat(New Object() {"OnResendRequest: ", e.ResendRequestMsg, ", beginSeqNo=", e.BeginSeqNo, ", endSeqNo=", e.EndSeqNo})) End Sub Public Sub OnSequenceGap(ByVal sender As Object, ByVal e As Session.SequenceGapEventArgs) Console.WriteLine(String.Concat(New Object() {"OnSequenceGap: ", e.Message, ", expected: ", e.ExpectedSeqNum, ", received: ", e.ReceivedSeqNum})) End Sub Public Sub OnSessionLevelReject(ByVal sender As Object, ByVal e As Session.SessionLevelRejectEventArgs) Console.WriteLine(("OnSessionLevelReject: " & e.SessionLevelRejectMsg.ToString)) End Sub End Class Dim event_listener As New SessionEventsListener AddHandler acceptor.LogonEvent, New Session.LogonEventHandler(AddressOf event_listener.OnLogon) AddHandler acceptor.LogoutEvent, New Session.LogoutEventHandler(AddressOf event_listener.OnLogout) AddHandler acceptor.SessionLevelRejectEvent, New Session.SessionLevelRejectEventHandler(AddressOf event_listener.OnSessionLevelReject) AddHandler acceptor.SequenceGapEvent, New Session.SequenceGapEventHandler(AddressOf event_listener.OnSequenceGap) AddHandler acceptor.HeartbeatWithTestReqIDEvent, New Session.HeartbeatWithTestReqIDEventHandler(AddressOf event_listener.OnHeartbeatWithTestReqID) AddHandler acceptor.ResendRequestEvent, New Session.ResendRequestEventHandler(AddressOf event_listener.OnResendRequest) AddHandler acceptor.NewStateEvent, New Session.NewStateEventHandler(AddressOf event_listener.OnNewStateEvent)
// Session's events listener ref class SessionEventsListener { public: void OnLogon(Object^ sender, Session::LogonEventArgs^ e) { Console::WriteLine("OnLogon: {0}", e->LogonMsg); } void OnLogout(Object^ sender, Session::LogoutEventArgs^ e) { Console::WriteLine("OnLogout: {0}", e->LogoutMsg); } void OnSessionLevelReject(Object^ sender, Session::SessionLevelRejectEventArgs^ e) { Console::WriteLine("OnSessionLevelReject: {0}", e->SessionLevelRejectMsg); } void OnSequenceGap(Object^ sender, Session::SequenceGapEventArgs^ e) { Console::WriteLine("OnSequenceGap: {0}, expected: {1}, received: {2}", e->Message, e->ExpectedSeqNum, e->ReceivedSeqNum); } void OnHeartbeatWithTestReqID(Object^ sender, Session::HeartbeatWithTestReqIDEventArgs^ e) { Console::WriteLine("OnHeartbeatWithTestReqID: {0}, id: {1}", e->HeartbeatMsg, e->TestReqID); } void OnResendRequest(Object^ sender, Session::ResendRequestEventArgs^ e) { Console::WriteLine("OnResendRequest: {0} , beginSeqNo= {1}, endSeqNo={2}", e->ResendRequestMsg, e->BeginSeqNo, e->EndSeqNo); } void OnNewStateEvent(Object^ sender, Session::NewStateEventArgs^ e) { Console::WriteLine("NewStateEvent received." ); } }; SessionEventsListener^ event_listener = gcnew SessionEventsListener(); acceptor->LogonEvent += gcnew Session::LogonEventHandler(event_listener, &SessionEventsListener::OnLogon); acceptor->LogoutEvent += gcnew Session::LogoutEventHandler(event_listener, &SessionEventsListener::OnLogout); acceptor->SessionLevelRejectEvent += gcnew Session::SessionLevelRejectEventHandler(event_listener, &SessionEventsListener::OnSessionLevelReject); acceptor->SequenceGapEvent += gcnew Session::SequenceGapEventHandler(event_listener, &SessionEventsListener::OnSequenceGap); acceptor->HeartbeatWithTestReqIDEvent += gcnew Session::HeartbeatWithTestReqIDEventHandler(event_listener, &SessionEventsListener::OnHeartbeatWithTestReqID); acceptor->ResendRequestEvent += gcnew Session::ResendRequestEventHandler(event_listener, &SessionEventsListener::OnResendRequest); acceptor->NewStateEvent += gcnew Session::NewStateEventHandler(event_listener, &SessionEventsListener::OnNewStateEvent);
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. |