Click here to Skip to main content
15,867,594 members
Articles / Desktop Programming / WPF

WPF Version of IPMessager

Rate me:
Please Sign up or sign in to vote.
4.87/5 (10 votes)
27 Feb 2010CPOL2 min read 43.9K   2.7K   55   11
Redeveloped the IPMessager program using C# and WPF
Image 1

Introduction

Many people have used IPMessager, an old Win32 program, which can send messages and files between machines of a Local Area Network. I redeveloped the application according to its protocol using C# 3.5 and WPF. It's a good way to learn both WPF programming and Network programming with .NET Framework.

Background

IP Messenger is a Send/Receive message service using the TCP/UDP Port (default:2425). Messages are sent by UDP and files are sent by TCP. All messages are of the following format:

Version : PacketNo : SenderName : SenderHost : CommandNo : AdditionalSection

For example, "1:100:shirouzu:jupiter:32:Hello".

Currently the version number is 1, PacketNo is used to identify the message, the message type and options are determined by the CommandNo.

For details of Member recognition, Send/Receive Message, transfer file attachment, etc., you can read the protocol document.

Using the Code

One added functionality is to choose Network interface in case you have multiple network cards.

The following code can get all active IPv4 network addresses:

C#
public static List<IPAddress> GetIPv4NetworkInterfaces()
{
    List<IPAddress> IPv4Addresses = new List<IPAddress>();
    NetworkInterface[] nics = NetworkInterface.GetAllNetworkInterfaces();
    foreach (NetworkInterface adapter in nics)
    {
        if (adapter.NetworkInterfaceType == NetworkInterfaceType.Loopback
            || adapter.OperationalStatus != OperationalStatus.Up)
        {
            continue;
        }
        // Only get information for interfaces that support IPv4.
        if (adapter.Supports(NetworkInterfaceComponent.IPv4))
        {
            IPInterfaceProperties adapterProperties = adapter.GetIPProperties();
            foreach (UnicastIPAddressInformation ipAddress in 
				adapterProperties.UnicastAddresses)
            {
                if (ipAddress.Address.AddressFamily == AddressFamily.InterNetwork)
                {
                    IPv4Addresses.Add(ipAddress.Address);
                }
            }
        }
    }
    return IPv4Addresses;
}        

Use UdpClient to send/receive message.

C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
namespace IPMessager
{
    public delegate void UdpMessageReceivedDelegate(byte[] message, IPEndPoint remoteEP);
    public class UdpService
    {
        public int PortNumber;
        bool listening = false;
        UdpClient udpClient;
        public UdpMessageReceivedDelegate MessageReceived;
        public void Start(IPEndPoint ipEndPoint)
        {
            if (udpClient != null)
            {
                Stop();
            }
            PortNumber = ipEndPoint.Port;
            udpClient = new UdpClient(ipEndPoint);
            udpClient.EnableBroadcast = true;
            listening = true;
            udpClient.BeginReceive(new AsyncCallback(OnRreceive), null);
        }
        public void Stop()
        {
            listening = false;
            if (udpClient != null)
            {
                udpClient.Client.Shutdown(SocketShutdown.Both);
                udpClient.Close();
            }
        }
        void OnRreceive(IAsyncResult result)
        {
            if (listening)
            {
                try
                {
                    IPEndPoint remoteEP = new IPEndPoint(IPAddress.Any, PortNumber);
                    byte[] data = udpClient.EndReceive(result, ref remoteEP);
                    if (MessageReceived != null)
                    {
                        MessageReceived(data, remoteEP);
                    }
                }
                catch (ArgumentException)
                {
                }
            }
            if (listening)
            {
                udpClient.BeginReceive(new AsyncCallback(OnRreceive), null);
            }
        }
        public void SendMessage(byte[] message)
        {
            SendMessage(message, new IPEndPoint(IPAddress.Broadcast, PortNumber));
        }
        public void SendMessage(byte[] data, IPEndPoint target)
        {
            udpClient.Send(data, data.Length, target);
        }
    }
}

