Introduction
This library is aimed to make TCP/IP and Client/Server programming so easy. With its multi-threaded structure, it provides methods and properties to send and receive data between server and client using TCP protocol.
You will be able to easily develop your own Client/Server program without needing deep knowledge about socket programming. create your own command list, send and receive packets easily.
In addition, handshaking between client and server has been made very easy, just call handshake and the library will do the rest. This library is written in C# and uses no external dependency.
To Be Completed
This class is not developed to transfer large amount of data and it only works in TCP mode. I am working on it to support multi-packet data to support large data transfer automatically but unfortunately I am a little busy right now.
To send this type of data, you need to develop or modify this class to support UDP protocol.
Background
Please pay very attention to the following two parameters which are defined in NETCOM class:
MAX_TRY_COUNT
which means how many times the underlaying layer should re-try to send a packet or data to the other side before it returns failure.
DEFAULT_CONNECT_WAIT_TIMEOUT
which means how long the underlaying layer should wait for the connection to be completed with the other side before it returns failure.
MAX_PACKET_CONTENTS_LENGTH
NETCOM
: Is the underlaying layer to provide connection to the other side and handle send/receive data between two sides. AgentRelay
: Is the main class that provides Packet
based communication between two sides. Please pay attention that the maximum packet's data length is 400 bytes. RawAgentRelay
: Is the main class that provides communication between two sides in raw mode. You can send/receive data between two sides and the length of data can be different and then there is no control over the contents. Just consider the maximum data length is 2000 bytes.
NOTE: You can change the maximum data length in NETCOMM class directly.
Using the Code
There are two classes which are provided by this library:
AgentRelay
: which is based on Packet
transmit/receive system and is very useful to develop applications which require to be connected to each other to send and receive fixed commands over network. RawAgentRelay
: which is not based on Packet
and transmit/receive raw bytes between two sides. This class is very useful when you want to develop applications that may work as a bridge and it should not pay attention whether what is exactly transferring between them. ServerRelay
: which is responsible to provide server functionality to accept and handle connection from another AgentRelay
objects.
Note: Both AgentRelay and RawAgentRelay act as client modules and ServerRelay acts as a server module.
AgentRelay Class as Client Module
This class uses NETCOM to create a TCP/IP connection between two sides and provides Packet
based communication between them including automatic handshake process.
Packet
structure is shown here:
[StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi, Size = 406)]
public class Packet
{
[MarshalAs(UnmanagedType.I1)]
public byte Type=0;
[MarshalAs(UnmanagedType.I2)]
public ushort FragmentIndex=0;
[MarshalAs(UnmanagedType.I1)]
public byte Command;
[MarshalAs(UnmanagedType.I2)]
public ushort DataLength;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 400)]
public byte[] Content;
}
In our example, we want to create a simple chat software to send/receive text messages between two sides. First, we need to create our own command list:
private enum eTcpCommands
{
ChatMessage = 1,
QueryNameRequest = 2,
QueryNameResponse = 3,
....
}
NOTE: Command codes 250 to 255 are reserved for internal control process.
Create an instance of AgentRelay
class and connect to other side using Connect
method:
AgentRelay m_chatProvider = new AgentRelay();
m_chatProvider.Connect(tbIPAddress.Text, 1234);
To send message to other side, easily call SendMessage
method:
m_chatProvider.SendMessage((int)eTcpCommands.ChatMessage, txt);
You need to handle received messages:
m_chatProvider.OnNewPacketReceived += chatProvider_OnNewPacketReceived;
private void chatProvider_OnNewPacketReceived(AgentRelay.Packet packet, AgentRelay agentRelay)
{
switch(packet.Command)
{
case (byte)eTcpCommands.ChatMessage:
this.Invoke(new MethodInvoker(() => { lbMessages.Items.Insert
(0,AgentRelay.MakeStringFromPacketContents(packet)); }));
break;
case (byte)eTcpCommands.QueryNameRequest:
agentRelay.SendMessage((int)eTcpCommands.QueryNameResponse, "TCP/IP Test");
break;
case (byte)eTcpCommands.QueryNameResponse:
this.Invoke(new MethodInvoker(() => { lbMessages.Items.Insert
(0, "NAME: " + AgentRelay.MakeStringFromPacketContents(packet)); }));
break;
default:
agentRelay.SendResponse(AgentRelay.eResponseTypes.InvalidCommand);
break;
}
}
Finally, RawAgentRelay is same as AgentRelay but is not limited to packet concept.
Some Notes
SendMessage()
This method is used to send your specific commands and contents to the other side.
SendResponse()
This method is used to send fixed responses to the other side without any extra content, which are Success
, Wait
, Invalid
and Error
.
OnNewPacketReceived(AgentRelay.Packet packet, AgentRelay agentRelay)
This event is called whenever a new packet is received, agentRelay
refers to the sender client and you can use this object to send any response to the other side immediately.
GetNextReceivedPacket(out Packet packet, int timeoutMs)
If you like to check for any newly received packet in your main code (instead by AgentRelay
itself), you first must set the OnNewPacketReceived
event to null
and then periodically call GetNextReceivedPacket
to receive packets if any.
UserData
Property
There is an object called UserData
in AgentRelay
class which is not used by the class directly and you can use it to store any type of data into your agentRelay
object.
Note: When you are done, you have to call Dispose()
to release all the allocated resources.
ServerRelay Class as Server Module
This class uses NETCOM to receive and handle a TCP/IP connection request and provides it as an AgentRelay
object to you.
The first step is to create an object from ServerRelay
class and call StartServer
method. This method has two parameters which indicates the listening IP address and port. The IP address is optional and if passed as null
, it will start listening on all network devices in the system (which is not recommended).
ServerRelay m_serverRelay = new ServerRelay(true);
m_serverRelay.OnNewAgentConnected += m_serverRelay_OnNewAgentConnected;
m_serverRelay.StartServer(null, 1234);
Do not forget to handle OnNewPacketReceived
for the newly connected agent, otherwise you will not receive responses from that agent.
void m_serverRelay_OnNewAgentConnected(AgentRelay agentRelay)
{
agentRelay.OnNewPacketReceived += chatProvider_OnNewPacketReceived;
}
The next step is to enable accepting incoming connections after starting the server:
m_serverRelay.AcceptIncommingConnections = true;
It is possible to send a message to all connected agents at once (Broadcast a message):
BroadcastMessage(int cmdCode, string content, AgentRelay excludedAgent)
The content is optional and you can exclude a specific agent to receive that particular message. Maybe that agent is the caller itself that does not like to stick in a deadly loop over network!
Some Notes
ServerRelay
constructor
If you pass true
to the constructor which means EnableAutoHandshake
, the server will try to handshake with all the connected agents every 15 seconds which is useful to discover faulty agents.
OnNewAgentConnected(AgentRelay agentRelay)
Each time a new agent connects to our server, OnNewAgentConnected
will be raised to inform you about the new agent.
StopServer()
Do not forget to call this method to clean up all the resources.
If you pass true
to this function, it will dispose and cleanup all active agents which were connected to the server.
Points of Interest
While I was developing socket based programs, I faced some situations that the connection were established and it looked very well but in fact because of some unknown reasons, it was faulty in fact!
I came to this point to prepare a handshaking mechanism so the networking layer would be worried about the connection, so simply call a method StartHandshakeAsync
and wait for the result.
This method is only supported by AgentRelay
class, after calling this method, you have to check the LastHandshakeResult
to see the result, ALTHOUGH the ServerRelay
will do this automatically and there is no need to call this method manually.
History
- 7th Apr 015 - First stable release