programming4us
programming4us
WEBSITE

Silverlight Recipes : Using Sockets to Communicate over TCP (part 3)

- Free product key for windows 10
- Free Product Key for Microsoft office 365
- Malwarebytes Premium 3.7.1 Serial Keys (LifeTime) 2019
Let's now look at the codebehind for MainPage in Listing 3.
Listing 3. Codebehind for the MainPage in MainPage.xaml.cs
using System.Windows;
using System.Windows.Controls;

namespace Recipe7_5.ChatClient
{
  public partial class MainPage : UserControl
  {
    public ClientConnectionManager ConnManager { get; set; }

    public MainPage()

{
      InitializeComponent();
      //initialize the ClientConnectionManager
      ConnManager = new ClientConnectionManager { ParentPage = this };
      //set the data context to the ClientConnetionManager
      LayoutRoot.DataContext = ConnManager;
    }

    private void btnJoin_Click(object sender, RoutedEventArgs e)
    {
      ConnManager.Join();
    }
    private void btnLogoff_Click(object sender, RoutedEventArgs e)
    {
      ConnManager.Disconnect();
    }

    private void btnTalk_Click(object sender, RoutedEventArgs e)
    {
      //get the participant name from the Button.Tag
      //which was bound to the name at data binding
      ConnManager.TalkingTo = (sender as Button).Tag as string;
      ShowChatView();
    }

    private void btnSend_Click(object sender, RoutedEventArgs e)
    {
      ConnManager.SendTextMessage();
    }

    private void btnEndChat_Click(object sender, RoutedEventArgs e)
    {
      ConnManager.SendChatEnd();
    }
    internal void ShowParticipantsView()
    {
      viewParticipants.Visibility = Visibility.Visible;
      viewLogin.Visibility = Visibility.Collapsed;
      viewChat.Visibility = Visibility.Collapsed;
    }
    internal void ShowChatView()
    {
      viewParticipants.Visibility = Visibility.Collapsed;
      viewLogin.Visibility = Visibility.Collapsed;
      viewChat.Visibility = Visibility.Visible;

					  

}
    internal void ShowLoginView()
    {
      viewParticipants.Visibility = Visibility.Collapsed;
      viewLogin.Visibility = Visibility.Visible;
      viewChat.Visibility = Visibility.Collapsed;
    }
  }
}

The MainPage constructor creates a new instance of the ClientConnectionManager named ConnManager, initializing its ParentPage property with this Page instance. This is done so that in the ClientConnectionManager implementation, you have access to MainPage and its UI elements to effect various state changes. You also set the DataContext of the topmost Grid named LayoutRoot to ConnManager so that all the bindings to various properties of ClientConnectionManager that you saw in the XAML can be put into effect.

The various Button click handlers are self-explanatory; corresponding functions in the ClientConnectionManager are invoked from them. The ShowLoginView(), ShowParticipantsView(), and ShowChatView() methods toggle between views and are used from within the ClientConnectionManager, as you see next.

We have encapsulated all the client-side sockets-based communication and message processing in ClientConnectionManager. Listing 4 shows the ClientConnectionManager class.

Listing 4. ClientConnectionManager in ConnectionManager.cs
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO;
using System.Net;
using System.Net.Sockets;

namespace Recipe7_5.ChatClient
{
  public class ClientConnectionManager : INotifyPropertyChanged
  {
    public event PropertyChangedEventHandler PropertyChanged;

    //create a new socket
    Socket ClientSocket = new Socket(AddressFamily.InterNetwork,
      SocketType.Stream, ProtocolType.Tcp);
    //reference to the parent page
    public Page ParentPage { get; set; }
    //participants collection
    private ObservableCollection<string> _Participants;
    public ObservableCollection<string> Participants

{
      get { return _Participants; }
      set
      {
        _Participants = value;
        if (PropertyChanged != null)
          PropertyChanged(this, new PropertyChangedEventArgs("Participants"));
      }
    }
    //collection of all messages exchanged in a particular conversation
    private ObservableCollection<TextMessage> _Conversation;
    public ObservableCollection<TextMessage> Conversation
    {
      get { return _Conversation; }
      set
      {
        _Conversation = value;
        if (PropertyChanged != null)
          PropertyChanged(this, new PropertyChangedEventArgs("Conversation"));
      }
    }
    //IP Address of the server connected to
    private string _IP;
    public string IP
    {
      get { return _IP; }
      set
      {
        _IP = value;
        if (PropertyChanged != null)
          PropertyChanged(this, new PropertyChangedEventArgs("IP"));
      }
    }
    //Port connected to
    private string _Port;
    public string Port
    {
      get { return _Port; }
      set
      {
        _Port = value;
        if (PropertyChanged != null)
          PropertyChanged(this, new PropertyChangedEventArgs("Port"));
      }
    }

					  

//name of the person logged in
    private string _Me;
    public string Me
    {
      get { return _Me; }
      set
      {
        _Me = value;
        if (PropertyChanged != null)
          PropertyChanged(this, new PropertyChangedEventArgs("Me"));

      }
    }
    //the other person in a conversation
    private string _TalkingTo;
    public string TalkingTo
    {
      get { return _TalkingTo; }
      set
      {
        _TalkingTo = value;
        if (PropertyChanged != null)
          PropertyChanged(this, new PropertyChangedEventArgs("TalkingTo"));
      }
    }
    //the body of a conversation message
    private string _MessageBody;
    public string MessageBody
    {
      get { return _MessageBody; }
      set
      {
        _MessageBody = value;
        if (PropertyChanged != null)
          PropertyChanged(this, new PropertyChangedEventArgs("MessageBody"));
      }
    }
    //buffer used to receive messages
    private const int RECEIVEBUFFERSIZE = 10 * 1024;
    private byte[] ReceiveBuffer = new Byte[RECEIVEBUFFERSIZE];
    //constructor
    public ClientConnectionManager()
    {
      //initialize the collections
      Participants = new ObservableCollection<string>();

					  

Conversation = new ObservableCollection<TextMessage>();
    }
    //called when the login button is clicked
    public void Join()
    {
      //create a new SocketEventArgs, specify the remote endpoint details
      SocketAsyncEventArgs sockEvtArgs =
        new SocketAsyncEventArgs
        {
          RemoteEndPoint = new IPEndPoint(IPAddress.Parse(IP),
            Convert.ToInt32(Port)),
          UserToken = Me
        };
      //connect a completion handler
      sockEvtArgs.Completed +=
        new EventHandler<SocketAsyncEventArgs>(Connection_Completed);
      //connect asynchronously
      ClientSocket.ConnectAsync(sockEvtArgs);

    }
    //connection completion handler
    void Connection_Completed(object sender, SocketAsyncEventArgs e)
    {
      //connected successfully, send a
      //ConnectionDisconnectionRequest with Connect=true
      if (e.SocketError == SocketError.Success)
      {
        SocketAsyncEventArgs sockEvtArgs =
          new SocketAsyncEventArgs { UserToken = e.UserToken };
        //serialize a new ConnectionDisconnectionMessage into a MemoryStream
        MemoryStream SerializedStream =
          MessageWrapper.SerializeMessage(
          new MessageWrapper
          {
            Message = new ConnectionDisconnectionRequest
            {
              From = e.UserToken as string,
              Connect = true
            }
          });
        //set buffer to the contents of the memorystream
        sockEvtArgs.SetBuffer(SerializedStream.GetBuffer(),
          0, (int)SerializedStream.Length);
        sockEvtArgs.Completed +=
          new EventHandler<SocketAsyncEventArgs>(ConnectionRequestSend_Completed);

					  

//send
        ClientSocket.SendAsync(sockEvtArgs);
      }
    }
    //ConnectionDisconnectionRequest send completion handler
    void ConnectionRequestSend_Completed(object sender, SocketAsyncEventArgs e)
    {
      //sent successfully
      if (e.SocketError == SocketError.Success)
      {
        //start receiving messages
        ReceiveMessage();
        //switch context
        ParentPage.Dispatcher.BeginInvoke(new Action(delegate
        {
          //switch view to participants
          ParentPage.ShowParticipantsView();
        }));
      }
    }
    //receive a message
    private void ReceiveMessage()
    {
      SocketAsyncEventArgs sockEvtArgsReceive = new SocketAsyncEventArgs();
      sockEvtArgsReceive.SetBuffer(ReceiveBuffer, 0, RECEIVEBUFFERSIZE);
      sockEvtArgsReceive.Completed +=
        new EventHandler<SocketAsyncEventArgs>(Receive_Completed);
      ClientSocket.ReceiveAsync(sockEvtArgsReceive);
    }
    //receive completion handler
    void Receive_Completed(object sender, SocketAsyncEventArgs e)
    {
      if (e.SocketError == SocketError.Success)
      {
        ParentPage.Dispatcher.BeginInvoke(new Action(delegate
        {
          //copy the message to a temporary buffer - this is
          //because we reuse the same buffer for all SocketAsyncEventArgs,
          //and message lengths may vary
          byte[] Message = new byte[e.BytesTransferred];
          Array.Copy(e.Buffer, 0, Message, 0, e.BytesTransferred);
          //process the message
          ProcessMessage(Message);
          //keep receiving
          ReceiveMessage();

					  

}));
      }
    }
    //process a message
    internal void ProcessMessage(byte[] Message)
    {
      //deserialize the message into the wrapper
      MessageWrapper mw = MessageWrapper.DeserializeMessage(Message);
      //check type of the contained message
      //correct type resolution is ensured through the
      //usage of KnownTypeAttribute on the MessageWrapper
      //data contract declaration
      if (mw.Message is TextMessage)
      {
        //receiving a text message from someone -
        //switch to chat view if not there already
        ParentPage.ShowChatView();
        //remember the other party in the conversation
        if (this.TalkingTo == null)
          this.TalkingTo = (mw.Message as TextMessage).From;
        //data bind the text of the message
        Conversation.Add(mw.Message as TextMessage);
      }
      //someone has ended an ongoing chat
      else if (mw.Message is ChatEndNotification)
      {
        //reset
        this.TalkingTo = null;
        //reset
        Conversation.Clear();
        //go back to participants list
        ParentPage.ShowParticipantsView();
      }
      //server has sent a reply to your connection request
      else if (mw.Message is ConnectionReply)
      {
        //reset
        Participants.Clear();
        //get the list of the other participants
        List<string> ReplyList = (mw.Message as ConnectionReply).Participants;
        //data bind
        foreach (string s in ReplyList)
          Participants.Add(s);

      }

					  

//someone has connected or disconnected
      else if (mw.Message is ConnectionDisconnectionNotification)
      {
        ConnectionDisconnectionNotification notif =
          mw.Message as ConnectionDisconnectionNotification;
        //if it is a connection
        if (notif.Connect)
          //add to participants list
          Participants.Add(notif.Participant);
        else
        {
          //remove from participants list
          Participants.Remove(notif.Participant);
          //if you were in a conversation with this person,
          //go back to the participants view
          if (notif.Participant == TalkingTo)
          {
            ParentPage.ShowParticipantsView();
          }
        }
      }
    }
    //send a text message
    internal void SendTextMessage()
    {
      //package the From, To and Text of the message
      //into a TextMessage, and then into a wrapper
      MessageWrapper mwSend =
        new MessageWrapper
        {
          Message = new TextMessage {
            From = Me, To = TalkingTo, Body = MessageBody }
        };
      //serialize
      MemoryStream SerializedStream = MessageWrapper.SerializeMessage(mwSend);
      SocketAsyncEventArgs sockEvtArgsSend =
        new SocketAsyncEventArgs { UserToken = mwSend.Message };
      //grab the byte[] and set the buffer
      sockEvtArgsSend.SetBuffer(
        SerializedStream.GetBuffer(), 0, (int)SerializedStream.Length);
      //attach handler
      sockEvtArgsSend.Completed +=
        new EventHandler<SocketAsyncEventArgs>(SendTextMessage_Completed);
      //send
      ClientSocket.SendAsync(sockEvtArgsSend);

					  

}
    //send completed
    void SendTextMessage_Completed(object sender, SocketAsyncEventArgs e)
    {
      //success
      if (e.SocketError == SocketError.Success)
      {
        //switch context
        ParentPage.Dispatcher.BeginInvoke(new Action(delegate
        {
          //send was successful, add message to ongoing conversation
          Conversation.Add(e.UserToken as TextMessage);
          //reset edit box
          MessageBody = "";
        }));
      }
    }
    //disconnect
    internal void Disconnect()
    {
      SocketAsyncEventArgs sockEvtArgs = new SocketAsyncEventArgs();
      //package a ConnectionDisconnectionRequest with Connect=false
      MemoryStream SerializedStream =
        MessageWrapper.SerializeMessage(
        new MessageWrapper
        {
          Message = new ConnectionDisconnectionRequest
          {
            From = Me,
            Connect = false
          }
        });
      sockEvtArgs.SetBuffer(
        SerializedStream.GetBuffer(), 0, (int)SerializedStream.Length);
      sockEvtArgs.Completed +=
        new EventHandler<SocketAsyncEventArgs>(DisconnectRequest_Completed);
      ClientSocket.SendAsync(sockEvtArgs);
    }
    //disconnect completed
    void DisconnectRequest_Completed(object sender, SocketAsyncEventArgs e)
    {
      //success
      if (e.SocketError == SocketError.Success)
      {
        //reset my identity

					  

this.Me = null;
        //clear all participants
        Participants.Clear();
        //show login screen
        ParentPage.ShowLoginView();
      }
    }
    //end a chat
    internal void SendChatEnd()
    {
      MessageWrapper mwSend =
        new MessageWrapper
        {
          Message = new ChatEndNotification { From = Me, To = TalkingTo }
        };
      MemoryStream SerializedStream =
        MessageWrapper.SerializeMessage(mwSend);
      SocketAsyncEventArgs sockEvtArgsSend =
        new SocketAsyncEventArgs { UserToken = mwSend.Message };
      sockEvtArgsSend.SetBuffer(
        SerializedStream.GetBuffer(), 0, (int)SerializedStream.Length);
      sockEvtArgsSend.Completed +=
        new EventHandler<SocketAsyncEventArgs>(SendChatEnd_Completed);
      ClientSocket.SendAsync(sockEvtArgsSend);
    }
    //chat ended
    void SendChatEnd_Completed(object sender, SocketAsyncEventArgs e)
    {
      //success
      if (e.SocketError == SocketError.Success)
      {
        //switch context
        ParentPage.Dispatcher.BeginInvoke(new Action(delegate
        {
          //reset identity of the other participant
          this.TalkingTo = null;
          //clear the conversation
          Conversation.Clear();
          //switch back to the participants view
          ParentPage.ShowParticipantsView();
        }));
      }
    }
  }
}

					  

