Click here to Skip to main content
Click here to Skip to main content
Go to top

WPF Version of IPMessager

, 27 Feb 2010
Rate this:
Please Sign up or sign in to vote.
Redeveloped the IPMessager program using C# and WPF

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:

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.

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.

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.

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)

Share

About the Author

Liu Junfeng
Software Developer (Senior) Beyondsoft SH
China China
No Biography provided

Comments and Discussions

 
GeneralMy vote of 5 PinmemberKrunal Mevada26-Feb-10 0:31 

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

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

| Advertise | Privacy | Mobile
Web01 | 2.8.140905.1 | Last Updated 27 Feb 2010
Article Copyright 2010 by Liu Junfeng
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid