I've got a server and client set up using TcpListener
and TcpClient
.
I want to send an object to my server application for processing.
I've discovered the using System.Runtime.Serialization
and the following documentation, but I didn't want to faff around to find that I'm doing it in long winded way.
The question: What is the best way to process and send an object over the TCP stream?
Sending and receiving.
Here's an example of my object:
// Create a new house to send
house newHouse = new house();
// Set variables
newHouse.street = "Mill Lane";
newHouse.postcode = "LO1 BT5";
newHouse.house_number = 11;
newHouse.house_id = 1;
newHouse.house_town = "London";
Assuming you have a class House
(available on both sides of your connection) looking like this:
[Serializable]
public class House
{
public string Street { get; set; }
public string ZipCode { get; set; }
public int Number { get; set; }
public int Id { get; set; }
public string Town { get; set; }
}
You can serialize the class into a MemoryStream
. You can then use in your TcpClient
connection like this:
// Create a new house to send house and set values.
var newHouse = new House
{
Street = "Mill Lane",
ZipCode = "LO1 BT5",
Number = 11,
Id = 1,
Town = "London"
};
var xmlSerializer = new XmlSerializer(typeof(House));
var networkStream = tcpClient.GetStream();
if (networkStream.CanWrite)
{
xmlSerializer.Serialize(networkStream, newHouse);
}
Of course you have to do a little more investigation to make the program running without exception. (e.g. Check memoryStream.Length
not to be greater than an int, a.s.o.), but I hope I gave you the right suggestions to help you on your way ;-)
First create a empty ServerApplication and ClientApplication as Console Application to simplify the example.
Then, put the definition for the serializable object into a separate assembly and then add a reference to the shared assembly to each project (server and client). Is necesary share the same object, not just an identical class copy.
To Generate DLL > Right clic in Solution 'ServerApplication' in the Solution Explorer > Add New Project... -> select Class Library (e.g. name this project MySharedHouse) Rename the default Class1 to House and complete it
[Serializable]
public class House
{
public string Street { get; set; }
public string ZipCode { get; set; }
public int Number { get; set; }
public int Id { get; set; }
public string Town { get; set; }
}
Right clic in MySharedHouse and Build.
Now the dll is build and we need to add it in Server Project and Client Project. Right clic in ServerApplication > Add Reference > Browse and find the dll, for this example
Projects\ServerApplication\MySharedHouse\bin\Debug\MySharedHouse.dll
Repeat the process in ClientApplication using the same dll (same path).
Now you can use instances of House class in ServerApplication and ClientApplication as a single object, simply adding the sentence "using MySharedHouse" at the top.
SERVER CODE
using System;
using System.Net;
using System.Net.Sockets;
using System.Runtime.Serialization.Formatters.Binary;
using System.Threading;
using MySharedHouse;
namespace ServerApplication
{
class Program
{
static void Main(string[] args)
{
MessageServer s = new MessageServer(515);
s.Start();
}
}
public class MessageServer
{
private int _port;
private TcpListener _tcpListener;
private bool _running;
private TcpClient connectedTcpClient;
private BinaryFormatter _bFormatter;
private Thread _connectionThread;
public MessageServer(int port)
{
this._port = port;
this._tcpListener = new TcpListener(IPAddress.Loopback, port);
this._bFormatter = new BinaryFormatter();
}
public void Start()
{
if (!_running)
{
this._tcpListener.Start();
Console.WriteLine("Waiting for a connection... ");
this._running = true;
this._connectionThread = new Thread
(new ThreadStart(ListenForClientConnections));
this._connectionThread.Start();
}
}
public void Stop()
{
if (this._running)
{
this._tcpListener.Stop();
this._running = false;
}
}
private void ListenForClientConnections()
{
while (this._running)
{
this.connectedTcpClient = this._tcpListener.AcceptTcpClient();
Console.WriteLine("Connected!");
House house = new House();
house.Street = "Evergreen Terrace";
house.ZipCode = "71474";
house.Number = 742;
house.Id = 34527;
house.Town = "Springfield";
_bFormatter.Serialize(this.connectedTcpClient.GetStream(), house);
Console.WriteLine("send House!");
}
}
}
}
CLIENT CODE
using System;
using System.Net.Sockets;
using System.Runtime.Serialization.Formatters.Binary;
using System.Threading;
using MySharedHouse;
namespace ClientApplication
{
class Program
{
static void Main(string[] args)
{
MessageClient client = new MessageClient(515);
client.StartListening();
}
}
public class MessageClient
{
private int _port;
private TcpClient _tcpClient;
private BinaryFormatter _bFormatter;
private Thread _listenThread;
private bool _running;
private House house;
public MessageClient(int port)
{
this._port = port;
this._tcpClient = new TcpClient("127.0.0.1", port);
this._bFormatter = new BinaryFormatter();
this._running = false;
}
public void StartListening()
{
lock (this)
{
if (!_running)
{
this._running = true;
this._listenThread = new Thread
(new ThreadStart(ListenForMessage));
this._listenThread.Start();
}
else
{
this._running = true;
this._listenThread = new Thread
(new ThreadStart(ListenForMessage));
this._listenThread.Start();
}
}
}
private void ListenForMessage()
{
Console.WriteLine("Reading...");
try
{
while (this._running)
{
this.house = (House)this._bFormatter.Deserialize(this._tcpClient.GetStream());
Console.WriteLine(this.house.Street);
Console.WriteLine(this.house.ZipCode);
Console.WriteLine(this.house.Number);
Console.WriteLine(this.house.Id);
Console.WriteLine(this.house.Town);
}
}
catch (Exception e)
{
Console.WriteLine(e);
Console.ReadLine();
}
}
}
}
Wooala! the first house to be sent over TCP/IP
You can simply decorate your House
class with the [Serializable]
attribute. (You do not need to define all the other stuff as posted in the other answer)
You can then send this object on the wire by serializing it using the BinaryFormatter
class.
Have you considered setting up a WCF service instead of using TcpListener and TcpClient ? Makes life a lot easier.
For instance you could define a service that returned a house
[ServiceContract]
public interface IService
{
[OperationContract]
House GetHouse(int houseId);
}
See this real world example.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With