As discussed before, ClientConnectionManager is used as the datasource for most of the data bound to the XAML for the client UI, and therefore implements INotifyPropertyChanged; the appropriate property setters raise PropertyChanged events.

After the user specifies the IP address, a port, and a participant name in the initial login screen, you establish a connection to the server. To do this, call the Join() method, which uses the Socket.ConnectAsync() method to establish the server connection. You specify the details of the remote endpoint (IP address and port) in the SocketeventArgs parameter. You also specify Connection_Completed() as the completion handler for ConnectAsync().

When a successful socket connection is established, in Connection_Completed() you send the first application-specific message of type ConnectionDisconnectionRequest to the server, with the ConnectionDisconnectionRequest.Connect property set to True, to indicate a request for connection. You wrap the message in an instance of the MessageWrapper type, serialize it to a MemoryStream, and use the MemoryStream contents to fill the send buffer. Attach ConnectionRequestSend_Completed() as the completion handler, and then call SendAsync() to send the request.

When the send request returns, ConnectionRequestSend_Completed() is invoked; you check for a successful send by checking the SocketAsyncEventArgs.SocketError property. In the event of a successful operation, this property is set to SocketError.Success; a plethora of other values indicate different error conditions. On a successful send, you prepare the client for receiving a message back from the server by calling ReceiveMessage(). You also switch the client UI to display the view with the list of participants by calling ShowParticipantsView() on the Page.