Use TcpClient to send/receive files. TcpService is for listening to TCP connection.

C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Threading;
namespace IPMessager
{
    public delegate void TcpConnectionAcceptedDelegate(TcpConnection tcpConnection);
    public class TcpService
    {
        IPEndPoint selfIPEndPoint;
        TcpListener tcpListener;
        bool listening = false;
        public TcpConnectionAcceptedDelegate TcpConnectionAccepted;

        public void Start(IPEndPoint ipEndPoint)
        {
            selfIPEndPoint = ipEndPoint;
            tcpListener = new TcpListener(selfIPEndPoint);
            tcpListener.Server.SetSocketOption(SocketOptionLevel.Socket, 
				SocketOptionName.ReuseAddress, true);
            tcpListener.Server.NoDelay = true;
            tcpListener.Start();
            listening = true;
            tcpListener.BeginAcceptTcpClient(new AsyncCallback(OnAcceptTcpCliet), null);
        }

        void OnAcceptTcpCliet(IAsyncResult result)
        {
            if (listening)
            {
                TcpClient client = tcpListener.EndAcceptTcpClient(result);
                client.Client.SetSocketOption(SocketOptionLevel.Socket, 
				SocketOptionName.ReuseAddress, true);
                client.Client.NoDelay = true;
                if (TcpConnectionAccepted != null)
                {
                    Thread thread = new Thread(new ParameterizedThreadStart(
                        delegate(object obj)
                        {
                            TcpConnectionAccepted((TcpConnection)obj);
                        }));
                    thread.Start(new TcpConnection(client));
                }
            }
            if (listening)
            {
                tcpListener.BeginAcceptTcpClient
			(new AsyncCallback(OnAcceptTcpCliet), null);
            }
        }

        public void Stop()
        {
            listening = false;
            if (tcpListener != null)
            {
                tcpListener.Stop();
            }
        }
    }
}

TcpConnection is for sending/receiving data through TCP.

C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using System.Net;
using System.Net.Sockets;
namespace IPMessager
{
    public class TcpConnection
    {
        IPEndPoint selfIPEndPoint;
        TcpClient tcpClient;
        NetworkStream networkStream;
        public TcpConnection(IPEndPoint ipEndPoint)
        {
            selfIPEndPoint = ipEndPoint;
        }
        public TcpConnection(TcpClient client)
        {
            tcpClient = client;
            networkStream = tcpClient.GetStream();
        }
        public IPEndPoint RemoteEndPoint
        {
            get { return (IPEndPoint)tcpClient.Client.RemoteEndPoint; }
        }
        public bool Open(IPEndPoint ipEndPoint)
        {
            //tcpClient = new TcpClient(selfIPEndPoint);
            tcpClient = new TcpClient();
            tcpClient.Client.SetSocketOption
		(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
            tcpClient.Connect(ipEndPoint);
            if (tcpClient.Connected)
            {
                networkStream = tcpClient.GetStream();
                return true;
            }
            return false;
        }
        public void Close()
        {
            tcpClient.Client.Shutdown(SocketShutdown.Both);
            networkStream.Close();
            tcpClient.Close();
        }
        public void Send(byte[] data)
        {
            networkStream.Write(data, 0, data.Length);
        }
        public void Send(Stream stream, Action<long> progressUpdate)
        {
            long bytesTransferred = 0;
            int bytesRead = 1;
            byte[] buffer = new byte[tcpClient.SendBufferSize];
            while (stream.CanRead && bytesRead > 0)
            {
                bytesRead = stream.Read(buffer, 0, buffer.Length);
                networkStream.Write(buffer, 0, bytesRead);
                bytesTransferred += bytesRead;
                if (progressUpdate != null)
                {
                    progressUpdate(bytesTransferred);
                }
            }
        }
        public byte[] Receive()
        {
            int loop = 0;
            while (loop < 1000)
            {
                if (networkStream.DataAvailable)
                {
                    byte[] data = new byte[tcpClient.Available];
                    networkStream.Read(data, 0, data.Length);
                    return data;
                }
                System.Threading.Thread.Sleep(1);
                loop++;
            }
            return null;
        }
        public long Receive(Stream stream, long bytesToReceive, Action<long> progressUpdate)
        {
            long bytesTransferred = 0;
            int bytesRead = 0;
            byte[] buffer = new byte[tcpClient.ReceiveBufferSize];
            int loop = 0;
            while (loop < 1000 && bytesTransferred < bytesToReceive)
            {
                while (networkStream.DataAvailable && bytesTransferred < bytesToReceive)
                {
                    loop = 0;
                    int bytesToRead = (int)(bytesToReceive - bytesTransferred);
                    if (bytesToRead > buffer.Length)
                    {
                        bytesToRead = buffer.Length;
                    }
                    bytesRead = networkStream.Read(buffer, 0, bytesToRead);
                    stream.Write(buffer, 0, bytesRead);
                    bytesTransferred += bytesRead;
                    if (progressUpdate != null)
                    {
                        progressUpdate(bytesTransferred);
                    }
                }
                System.Threading.Thread.Sleep(1);
                loop++;
            }
            stream.Flush();
            return bytesTransferred;
        }
    }
}

Points of Interest

I encountered some problems when using wireless network, any improvement is welcome. The latest source code is available on the Google Code website.

History

