You can find updates here.
This is a simple TCP/IP chat sample. The solution is made up of three different projects. The main project is "Listener", where you can find the core of this program. In Rete.cs, there are the main methods used to make this program work.
Please note that source code comments (//) are written in Italian.
The most important class is
Poller, in rete.cs. In Main.cs is created a
Poller object, that is used to connect, poll and write the socket.
In Main.cs is started a thread that has to refresh the GUI; the thread executes:
public void StartGUIRefreshThread()
ThreadStart GuiRefreshDelegate=new ThreadStart(this.GUIRefreshThread);
GUIRefresh= new Thread(GuiRefreshDelegate);
This is a simple example of using threads. Starting a new thread means running different portions of the code at "the same time". While a thread is running a loop, the "main program" which is another thread executes other instructions.
ThreadStart object contains a reference to a method that has to be run when the thread starts. If this function does not contain a loop, the thread will stop after a while. If the referenced method contains an infinite loop, the thread will be running as long as the application.
GUIRefresh.Start(); executes the "
this.GUIRefreshThread()" method, as specified in "
StartGUIRefreshThread" method starts a thread which contains an infinite loop:
public void GUIRefreshThread()
int localDelay, totalDelay=1200, newDataPresentIconDelay=300;
This checks the
Poller status, and displays the appropriate output to the user.
Poller object handles the TCP connection, using a "raw"
Socket object, initialized with the "
InizializzaTX()" method if the current application is running as a client, or with "
InizializzaRX" if the application is running as a server (listener).
public bool InizializzaRX()
this.ListenSocket= new Socket(AddressFamily.InterNetwork,
This code creates a new socket (
this.ListenSocket) which is bound to the listening IP address and port (LIPE).
Now the socket is properly configured, but it's not "active". We have to start it to begin listening with the
<Socket>.Accept() method, which puts the socket in a "wait state" for client connections.
<Socket>.Blocking determines whether the execution will stop waiting for client connections or not (
true=stop). I use
blocking=true. Note that if you use
blocking=true in the main thread, your application will hang until a connection is accepted.
private void PollingRX()
this.DebugRefresh("PollingRX: fermo in accept() su"+ this.LIPE.Port);
this.DebugRefresh("PollingRX: Accept() eseguita");
this.DebugRefresh("PollingRX: eseguito ("+n+" bytes)");
this.DebugRefresh("PollingRX: ricevuto EXIT");
When a client makes a connection, the
Accept() returns a new socket, connected to the client, which is used to transfer data, using my
CheckAndRetrive() (read from socket) and
PushString() (write to socket) methods. See below to read pertinent code.
This loop continues until a "stop string" is received from the client.
public void InizializzaTX()
this.UsedScocket = new Socket(AddressFamily.InterNetwork,
This is the dual of RX: a new socket is created, and a connection to a remote IP and port (RIPE) is created.
private void PollingTX()
this.DebugRefresh("PollingTX: eseguito("+n+" bytes)");
this.DebugRefresh("PollingTX: ricevuto EXIT");
Very similar to RX... once the socket is connected, communication is "symmetric".
Writing and Reading data
This is how I get a string from the socket (
CheckAndRetrive() uses this function to get data from the socket):
public static string GetStringFromSocket(Socket s)
Byte recBytes=new Byte;
foreach (char c in ac)
The socket needs to be a connected socket; you have to use a byte array to put in the received data. Then you have to encode it with a encoding mechanism, the same is used to decode the data. I use UTF8 Encoding.
This reads at most a 10001 bytes block from the socket. To read more bytes, a loop is required, something like:
This is how to put a string in a socket:
public static int PutStringInSocket(Socket s, string msg)
else return 0;
Framing.IncapsulaMSG() is simply a method that writes tags in a message to make it simple to interpret it, and returns a string.
Poller are executed other threads, responsible for receiving/checking and sending data over the TCP connection. Loops inside
PollingTX() run in two different threads.
public bool StartPollingTX()
ThreadStart TXPollingDelegate = new ThreadStart(this.PollingTX);
TXPolling= new Thread(TXPollingDelegate);
this.DebugRefresh("PollingTX: (Start) eseguito");
This is an example that shows how the "Transmission" thread is started. (It runs "
this.PollingTX" described above.) The Settings tab is stored in a separate DLL, and so is the config utility. Settings are stored in an XML file.
I know there are many silly things, but this was intended only as an example.
I hope you enjoyed the article.