In ReceiveMessage(), you use a preallocated buffer to receive all your messages. You call Socket.ReceiveAsync() to start receiving messages, after attaching the Receive_Completed() completion handler. When a message is successfully retrieved, you copy it out of the message buffer into a temporary one before you process the message and take appropriate action. Note that you call ReceiveMessage() again as soon as you complete processing the previous message in order to keep the socket in a constant receive mode and not miss any incoming messages—albeit on a background thread because of the asynchronous nature of ReceiveAsync().

The ProcessMessage() method is central to the client-side message processing. Incoming messages are deserialized from byte[] to MessageWrapper instances by calling MessageWrapper.DeserializeMessage(). The type of the contained message in MessageWrapper.Body is used to determine the action taken.

The first message a client receives is the server's acknowledgment of the connection, in the form of a ConnectionReply message. The ConnectionReply.Participants collection contains the names of all the other participants logged in; you bind that collection to the participants ListBox on the UI and switch the view by calling ShowParticipantsView() on the page.

For incoming TextMessage instances, if the client is not already in chat mode, you switch the UI appropriately by calling ShowChatView() and then display the message by adding it to the Conversations collection bound to the ListBox used to display a conversation. You also set the ClientConnectionManager.TalkingTo property to the name of the participant from whom you are receiving the message, as indicated by the TextMessage.From property.