  • 2010-01-19
    • Created User Interface
    • Implemented Member recognition and Send/Receive Message
  • 2010-01-20
    • Implemented Receive files
  • 2010-01-21
    • Did code refactoring
    • Implemented Send files
  • 2010-01-22
    • Improved User Interface
  • 2010-01-25
    • Improved attachment list of send message window:
      • remove attachment
      • display file icon
      • attach folder
      • clear all
    • Implemented Receive and Send folder
  • 2010-01-26
    • Added two Tabs to show sending files and logs
  • 2010-01-27
    • Added an option dialog to configure some options
  • 2010-01-28
    • Allowed drag files to attachment list
    • Added a Reply button to MessageWindows
    • Ensured only one instance of the application is running
  • 2010-01-29
    • Displayed user icon
  • 2010-02-08
    • Added an About dialog

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect YunCheDa Hangzhou
China China
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralNo able to run Pin
Pranay Rana26-Feb-10 0:34
professionalPranay Rana26-Feb-10 0:34 
GeneralRe: No able to run Pin
Liu Junfeng27-Feb-10 2:51
Liu Junfeng27-Feb-10 2:51 
GeneralMy vote of 5 Pin
Krunal Mevada26-Feb-10 0:31
Krunal Mevada26-Feb-10 0:31 
GeneralSo good! Pin
Eckel Chung26-Feb-10 0:02
Eckel Chung26-Feb-10 0:02 
GeneralNice Pin
Som Shekhar25-Feb-10 20:19
Som Shekhar25-Feb-10 20:19 
GeneralRe: Nice Pin
Krunal Mevada26-Feb-10 0:30
Krunal Mevada26-Feb-10 0:30 
GeneralRe: Nice Pin
Som Shekhar26-Feb-10 0:40
Som Shekhar26-Feb-10 0:40 
GeneralRe: Nice Pin
Sunil Wise26-Feb-10 23:05
professionalSunil Wise26-Feb-10 23:05 
sure Please Send the code for notify icon
GeneralRe: Nice Pin
Som Shekhar26-Feb-10 23:25
Som Shekhar26-Feb-10 23:25 
GeneralRe: Nice Pin
Liu Junfeng27-Feb-10 2:41
Liu Junfeng27-Feb-10 2:41 
GeneralRe: Nice Pin
Som Shekhar27-Feb-10 2:54
Som Shekhar27-Feb-10 2:54 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.