Login | Register   
RSS Feed
Download our iPhone app
Browse DevX
Sign up for e-mail newsletters from DevX

By submitting your information, you agree that devx.com may send you DevX offers via email, phone and text message, as well as email offers about other products and services that DevX believes may be of interest to you. DevX will process your information in accordance with the Quinstreet Privacy Policy.


Extend Your Instant Messenger Application with FTP Support and Private Chat : Page 4

In part 1 of this article, you learned to create a mult-user chat application using network programming in .NET. In this article, you'll build on that application to add sophisticated features such as file downloads.




Application Security Testing: An Integral Part of DevOps

Building the Client
Now that the server is built, it is time to build the client. Using Visual Studio 2005, I create a new Windows application (name it WinClient) and populate the default form with the controls shown in Figure 7 and note the following:
  • Set the Multiline property of txtMessageHistory to True and the ReadOnly property to True.
  • Set the SelectionMode property of lstUsers to MultiExtended.

Figure 7. Adding Controls: Populate the Windows Form with the various controls shown in the screen shot.

Double-click on the form to switch to the code behind. Import the following namespaces:

Imports System.Net.Sockets Imports System.IO

Within the Form1 class, define the following variables and constants:

'---get own IP address Dim ips As Net.IPHostEntry = _ Net.Dns.Resolve(Net.Dns.GetHostName()) '---port nos and server IP address Const PORTNO As Integer = 500 Const FTPPORTNO As Integer = 501 Const SERVERIP As String = "" Dim client As TcpClient '--used for sending and receiving data Dim data() As Byte '---for FTP use Dim fs As System.IO.FileStream Dim filename As String Dim fullfilename As String

When the user signs in, the client first connects to the server and sends the nickname of the user using the SendMessage() subroutine (defined shortly). Then it begins reading data from the server asynchronously and changes the name of the Sign In button to "Sign Out." It will also ask for the list of names of users currently logged in.

When the user signs out of the chat application, you invoke the Disconnect() subroutine (defined shortly).

'--Sign in to server--- Private Sub btnSignIn_Click( _ ByVal sender As System.Object, _ ByVal e As System.EventArgs) _ Handles btnSignIn.Click If btnSignIn.Text = "Sign In" Then '---Sign in to the server Try client = New TcpClient ' client.NoDelay = True '---connect to the server client.Connect(SERVERIP, PORTNO) ReDim data(client.ReceiveBufferSize - 1) '---inform the server of your nick name--- ' e.g. [Join][User1] SendMessage("[Join][" & txtNick.Text & "]") '---begin reading data asynchronously from 'the server client.GetStream.BeginRead( _ data, 0, CInt(client.ReceiveBufferSize), _ AddressOf ReceiveMessage, Nothing) '---change the button and textbox btnSignIn.Text = "Sign Out" btnSend.Enabled = True txtNick.Enabled = False '---get all users connected ' e.g. [Usrs] System.Threading.Thread.Sleep(500) SendMessage("[Usrs]") Catch ex As Exception MsgBox(ex.ToString) End Try Else '---Sign off from the server Disconnect() lstUsers.Items.Clear() '---change the button and textbox btnSignIn.Text = "Sign In" btnSend.Enabled = False txtNick.Enabled = True End If End Sub

The Send button sends a message to the server. Note that you need to select a user in the ListBox before you can send a message.

'---Send Button Private Sub btnSend_Click( _ ByVal sender As System.Object, _ ByVal e As System.EventArgs) _ Handles btnSend.Click ' e.g. [Talk][User2,User3,etc]User1>Hello world! '---select users to chat If lstUsers.SelectedItems.Count < 1 Then MsgBox("You must select who to chat with.") Exit Sub End If '---formulate the message Dim Message As String = "[Talk][" '---check who to chat with Dim user As Object For Each user In lstUsers.SelectedItems Message += user & "," Next Message += "]" & txtNick.Text & ">" & txtMessage.Text '---update the message history txtMessageHistory.Text += txtNick.Text & _ ">" & txtMessage.Text & vbCrLf '---send message SendMessage(Message) txtMessage.Clear() End Sub

The SendMessage() subroutine, used in the code above, allows the client to send a message to the server:

'---Sends the message to the server Public Sub SendMessage(ByVal message As String) Try '---send the text Dim ns As System.Net.Sockets.NetworkStream SyncLock client.GetStream ns = client.GetStream Dim bytesToSend As Byte() = _ System.Text.Encoding. _ ASCII.GetBytes(message) '---sends the text--- ns.Write(bytesToSend, 0, bytesToSend.Length) ns.Flush() End SyncLock Catch ex As Exception MsgBox(ex.ToString) End Try End Sub

The ReceiveMessage() subroutine asynchronously reads data sent from the server in a separate thread. When the data is received, it will display the data in the txtMessageHistory control. As Windows controls are not thread-safe, you need to use a delegate, delUpdateHistory(), to update the controls.

'---Receives a message from the server Public Sub ReceiveMessage(ByVal ar As IAsyncResult) Try Dim bytesRead As Integer bytesRead = client.GetStream.EndRead(ar) If bytesRead < 1 Then Exit Sub Else Dim messageReceived As String = _ System.Text.Encoding.ASCII.GetString( _ data, 0, bytesRead) '---update the message history Dim para() As Object = {messageReceived} Me.Invoke(New delUpdateHistory(AddressOf _ Me.UpdateHistory), para) End If '---continue reading for more data client.GetStream.BeginRead(data, 0, _ CInt(client.ReceiveBufferSize), _ AddressOf ReceiveMessage, Nothing) Catch ex As Exception ' MsgBox(ex.ToString) End Try End Sub

The delUpdateHistory() delegate is used to invoke the UpdateHistory() function in the main thread:

'---delegate to update the textboxes in the main thread Public Delegate Sub delUpdateHistory(ByVal str As String)

In the UpdateHistory() subroutine, you examine the message format and perform the appropriate action. For example, if the user has left a chat (through the [Left] message), you must remove the user name from your ListBox. Listing 2 shows the code for the UpdateHistory() subroutine.

When the Send File button is clicked, check to see that a recipient user is selected and then prompt the user to select a file to send (see Listing 3).

The FTP_Send subroutine (see Listing 4) sends a file to the recipient through the TCP port 501. It sends files in blocks of 8192 bytes (the maximum buffer size).

The FTP_Receive subroutine (see Listing 5) receives an incoming file through TCP port 501. It writes the file to the c:\temp\ directory.

When the form is closed (by clicking on the "X" button on the window), disconnect the client from the server. This code handles the form close action:

Private Sub Form1_FormClosing( _ ByVal sender As Object, _ ByVal e As System.Windows.Forms.FormClosingEventArgs) _ Handles Me.FormClosing Disconnect() End Sub

The Disconnect() subroutine handles the actual disconnection of the client from the server:

'---disconnect from the server Public Sub Disconnect() Try client.GetStream.Close() client.Close() Catch ex As Exception End Try End Sub

Comment and Contribute






(Maximum characters: 1200). You have 1200 characters left.



Thanks for your registration, follow us on our social networks to keep up-to-date