Clients can also receive a couple of other types of messages. When you receive a ChatEndNotification, you reset the TalkingTo property, clear the conversation ListBox, and switch to the participants view. For a ConnectionDisconnectionNotification, if the Connect property is True (indicating that a new participant is connecting), you add the participant to the bound Participants property; otherwise, you remove them, and switch views if you were currently in conversation with the disconnecting participant.

The ClientConnectionManager class also implements various methods for sending different types of messages from the client. All of these methods follow the same pattern demonstrated when you sent the first ConnectionDisconnectionRequest earlier: you create and initialize a new message instance of the appropriate message type, serialize it using MessageWrapper.SerializeMessage(), and then send it using Socket.SendAsync().

Other  
  •  Microsoft ASP.NET 3.5 : The HTTP Request Context - The global.asax File
  •  Microsoft ASP.NET 3.5 : The HTTP Request Context - Initialization of the Application
  •  Free Email Everywhere and Anytime
  •  IIS 7.0 : Managing Web Sites - Administrative Tasks - Limiting Web Site Usage, Configuring Web Site Logging and Failed Request Tracing
  •  IIS 7.0 : Managing Web Sites - Administrative Tasks - Adding a New Web Site
  •  IIS 7.0 : Managing Worker Processes and Requests
  •  Websocket: Internet In Real Time
  •  IIS 7.0 : Managing Application Pools (part 3) - Advanced Application Pool Configuration, Monitoring Application Pool Recycling Events
  •  IIS 7.0 : Managing Application Pools (part 2) - Managing Application Pool Identities
  •  IIS 7.0 : Managing Application Pools (part 1) - Application Pool Considerations, Adding a New Application Pool
  •  
    Top 10
    Free Mobile And Desktop Apps For Accessing Restricted Websites
    MASERATI QUATTROPORTE; DIESEL : Lure of Italian limos
    TOYOTA CAMRY 2; 2.5 : Camry now more comely
    KIA SORENTO 2.2CRDi : Fuel-sipping slugger
    How To Setup, Password Protect & Encrypt Wireless Internet Connection
    Emulate And Run iPad Apps On Windows, Mac OS X & Linux With iPadian
    Backup & Restore Game Progress From Any Game With SaveGameProgress
    Generate A Facebook Timeline Cover Using A Free App
    New App for Women ‘Remix’ Offers Fashion Advice & Style Tips
    SG50 Ferrari F12berlinetta : Prancing Horse for Lion City's 50th
    - Messages forwarded by Outlook rule go nowhere
    - Create and Deploy Windows 7 Image
    - How do I check to see if my exchange 2003 is an open relay? (not using a open relay tester tool online, but on the console)
    - Creating and using an unencrypted cookie in ASP.NET
    - Directories
    - Poor Performance on Sharepoint 2010 Server
    - SBS 2008 ~ The e-mail alias already exists...
    - Public to Private IP - DNS Changes
    - Send Email from Winform application
    - How to create a .mdb file from ms sql server database.......
    programming4us programming4us
    programming4us
     
     
    programming4us