Page 1 of 1

Advanced P2P Networking - Chatrooms [Part 1] Rate Topic: -----

#1 Asscotte  Icon User is offline

  • D.I.C Addict
  • member icon

Reputation: 35
  • View blog
  • Posts: 610
  • Joined: 08-February 09

Posted 20 January 2010 - 12:03 PM

Title:
Advanced P2P Networking - Chatrooms

Topic Description:
How to correctly use P2P on a more advanced level.

Difficulty Level:
Intermediate


Advanced P2P - Chatroom

Intro:
I will start by saying that the following code is not 100% bug free, more about 97% Also I would like to say that the code shows how to correctly create and maintain connections via P2P in vb.net. The code displayed in the article is based on some code by William Moeur, from 2006. I have 'modernised' it, and made it more user friendly. Below are the original pieces of code. Both halves are required for either user in a Server application or use in a client application. To follow this tutorial you will require a fairly solid knowledge of Visual Basic dot net. The way that this code works is that all data gets sent to the server then returned rather than direct client to client.

clsListener.vb
' clsListener - Used on the server end of TCP/IP communications
'			   Dynamically loads tcpConnections as connections are requested
'
'   Copyright (C) 2006  William Moeur
'   This program is free software; you can redistribute it and/or modify it
'
'Constructor: 
'		   Private WithEvents listener As clsListener
'		   listener = New clsListener(PORT_NUM, optional PacketSize)
'
'Events:
'	   ConnectionRequest(Requestor, AllowConnection) - Raised when a new connection request is made.
'		   Set AllowConnection to True to accept connection, otherwise connection is denied.
'
'	   Disconnect(Client) - A client has disconnected.
'
'	   MessageReceived(Client, msgTag)
'	   StringReceived(Client, msgTag, StrMessage) - Data is in a String
'	   DataReceived(Client, msgTag, memStream) - Data is in a memoryStream
'		   MsgTag is a 1-byte message identifier defined by end user
'		   
'Methods: Send messages to all connected clients
'	   Broadcast(msgTag) - Sends a 1-byte message
'	   Broadcast(msgTag, strX) - Sends a message string
'	   Broadcast(msgTag, byteData()) - Sends array of Byte data

Option Strict On
Option Explicit On

Imports System.Net.Sockets
Imports System.IO
Imports System.Collections.Generic

Public Class clsListener
	Private Enum RequestTags As Byte
		Connect = 1
		Disconnect = 2
		DataTransfer = 3
		StringTransfer = 4
		ByteTransfer = 5
	End Enum

	Private Server As TcpListener
	Private Clients As Dictionary(Of Int16, tcpConnection)
	Private nClients As Byte
	Private mPacketSize As Int16

#Region "Event Declarations"
	Public Event ConnectionRequest(ByVal Requestor As TcpClient, ByRef AllowConnection As Boolean)
	Public Event DataReceived(ByVal Client As tcpConnection, ByVal msgTag As Byte, ByVal mStream As MemoryStream)
	Public Event MessageReceived(ByVal Client As tcpConnection, ByVal message As Byte)
	Public Event StringReceived(ByVal Client As tcpConnection, ByVal msgTag As Byte, ByVal message As String)
	Public Event Disconnect(ByVal Client As tcpConnection)
#End Region

	Public Sub New(ByVal nPort As Integer, Optional ByVal PacketSize As Int16 = 4096)
		'constructor:
		'Creates a dictionary to store client connections
		'and starts listening for connection requests on the
		'port specified
		mPacketSize = packetsize
		Clients = New Dictionary(Of Int16, tcpConnection)
		Listen(nPort)
	End Sub

	Private Sub Listen(ByVal nPort As Integer)
		'instantiate the listener class
		Server = New TcpListener(System.Net.IPAddress.Any, nPort)
		'start listening for connection requests
		Server.Start()
		'asyncronously wait for connection requests
		Server.BeginAcceptTcpClient(New AsyncCallback(AddressOf DoAcceptTcpClientCallback), Server)
	End Sub

	Private Sub DoAcceptTcpClientCallback(ByVal ar As IAsyncResult)
		' Processes the client connection request.
		' A maximum of 255 connections can be made.
		Dim Allowed As Boolean

		' Get the listener that handles the client request.
		Dim listener As TcpListener = CType(ar.AsyncState, TcpListener)

		Dim client As TcpClient = listener.EndAcceptTcpClient(ar)
		'ask end user if he wants to accept this connection request
		RaiseEvent ConnectionRequest(client, Allowed)

		If Not Allowed Then
			SendMessage(RequestTags.Disconnect, 0, client)
			client.GetStream.Close()
			client.Close()
			client = Nothing
		Else
			'add client to list of connected clients
			SendMessage(RequestTags.Connect, mPacketSize, client)
			Dim newClient As tcpConnection = New tcpConnection(client, mPacketSize)
			newClient.Tag = nClients
			Clients.Add(nClients, newClient)
			nClients += CByte(1)

			'need to delegate events for client since client
			'is created dynamically and is going to be put into a 
			'collection so this is how we are going to propagate 
			'the events up to the end user
			AddHandler newClient.DataReceived, AddressOf onDataReceived
			AddHandler newClient.MessageReceived, AddressOf onMessageReceived
			AddHandler newClient.StringReceived, AddressOf onStringReceived
			AddHandler newClient.Disconnect, AddressOf onClientDisconnect
			newClient = Nothing
		End If

		'continue listening
		listener.BeginAcceptTcpClient(New AsyncCallback(AddressOf DoAcceptTcpClientCallback), listener)

	End Sub 'DoAcceptTcpClientCallback

	Private Sub SendMessage(ByVal msgTag As Byte, ByVal msg As Int16, ByVal client As TcpClient)
		' This subroutine sends a one-byte response through a tcpClient
		' Synclock ensure that no other threads try to use the stream at the same time.
		SyncLock client.GetStream
			Dim writer As New BinaryWriter(client.GetStream)
			writer.Write(msgTag)
			writer.Write(msg)
			' Make sure all data is sent now.
			writer.Flush()
		End SyncLock
	End Sub

#Region "Overloaded Broadcast methods send data to all client connections"
	Public Sub Broadcast(ByVal msgTag As Byte)
		For Each myClient As KeyValuePair(Of Short, tcpConnection) In Clients
			Clients(myClient.Key).Send(msgTag)
		Next
	End Sub

	Public Sub Broadcast(ByVal msgTag As Byte, ByVal strX As String)
		For Each myClient As KeyValuePair(Of Short, tcpConnection) In Clients
			Clients(myClient.Key).Send(msgTag, strX)
		Next
	End Sub

	Public Sub Broadcast(ByVal msgTag As Byte, ByVal byteData() As Byte)
		For Each myClient As KeyValuePair(Of Short, tcpConnection) In Clients
			Clients(myClient.Key).Send(msgTag, byteData)
		Next
	End Sub
#End Region

#Region "Events handlers for the clients"
	Private Sub onClientDisconnect(ByVal Client As tcpConnection)
		RaiseEvent Disconnect(Client)
		'close client and remove from collection
		Clients.Remove(Client.Tag)
		Client = Nothing
	End Sub

	Private Sub onDataReceived(ByVal client As tcpConnection, ByVal msgTag As Byte, ByVal mstream As MemoryStream)
		RaiseEvent DataReceived(client, msgTag, mstream)
	End Sub

	Private Sub onMessageReceived(ByVal Client As tcpConnection, ByVal message As Byte)
		RaiseEvent MessageReceived(Client, message)
	End Sub

	Private Sub onStringReceived(ByVal Sender As tcpConnection, ByVal msgTag As Byte, ByVal message As String)
		RaiseEvent StringReceived(Sender, msgTag, message)
	End Sub
#End Region

End Class



tcpConnection.vb
' tcpConnection Class - Can be used on the client end of a TCP/IP
'					   Client-server application.  Also used by the
'					   clsListener class on the Server End.
'
'   Copyright (C) 2006  William Moeur
'   This program is free software; you can redistribute it and/or modify it
'
'Constructor:
'	   From Client: 
'			   Private WithEvents client As tcpConnection
'			   client = New tcpConnection("localhost", PORT_NUM)
'	   From Server:
'			   clsListener handles this
'
'Methods: MsgTag is a 1-byte message identifier defined by end user
'	   Send(msgTag) - sends only the user-defined message tag
'	   Send(msgTag, strX) - sends a string
'	   Send(msgTag, byteData()) - sends an array of bytes
'	   SendFile(msgTag, FilePath) - Sends the contents of the file located at FilePath
'
'Events:
'	   Connect(ByVal sender As tcpConnection)
'	   Disconnect(ByVal Sender As tcpConnection)
'
'   Data Reception: MsgTag is a 1-byte message identifier defined by end user
'	   MessageReceived(Sender, msgTag)
'	   StringReceived(Sender, msgTag, StrMessage) - Data is in a String
'	   DataReceived(Sender, msgTag, memStream) - Data is in a memoryStream
'		   
'	   TransferProgress(Sender, msgTag, Percentage) - periodically announces percentage of data
'		   transfer that has been completed
'
Option Strict On
Option Explicit On

Imports System.Net.Sockets
Imports System.IO

Public Class tcpConnection
	Private Enum RequestTags As Byte
		Connect = 1
		Disconnect = 2
		DataTransfer = 3
		StringTransfer = 4
		ByteTransfer = 5
	End Enum

	Private PACKET_SIZE As Int16 = 4096
	Private client As TcpClient
	Private readByte(0) As Byte
	Private myTag As Byte
	Private isConnected As Boolean 'set to true when connection is granted by server

#Region "Declare events"
	Public Event DataReceived(ByVal sender As tcpConnection, ByVal msgTag As Byte, ByVal mstream As MemoryStream)
	Public Event MessageReceived(ByVal sender As tcpConnection, ByVal msgTag As Byte)
	Public Event StringReceived(ByVal Sender As tcpConnection, ByVal msgTag As Byte, ByVal message As String)
	Public Event TransferProgress(ByVal Sender As tcpConnection, ByVal msgTag As Byte, ByVal Percentage As Single)
	Public Event Connect(ByVal sender As tcpConnection)
	Public Event Disconnect(ByVal sender As tcpConnection)
#End Region

#Region "Overloaded Constructors and destructor"
	Public Sub New(ByVal client As TcpClient, ByVal PacketSize As Int16)
		'instantiates class for use in server
		'don't handle errors here, allow caller to handle them
		PACKET_SIZE = PacketSize
		Me.client = client
		'Start an asynchronous read from the NetworkStream
		Me.client.GetStream.BeginRead(readByte, 0, 1, AddressOf ReceiveOneByte, Nothing)
	End Sub

	Public Sub New(ByVal IPServer As String, ByVal Port As Integer)
		'instantiates class for use in client
		'don't handle errors here, allow caller to handle them
		'create a new TcpClient and make a synchronous connection 
		'attempt to the provided host name and port number
		Me.client = New TcpClient(IPServer, Port)
		'Start an asynchronous read from the NetworkStream
		Me.client.GetStream.BeginRead(readByte, 0, 1, AddressOf ReceiveOneByte, Nothing)
	End Sub

	Protected Overrides Sub finalize()
		'we don't care about errors in this section since we are ending
		On Error Resume Next
		If isConnected Then Send(RequestTags.Disconnect)
		client.GetStream.Close()
		client.Close()
		client = Nothing
	End Sub

#End Region

	Public Property Tag() As Byte
		Get
			Tag = myTag
		End Get
		Set(ByVal value As Byte)
			myTag = value
		End Set
	End Property

	Private Sub ReceiveOneByte(ByVal ar As IAsyncResult)
		'This is where the data is received.  All data communications 
		'begin with a one-byte identifier that tells the class how to
		'handle what is to follow.
		Dim r As BinaryReader
		Dim sreader As StreamReader
		Dim mStream As MemoryStream
		Dim lData As Int32
		Dim readBuffer(PACKET_SIZE) As Byte
		Dim StrBuffer(PACKET_SIZE) As Char
		Dim passThroughByte As Byte
		Dim nData As Integer
		Dim lenData As Integer

		SyncLock client.GetStream
			'if error occurs here then socket has closed
			Try
				client.GetStream.EndRead(ar)
			Catch
				RaiseEvent Disconnect(Me)
				Exit Sub
			End Try
		End SyncLock
		'this is the instruction on how to handle the rest of the data to come.
		Select Case readByte(0)
			Case RequestTags.Connect
				'sent from server to client informing client that a successful 
				'connection negotiation has been made and the connection now exists.
				isConnected = True 'identifies this class as on the client end
				RaiseEvent Connect(Me)
				SyncLock client.GetStream
					r = New BinaryReader(client.GetStream)
					PACKET_SIZE = r.ReadInt16
					'Continue the asynchronous read from the NetworkStream
					Me.client.GetStream.BeginRead(readByte, 0, 1, AddressOf ReceiveOneByte, Nothing)
				End SyncLock

			Case RequestTags.Disconnect
				'sent to either client or server
				'propagated forward to Listener on server end
				RaiseEvent Disconnect(Me)

			Case RequestTags.DataTransfer
				'a block of data is coming
				'Format of this transaction is
				'   DataTransfer identifier byte
				'   Pass-Through Byte contains user defined data
				'   Length of data block (max size = 2,147,483,647 bytes)
				SyncLock client.GetStream
					r = New BinaryReader(client.GetStream)
					'next we expect a pass-through byte
					client.GetStream.Read(readByte, 0, 1)
					passThroughByte = readByte(0)
					'next expect length of data (Int32)
					nData = r.ReadInt32
					lenData = nData
					'now comes the data, save it in a memory stream
					mStream = New MemoryStream
					While nData > 0
						RaiseEvent TransferProgress(Me, passThroughByte, CSng(1.0 - nData / lenData))
						lData = client.GetStream.Read(readBuffer, 0, PACKET_SIZE)
						mStream.Write(readBuffer, 0, lData)
						nData -= lData
					End While
					'Continue the asynchronous read from the NetworkStream
					Me.client.GetStream.BeginRead(readByte, 0, 1, AddressOf ReceiveOneByte, Nothing)
				End SyncLock
				'once all data has arrived, pass it on to the end user as a stream
				RaiseEvent DataReceived(Me, passThroughByte, mStream)
				mStream.Dispose()

			Case RequestTags.StringTransfer
				'Here we receive the transfer of string data in a block
				'not to exceed PACKET_SIZE in length.
				SyncLock client.GetStream
					sreader = New StreamReader(client.GetStream)
					'next we expect a pass-through byte
					client.GetStream.Read(readByte, 0, 1)
					passThroughByte = readByte(0)
					nData = sreader.Read(StrBuffer, 0, PACKET_SIZE)
				End SyncLock
				Dim strX As New String(StrBuffer, 0, nData)

				'pass string on to end user
				RaiseEvent StringReceived(Me, passThroughByte, strX)
				SyncLock client.GetStream
					'Continue the asynchronous read from the NetworkStream
					Me.client.GetStream.BeginRead(readByte, 0, 1, AddressOf ReceiveOneByte, Nothing)
				End SyncLock

			Case RequestTags.ByteTransfer
				'Here we receive a user-defined one-byte message
				SyncLock client.GetStream
					client.GetStream.Read(readByte, 0, 1)
				End SyncLock
				'pass byte on to end user
				RaiseEvent MessageReceived(Me, readByte(0))
				SyncLock client.GetStream
					'Continue the asynchronous read from the NetworkStream
					Me.client.GetStream.BeginRead(readByte, 0, 1, AddressOf ReceiveOneByte, Nothing)
				End SyncLock

		End Select

	End Sub


#Region "Overloaded methods to send data between client(s) and server"

	Public Sub Send(ByVal msgTag As Byte)
		' This subroutine sends a one-byte response
		SyncLock client.GetStream
			Dim writer As New BinaryWriter(client.GetStream)
			'notify that 1-byte is coming
			writer.Write(RequestTags.ByteTransfer)
			'Send user defined message byte
			writer.Write(msgTag)
			' Make sure all data is sent now.
			writer.Flush()
		End SyncLock
	End Sub

	Public Sub Send(ByVal msgTag As Byte, ByVal strX As String)
		'sends a string of max length PACKET_SIZE
		SyncLock client.GetStream
			Dim writer As New StreamWriter(client.GetStream)
			'Notify other end that a string block is coming
			writer.Write(Chr(RequestTags.StringTransfer))
			'Send user defined message byte
			writer.Write(Chr(msgTag))
			'Send the string
			writer.Write(strX)
			'make sure all data gets sent now
			writer.Flush()
		End SyncLock
	End Sub

	Public Sub Send(ByVal msgTag As Byte, ByVal byteData() As Byte)
		'sends array of byte data
		SyncLock client.GetStream
			Dim writer As New BinaryWriter(client.GetStream)
			'Notify that byte data is coming
			writer.Write(RequestTags.DataTransfer)
			'send user-define message byte
			writer.Write(msgTag)
			'send length of data block
			writer.Write(byteData.Length)
			'send the data
			writer.Write(byteData)
			'make sure all data is sent
			writer.Flush()
		End SyncLock
	End Sub

	Public Sub SendFile(ByVal msgTag As Byte, ByVal FilePath As String)
		'max filesize is 2GB
		Dim byteArray() As Byte
		Dim fs As FileStream = New FileStream(FilePath, FileMode.Open, FileAccess.Read)
		Dim r As New BinaryReader(fs)

		SyncLock client.GetStream
			Dim w As New BinaryWriter(client.GetStream)
			'notify that file data is coming
			w.Write(RequestTags.DataTransfer)
			'send user-define message byte
			w.Write(msgTag)
			'send size of file
			w.Write(CInt(fs.Length))
			'Send the file data
			Do
				'read data from file
				byteArray = r.ReadBytes(PACKET_SIZE)
				'write data to Network Stream
				w.Write(byteArray)
			Loop While byteArray.Length = PACKET_SIZE
			'make sure all data is sent
			w.Flush()
		End SyncLock
	End Sub
#End Region

End Class




As you can probally see the code is quite dated, but well comented and I recommend a quick glance at it before continuing on with the tutorial. The basic way that the above code works is that a message consists of three parts but a coder / user on gets to use two. There are two byte tags that get sent with any message be it a file or a string. This is for the simple purpose that it helps you identify what is being recived. For example, if Bob sent Anne the string "Hello World" it would get turned into the binary "0100100001100101011011000110110001101111001000000101011101101111011100100110110001100100". When Anne receives the binary message how can she work out what it is? There are two methods, one is through trial and error, guessing what the binary message is; Turn the message into a file, ask Anne if it is right if it isnt turn it into a picture, ask anne if its right if it isnt... etc. That would take ages so what we do is tack a one byte tag to the start of the sent data to identify its type, so Anne can easily work out what she has just been sent.

In the above code the byte tags are:
	Private Enum RequestTags As Byte ' NB: Note the "As Byte"'
' Signals a client wishes to connect. '
		Connect = 1
'Signals when a client wishes to disconnect'
		Disconnect = 2

'These are pretty self explanatory.'
		DataTransfer = 3
		StringTransfer = 4
		ByteTransfer = 5
	End Enum



The catch is that both halves of the P2P network, (Server & Client), must have the same Enum or this will not work. Then the next byte tag after the identifier is the user Byte tag. This is so that you, the coder can see what you have recived for example you may be expecting two strings, A: "Hello World" and B: "Goodbye World". How can you tell the difference? well you simply create a new Enum As Byte and your done:

Public Enum WorldType as Byte
Hello = 1
Goodbye = 2
End Enum



And then the third part of the data is whatever you send, unless you just send a message tag. Simple really once you understand the logic behind it. You could go away from this tutorial and create a P2P system just from that but, why not stick around a while longer.


Upgrades

So when I upgraded the code to VB 08 I found that there were some still quite old 'mistakes'. The one of the biggest being limiting the server to only 255 clients, as there are only 256 values in a byte but we don't count the zero. This is shown in the below code:

   Private Clients As Dictionary(Of Int16, tcpConnection)



This is a bit old now so I replaced it with a Custom structure:
 Public Structure ClientDataHolder
		Dim UsernameName As String
		Dim Client As RTS_SocketClient
		Dim Tag As Byte
	End Structure



Which works just fine. So I then just declared Clients as an Arraylist rather than a Dictionary.

Down To The Code...
Below I have placed both halves of the code and I will explain each after the code.

RTS_Listener.vb (Server code)
Option Strict On
Option Explicit On

Imports System.Net.Sockets
Imports System.IO
Imports System.Collections.Generic
Imports System.Net

Friend Class RTS_Listener

	Private Enum RequestTags As Byte
		Connect = 1
		Disconnect = 2
		DataTransfer = 3
		StringTransfer = 4
		ByteTransfer = 5
	End Enum

	Private Server As TcpListener
	Private Clients As New ArrayList
	Private BootedUsers As New ArrayList
	Private nClients As Byte
	Private mPacketSize As Int16

#Region "Event Declarations"
	Public Event ConnectionRequest(ByVal Requestor As TcpClient, ByRef AllowConnection As Boolean)
	Public Event DataReceived(ByVal Client As RTS_SocketClient, ByVal msgTag As Byte, ByVal mStream As MemoryStream)
	Public Event MessageReceived(ByVal Client As RTS_SocketClient, ByVal message As Byte)
	Public Event StringReceived(ByVal Client As RTS_SocketClient, ByVal msgTag As Byte, ByVal message As String)
	Public Event Disconnect(ByVal Client As RTS_SocketClient)
	Public Event ClientLoggedIn(ByVal Username As String)
#End Region

#Region " Reverse Modulation Code"
	Public Structure ClientDataHolder
		Dim UsernameName As String
		Dim Client As RTS_SocketClient
		Dim Tag As Byte
	End Structure

	Public Structure _BootedUser
		Dim IP As String
		Dim Tag As Byte
		Dim Username As String
	End Structure

	Public Sub Close()
		Try
			Server.Stop()
			Clients = New ArrayList
		Catch ex As Exception
			Server.Stop()
		End Try
	End Sub

	Public Sub New(Optional ByVal PacketSize As Int16 = 4096)
		'constructor:
		'Creates a array to store client connections
		mPacketSize = PacketSize
		Clients = New ArrayList
	End Sub

	Public Sub Listen(ByVal nPort As Integer)
		'instantiate the listener class
		Server = New TcpListener(System.Net.IPAddress.Any, nPort)
		'start listening for connection requests
		Try
			Server.Start()
		Catch ex As Exception
			Throw New ApplicationException(ex.Message)
		End Try
		'asyncronously wait for connection requests
		Server.BeginAcceptTcpClient(New AsyncCallback(AddressOf DoAcceptTcpClientCallback), Server)
	End Sub

	Private Sub DoAcceptTcpClientCallback(ByVal ar As IAsyncResult)
		' Processes the client connection request.
		' A maximum of (Infinity/Ram Space) connections can be made.
		Dim Allowed As Boolean

		' Get the listener that handles the client request.
		Dim listener As TcpListener = CType(ar.AsyncState, TcpListener)

		Dim client As TcpClient = listener.EndAcceptTcpClient(ar)
		'ask end user if he wants to accept this connection request
		RaiseEvent ConnectionRequest(client, Allowed)

		If Not Allowed Then
			SendMessage(RequestTags.Disconnect, 0, client)
			client.GetStream.Close()
			client.Close()
			client = Nothing
		Else
			'add client to list of connected clients
			SendMessage(RequestTags.Connect, mPacketSize, client)
			Dim esNewClient As New ClientDataHolder
			Dim NewRemoteClient As New RTS_SocketClient(client, mPacketSize)
			esNewClient.Client = NewRemoteClient
			esNewClient.Tag = nClients
			Clients.Add(esNewClient)

			'need to delegate events for client since client
			'is created dynamically and is going to be put into a 
			'collection so this is how we are going to propagate 
			'the events up to the end user
			AddHandler esNewClient.Client.DataReceived, AddressOf onDataReceived
			AddHandler esNewClient.Client.MessageReceived, AddressOf onMessageReceived
			AddHandler esNewClient.Client.StringReceived, AddressOf onStringReceived
			AddHandler esNewClient.Client.Disconnect, AddressOf onClientDisconnect
		End If

		'continue listening
		listener.BeginAcceptTcpClient(New AsyncCallback(AddressOf DoAcceptTcpClientCallback), listener)

	End Sub 'DoAcceptTcpClientCallback

	Private Sub SendMessage(ByVal msgTag As Byte, ByVal msg As Int16, ByVal client As TcpClient)
		' This subroutine sends a one-byte response through a tcpClient
		' Synclock ensure that no other threads try to use the stream at the same time.
		SyncLock client.GetStream
			Dim writer As New BinaryWriter(client.GetStream)
			writer.Write(msgTag)
			writer.Write(msg)
			' Make sure all data is sent now.
			writer.Flush()
		End SyncLock
	End Sub
#End Region

#Region "Overloaded Broadcast methods send data to all client connections"
	'Each of these should use a for each loop.
#Region "Broad Casting code"
	''' <summary>
	''' BroadCast A one Byte tag
	''' </summary>
	''' <param name="msgTag"></param>
	''' <remarks></remarks>
	Public Sub Broadcast(ByVal msgTag As Byte)
		For Each Item As ClientDataHolder In Clients
			Item.Client.Send(msgTag)
		Next
	End Sub

	''' <summary>
	''' BroadCast a one message byte and string
	''' </summary>
	''' <param name="msgTag"></param>
	''' <param name="strX"></param>
	''' <remarks></remarks>
	Public Sub Broadcast(ByVal msgTag As Byte, ByVal strX As String)
		For Each Item As ClientDataHolder In Clients
			Item.Client.Send(msgTag, strX)
		Next
	End Sub

	''' <summary>
	''' BroadCast a File and a message tag
	''' </summary>
	''' <param name="File"></param>
	''' <param name="Msgtag"></param>
	''' <remarks></remarks>
	Public Sub BroadcastSendFile(ByVal File As String, ByVal Msgtag As Byte)
		For Each Item As ClientDataHolder In Clients
			Item.Client.SendFile(Msgtag, File)
		Next
	End Sub

	''' <summary>
	''' BroadCasts a message tag and Byte data
	''' </summary>
	''' <param name="msgTag"></param>
	''' <param name="byteData"></param>
	''' <remarks></remarks>
	Public Sub Broadcast(ByVal msgTag As Byte, ByVal byteData() As Byte)
		For Each Item As ClientDataHolder In Clients
			Item.Client.Send(msgTag, byteData)
		Next
	End Sub
#End Region

#Region "Authentication"
	''' <summary>
	''' Authenticates a user
	''' </summary>
	''' <param name="Client">The RTS_SocketClient that will be compared to</param>
	''' <param name="Username">The username that will be entered</param>
	''' <remarks></remarks>
	Public Sub Login(ByVal Client As RTS_SocketClient, ByVal Username As String)
		For Each item As ClientDataHolder In Clients
			If item.Tag = Client.Tag Then
				Client.Username = (Username)
				RaiseEvent ClientLoggedIn(Username)
			End If
		Next
	End Sub

	''' <summary>
	''' Validates a login.
	''' </summary>
	''' <param name="RequestedLogin">The Login name requested by a client.</param>
	''' <param name="ServerUsername">The admin username for the server. Just for abitary checks. =)</param>
	''' <returns>True = Valid, False = Bad Login</returns>
	''' <remarks></remarks>
	Public Function ValidateLogin(ByVal RequestedLogin As String, ByVal ServerUsername As String, ByVal Client As RTS_SocketClient) As Boolean
		Dim xcor As Boolean = True

		For Each item As _BootedUser In BootedUsers
			If item.IP = Client.GetClientIP Then
				Client.DisconnectFromHost()
				Exit Function
			End If
		Next

		For Each item As _BootedUser In BootedUsers
			If item.Tag = Client.Tag Then
				Client.DisconnectFromHost()
				Exit Function
			End If
		Next

		If RequestedLogin.Count > 20 Then
			xcor = False
		End If

		For Each item As ClientDataHolder In Clients
			If item.Client.Username = RequestedLogin Then
				xcor = False
			End If
		Next
		If ServerUsername = RequestedLogin Then
			xcor = False
		End If
		Return xcor
	End Function

	''' <summary>
	''' Gives you the username of a client!!!!
	''' </summary>
	''' <param name="Client">The client.</param>
	''' <returns>Returns the username as string.</returns>
	''' <remarks></remarks>
	Public Function ReturnUsername(ByVal Client As RTS_SocketClient) As String
		Dim name As String = ""
		For Each item As ClientDataHolder In Clients
			If item.Tag = Client.Tag Then
			   &nbs



Is This A Good Question/Topic? 0
  • +

Replies To: Advanced P2P Networking - Chatrooms [Part 1]

#2 _HAWK_  Icon User is offline

  • Master(Of Foo)
  • member icon

Reputation: 1062
  • View blog
  • Posts: 4,138
  • Joined: 02-July 08

Posted 26 January 2010 - 07:08 PM

Hi Asscotte, thanks for the tutorial. I am looking forward to learning this better. A couple of thing are missing or I just am missing it;

Quote

Public Function ReturnUsername(ByVal Client As RTS_SocketClient) As String
		Dim name As String = ""
		For Each item As ClientDataHolder In Clients
			If item.Tag = Client.Tag Then
			   &nbs

And I can't find the RTS_SocketClient object/class.

Thanks...
Was This Post Helpful? 0
  • +
  • -

#3 AdamSpeight2008  Icon User is offline

  • MrCupOfT
  • member icon


Reputation: 2270
  • View blog
  • Posts: 9,496
  • Joined: 29-May 08

Posted 28 January 2010 - 03:40 PM

A Link to Part 2 of the tutorial
Was This Post Helpful? 0
  • +
  • -

#4 Asscotte  Icon User is offline

  • D.I.C Addict
  • member icon

Reputation: 35
  • View blog
  • Posts: 610
  • Joined: 08-February 09

Posted 29 January 2010 - 08:47 AM

Thanks Adam, I need to check my tutorials more often ;) Okay Because the tutorial was so long is was split into two sections, to be able to use the last function you need to change it to:

	''' <summary>
	''' Gives you the username of a client!!!!
	''' </summary>
	''' <param name="Client">The client.</param>
	''' <returns>Returns the username as string.</returns>
	''' <remarks></remarks>
	Public Function ReturnUsername(ByVal Client As RTS_SocketClient) As String
		Dim name As String = ""
		For Each item As ClientDataHolder In Clients
			If item.Tag = Client.Tag Then
				name = item.UsernameName
			End If
		Next
		Return name
	End Function




AS WELL AS the obvious missing end region.

This post has been edited by Asscotte: 29 January 2010 - 09:23 AM

Was This Post Helpful? 0
  • +
  • -

#5 _HAWK_  Icon User is offline

  • Master(Of Foo)
  • member icon

Reputation: 1062
  • View blog
  • Posts: 4,138
  • Joined: 02-July 08

Posted 29 January 2010 - 10:12 AM

Thanks Adam, but I don't see the RTS_SocketClient there either. I had already been thru both of these. If it's there I am just good at missing things =)
Was This Post Helpful? 0
  • +
  • -

#6 Asscotte  Icon User is offline

  • D.I.C Addict
  • member icon

Reputation: 35
  • View blog
  • Posts: 610
  • Joined: 08-February 09

Posted 30 January 2010 - 01:21 PM

Okay, because this tutorial has been blighted by issues I have Placed all source below...

RTS_Listener.vb (Server code)
Option Strict On
Option Explicit On

Imports System.Net.Sockets
Imports System.IO
Imports System.Collections.Generic
Imports System.Net

Friend Class RTS_Listener

	Private Enum RequestTags As Byte
		Connect = 1
		Disconnect = 2
		DataTransfer = 3
		StringTransfer = 4
		ByteTransfer = 5
	End Enum

	Private Server As TcpListener
	Private Clients As New ArrayList
	Private BootedUsers As New ArrayList
	Private nClients As Byte
	Private mPacketSize As Int16

#Region "Event Declarations"
	Public Event ConnectionRequest(ByVal Requestor As TcpClient, ByRef AllowConnection As Boolean)
	Public Event DataReceived(ByVal Client As RTS_SocketClient, ByVal msgTag As Byte, ByVal mStream As MemoryStream)
	Public Event MessageReceived(ByVal Client As RTS_SocketClient, ByVal message As Byte)
	Public Event StringReceived(ByVal Client As RTS_SocketClient, ByVal msgTag As Byte, ByVal message As String)
	Public Event Disconnect(ByVal Client As RTS_SocketClient)
	Public Event ClientLoggedIn(ByVal Username As String)
#End Region

#Region " Reverse Modulation Code"
	Public Structure ClientDataHolder
		Dim UsernameName As String
		Dim Client As RTS_SocketClient
		Dim Tag As Byte
	End Structure

	Public Structure _BootedUser
		Dim IP As String
		Dim Tag As Byte
		Dim Username As String
	End Structure

	Public Sub Close()
		Try
			Server.Stop()
			Clients = New ArrayList
		Catch ex As Exception
			Server.Stop()
		End Try
	End Sub

	Public Sub New(Optional ByVal PacketSize As Int16 = 4096)
		'constructor:
		'Creates a array to store client connections
		mPacketSize = PacketSize
		Clients = New ArrayList
	End Sub

	Public Sub Listen(ByVal nPort As Integer)
		'instantiate the listener class
		Server = New TcpListener(System.Net.IPAddress.Any, nPort)
		'start listening for connection requests
		Try
			Server.Start()
		Catch ex As Exception
			Throw New ApplicationException(ex.Message)
		End Try
		'asyncronously wait for connection requests
		Server.BeginAcceptTcpClient(New AsyncCallback(AddressOf DoAcceptTcpClientCallback), Server)
	End Sub

	Private Sub DoAcceptTcpClientCallback(ByVal ar As IAsyncResult)
		' Processes the client connection request.
		' A maximum of (Infinity/Ram Space) connections can be made.
		Dim Allowed As Boolean

		' Get the listener that handles the client request.
		Dim listener As TcpListener = CType(ar.AsyncState, TcpListener)

		Dim client As TcpClient = listener.EndAcceptTcpClient(ar)
		'ask end user if he wants to accept this connection request
		RaiseEvent ConnectionRequest(client, Allowed)

		If Not Allowed Then
			SendMessage(RequestTags.Disconnect, 0, client)
			client.GetStream.Close()
			client.Close()
			client = Nothing
		Else
			'add client to list of connected clients
			SendMessage(RequestTags.Connect, mPacketSize, client)
			Dim esNewClient As New ClientDataHolder
			Dim NewRemoteClient As New RTS_SocketClient(client, mPacketSize)
			esNewClient.Client = NewRemoteClient
			esNewClient.Tag = nClients
			Clients.Add(esNewClient)

			'need to delegate events for client since client
			'is created dynamically and is going to be put into a 
			'collection so this is how we are going to propagate 
			'the events up to the end user
			AddHandler esNewClient.Client.DataReceived, AddressOf onDataReceived
			AddHandler esNewClient.Client.MessageReceived, AddressOf onMessageReceived
			AddHandler esNewClient.Client.StringReceived, AddressOf onStringReceived
			AddHandler esNewClient.Client.Disconnect, AddressOf onClientDisconnect
		End If

		'continue listening
		listener.BeginAcceptTcpClient(New AsyncCallback(AddressOf DoAcceptTcpClientCallback), listener)

	End Sub 'DoAcceptTcpClientCallback

	Private Sub SendMessage(ByVal msgTag As Byte, ByVal msg As Int16, ByVal client As TcpClient)
		' This subroutine sends a one-byte response through a tcpClient
		' Synclock ensure that no other threads try to use the stream at the same time.
		SyncLock client.GetStream
			Dim writer As New BinaryWriter(client.GetStream)
			writer.Write(msgTag)
			writer.Write(msg)
			' Make sure all data is sent now.
			writer.Flush()
		End SyncLock
	End Sub
#End Region

#Region "Overloaded Broadcast methods send data to all client connections"
	'Each of these should use a for each loop.
#Region "Broad Casting code"
	''' <summary>
	''' BroadCast A one Byte tag
	''' </summary>
	''' <param name="msgTag"></param>
	''' <remarks></remarks>
	Public Sub Broadcast(ByVal msgTag As Byte)
		For Each Item As ClientDataHolder In Clients
			Item.Client.Send(msgTag)
		Next
	End Sub

	''' <summary>
	''' BroadCast a one message byte and string
	''' </summary>
	''' <param name="msgTag"></param>
	''' <param name="strX"></param>
	''' <remarks></remarks>
	Public Sub Broadcast(ByVal msgTag As Byte, ByVal strX As String)
		For Each Item As ClientDataHolder In Clients
			Item.Client.Send(msgTag, strX)
		Next
	End Sub

	''' <summary>
	''' BroadCast a File and a message tag
	''' </summary>
	''' <param name="File"></param>
	''' <param name="Msgtag"></param>
	''' <remarks></remarks>
	Public Sub BroadcastSendFile(ByVal File As String, ByVal Msgtag As Byte)
		For Each Item As ClientDataHolder In Clients
			Item.Client.SendFile(Msgtag, File)
		Next
	End Sub

	''' <summary>
	''' BroadCasts a message tag and Byte data
	''' </summary>
	''' <param name="msgTag"></param>
	''' <param name="byteData"></param>
	''' <remarks></remarks>
	Public Sub Broadcast(ByVal msgTag As Byte, ByVal byteData() As Byte)
		For Each Item As ClientDataHolder In Clients
			Item.Client.Send(msgTag, byteData)
		Next
	End Sub
#End Region

#Region "Authentication"
	''' <summary>
	''' Authenticates a user
	''' </summary>
	''' <param name="Client">The RTS_SocketClient that will be compared to</param>
	''' <param name="Username">The username that will be entered</param>
	''' <remarks></remarks>
	Public Sub Login(ByVal Client As RTS_SocketClient, ByVal Username As String)
		For Each item As ClientDataHolder In Clients
			If item.Tag = Client.Tag Then
				Client.Username = (Username)
				RaiseEvent ClientLoggedIn(Username)
			End If
		Next
	End Sub

	''' <summary>
	''' Validates a login.
	''' </summary>
	''' <param name="RequestedLogin">The Login name requested by a client.</param>
	''' <param name="ServerUsername">The admin username for the server. Just for abitary checks. =)</param>
	''' <returns>True = Valid, False = Bad Login</returns>
	''' <remarks></remarks>
	Public Function ValidateLogin(ByVal RequestedLogin As String, ByVal ServerUsername As String, ByVal Client As RTS_SocketClient) As Boolean
		Dim xcor As Boolean = True

		For Each item As _BootedUser In BootedUsers
			If item.IP = Client.GetClientIP Then
				Client.DisconnectFromHost()
				Exit Function
			End If
		Next

		For Each item As _BootedUser In BootedUsers
			If item.Tag = Client.Tag Then
				Client.DisconnectFromHost()
				Exit Function
			End If
		Next

		If RequestedLogin.Count > 20 Then
			xcor = False
		End If

		For Each item As ClientDataHolder In Clients
			If item.Client.Username = RequestedLogin Then
				xcor = False
			End If
		Next
		If ServerUsername = RequestedLogin Then
			xcor = False
		End If
		Return xcor
	End Function

	''' <summary>
	''' Gives you the username of a client!!!!
	''' </summary>
	''' <param name="Client">The client.</param>
	''' <returns>Returns the username as string.</returns>
	''' <remarks></remarks>
	Public Function ReturnUsername(ByVal Client As RTS_SocketClient) As String
		Dim name As String = ""
		For Each item As ClientDataHolder In Clients
			If item.Tag = Client.Tag Then
				name = item.UsernameName
			End If
		Next
		Return name
	End Function

#End Region

#Region "Personal User Messages"

	''' <summary>
	''' Sends a message to a user using their username.
	''' </summary>
	''' <param name="Username">The identifying username</param>
	''' <param name="MessageTag">the message tag to be sent</param>
	''' <param name="Message">the message</param>
	''' <remarks></remarks>
	Public Sub SendMessageToUser(ByVal Username As String, ByVal MessageTag As Byte, ByVal Message As String)
		For Each item As ClientDataHolder In Clients
			If item.UsernameName = Username Then
				item.Client.Send(MessageTag, Message)
			End If
		Next
	End Sub
	''' <summary>
	''' Sends a message to a user using their username.
	''' </summary>
	''' <param name="Client"></param>
	''' <param name="MessageTag"></param>
	''' <param name="Message"></param>
	''' <remarks></remarks>
	Public Sub SendMessageToUser(ByVal Client As RTS_SocketClient, ByVal MessageTag As Byte, ByVal Message As String)
		Client.Send(MessageTag, Message)
	End Sub

	''' <summary>
	''' Sends a specific file to a specific user.
	''' </summary>
	''' <param name="Username">Specified username.</param>
	''' <param name="MessageTag">Byte Tag</param>
	''' <param name="File">File to be sent</param>
	''' <remarks></remarks>
	Public Sub SendFileToUser(ByVal Username As String, ByVal MessageTag As Byte, ByVal File As String)
		For Each item As ClientDataHolder In Clients
			If item.UsernameName = Username Then
				item.Client.SendFile(MessageTag, File)
			End If
		Next
	End Sub

	''' <summary>
	''' Sends a specific file to a specific user. Pointless but should be here for 
	''' full functionallity
	''' </summary>
	''' <param name="Client">Client for the file to be sent to</param>
	''' <param name="MessageTag">The message tag for this message</param>
	''' <param name="File">The file to be sent</param>
	''' <remarks></remarks>
	Public Sub SendFileToUser(ByVal Client As RTS_SocketClient, ByVal MessageTag As Byte, ByVal File As String)
		Client.SendFile(MessageTag, File)
	End Sub

	''' <summary>
	''' Sends byte() data to a user
	''' </summary>
	''' <param name="Username">The user that the byte() data is aimed for</param>
	''' <param name="MessageTag">The message tag</param>
	''' <param name="Data">The byte() data</param>
	''' <remarks></remarks>
	Public Sub SendDataToUser(ByVal Username As String, ByVal MessageTag As Byte, ByVal Data() As Byte)
		For Each item As ClientDataHolder In Clients
			If item.UsernameName = Username Then
				item.Client.Send(MessageTag, Data)
			End If
		Next
	End Sub

	''' <summary>
	''' Sends byte() data to a user
	''' </summary>
	''' <param name="Client">The Client that the byte() data is aimed for</param>
	''' <param name="MessageTag">The message tag</param>
	''' <param name="Data">The byte() data</param>
	''' <remarks></remarks>
	Public Sub SendDataToUser(ByVal Client As RTS_SocketClient, ByVal MessageTag As Byte, ByVal Data() As Byte)
		Client.Send(MessageTag, Data)
	End Sub
#End Region

#Region "Adminy tasks"
	''' <summary>
	''' Boots A user from the network untill next server start.
	''' </summary>
	''' <param name="Username">The username of the person you wish to boot.</param>
	''' <remarks></remarks>
	Public Sub BootUser(ByVal Username As String)
		For Each item As ClientDataHolder In Clients
			If item.Client.Username = Username Then
				For Each thing As ClientDataHolder In Clients
					If thing.Client.GetClientIP = item.Client.GetClientIP Then
						Clients.Remove(thing)
					End If
				Next

				Dim a As New _BootedUser
				a.IP = item.Client.GetClientIP
				a.Tag = item.Client.Tag
				a.Username = item.Client.Username
				BootedUsers.Add(a)
				item.Client.DisconnectFromHost()
			End If
		Next
	End Sub
#End Region

#End Region

#Region "Events handlers for the clients"
	Private Sub onClientDisconnect(ByVal Client As RTS_SocketClient)
		RaiseEvent Disconnect(Client)
		'close client and remove from collection
		For Each item As ClientDataHolder In Clients
			If item.Tag = Client.Tag Then
				Clients.Remove(item)
			End If
		Next
		Client = Nothing
	End Sub

	Private Sub onDataReceived(ByVal client As RTS_SocketClient, ByVal msgTag As Byte, ByVal mstream As MemoryStream)
		RaiseEvent DataReceived(client, msgTag, mstream)
	End Sub

	Private Sub onMessageReceived(ByVal Client As RTS_SocketClient, ByVal message As Byte)
		RaiseEvent MessageReceived(Client, message)
	End Sub

	Private Sub onStringReceived(ByVal Sender As RTS_SocketClient, ByVal msgTag As Byte, ByVal message As String)
		RaiseEvent StringReceived(Sender, msgTag, message)
	End Sub
#End Region

	Private esPassword As String = ""
	Public Property Password() As String
		Get
			Return esPassword
		End Get
		Set(ByVal value As String)
			esPassword = value
		End Set
	End Property

	Private esSaltValue As String = ""
	Public Property SaltValue() As String
		Get
			Return esSaltValue
		End Get
		Set(ByVal value As String)
			esSaltValue = value
		End Set
	End Property

End Class





RTS_SocketClient.vb
Imports System.Net.Sockets
Imports System.IO
Imports System.Net

Friend Class RTS_SocketClient
	Inherits Object


	Private Enum RequestTags As Byte
		Connect = 1
		Disconnect = 2
		DataTransfer = 3
		StringTransfer = 4
		ByteTransfer = 5
	End Enum

	Private PACKET_SIZE As Int16 = 4096
	Private client As TcpClient
	Private readByte(0) As Byte
	Private myTag As Byte
	Private isConnected As Boolean 'set to true when connection is granted by server

#Region "Declare events"
	Public Event DataReceived(ByVal sender As RTS_SocketClient, ByVal msgTag As Byte, ByVal mstream As MemoryStream)
	Public Event MessageReceived(ByVal sender As RTS_SocketClient, ByVal msgTag As Byte)
	Public Event StringReceived(ByVal Sender As RTS_SocketClient, ByVal msgTag As Byte, ByVal message As String)
	Public Event TransferProgress(ByVal Sender As RTS_SocketClient, ByVal msgTag As Byte, ByVal Percentage As Single)
	Public Event Connect(ByVal sender As RTS_SocketClient)
	Public Event Disconnect(ByVal sender As RTS_SocketClient)
#End Region

#Region "Overloaded Constructors and destructor"
	Public Sub New(ByVal client As TcpClient, ByVal PacketSize As Int16)
		'instantiates class for use in server
		'don't handle errors here, allow caller to handle them
		PACKET_SIZE = PacketSize
		Me.client = client
		'Start an asynchronous read from the NetworkStream
		Me.client.GetStream.BeginRead(readByte, 0, 1, AddressOf ReceiveOneByte, Nothing)
	End Sub

	Public Sub New()

	End Sub

	Public Sub ConnectToHost(ByVal IPServer As String, ByVal Port As Integer)
		'instantiates class for use in client
		'don't handle errors here, allow caller to handle them
		'create a new TcpClient and make a synchronous connection 
		'attempt to the provided host name and port number
		Me.client = New TcpClient(IPServer, Port)
		'Start an asynchronous read from the NetworkStream
		Me.client.GetStream.BeginRead(readByte, 0, 1, AddressOf ReceiveOneByte, Nothing)
	End Sub

	Public Sub DisconnectFromHost()
		Me.client.Client.Close()
	End Sub

	Protected Overrides Sub finalize()
		'we don't care about errors in this section since we are ending
		On Error Resume Next
		If isConnected Then Send(RequestTags.Disconnect)
		client.GetStream.Close()
		client.Close()
		client = Nothing
	End Sub

#End Region

#Region "Code Hiding"
	Public Property Tag() As Byte
		Get
			Tag = myTag
		End Get
		Set(ByVal value As Byte)
			myTag = value
		End Set
	End Property

	Private Sub ReceiveOneByte(ByVal ar As IAsyncResult)
		'This is where the data is received.  All data communications 
		'begin with a one-byte identifier that tells the class how to
		'handle what is to follow.
		Dim r As BinaryReader
		Dim sreader As StreamReader
		Dim mStream As MemoryStream
		Dim lData As Int32
		Dim readBuffer(PACKET_SIZE) As Byte
		Dim StrBuffer(PACKET_SIZE) As Char
		Dim passThroughByte As Byte
		Dim nData As Integer
		Dim lenData As Integer
		Try
			SyncLock client.GetStream
				'if error occurs here then socket has closed
				Try
					client.GetStream.EndRead(ar)
				Catch
					RaiseEvent Disconnect(Me)
					Exit Sub
				End Try
			End SyncLock
		Catch ex As Exception
			Exit Sub
		End Try

		'this is the instruction on how to handle the rest of the data to come.
		Select Case readByte(0)
			Case RequestTags.Connect
				'sent from server to client informing client that a successful 
				'connection negotiation has been made and the connection now exists.
				isConnected = True 'identifies this class as on the client end
				RaiseEvent Connect(Me)
				SyncLock client.GetStream
					r = New BinaryReader(client.GetStream)
					PACKET_SIZE = r.ReadInt16
					'Continue the asynchronous read from the NetworkStream
					Me.client.GetStream.BeginRead(readByte, 0, 1, AddressOf ReceiveOneByte, Nothing)
				End SyncLock

			Case RequestTags.Disconnect
				'sent to either client or server
				'propagated forward to Listener on server end
				RaiseEvent Disconnect(Me)

			Case RequestTags.DataTransfer
				'a block of data is coming
				'Format of this transaction is
				'   DataTransfer identifier byte
				'   Pass-Through Byte contains user defined data
				'   Length of data block (max size = 2,147,483,647 bytes)
				SyncLock client.GetStream
					r = New BinaryReader(client.GetStream)
					'next we expect a pass-through byte
					client.GetStream.Read(readByte, 0, 1)
					passThroughByte = readByte(0)
					'next expect length of data (Int32)
					nData = r.ReadInt32
					lenData = nData
					'now comes the data, save it in a memory stream
					mStream = New MemoryStream
					While nData > 0
						RaiseEvent TransferProgress(Me, passThroughByte, CSng(1.0 - nData / lenData))
						lData = client.GetStream.Read(readBuffer, 0, PACKET_SIZE)
						mStream.Write(readBuffer, 0, lData)
						nData -= lData
					End While
					'Continue the asynchronous read from the NetworkStream
					Me.client.GetStream.BeginRead(readByte, 0, 1, AddressOf ReceiveOneByte, Nothing)
				End SyncLock
				'once all data has arrived, pass it on to the end user as a stream
				RaiseEvent DataReceived(Me, passThroughByte, mStream)
				mStream.Dispose()

			Case RequestTags.StringTransfer
				'Here we receive the transfer of string data in a block
				'not to exceed PACKET_SIZE in length.
				SyncLock client.GetStream
					sreader = New StreamReader(client.GetStream)
					'next we expect a pass-through byte
					client.GetStream.Read(readByte, 0, 1)
					passThroughByte = readByte(0)
					nData = sreader.Read(StrBuffer, 0, PACKET_SIZE)
				End SyncLock
				Dim strX As New String(StrBuffer, 0, nData)

				'pass string on to end user
				RaiseEvent StringReceived(Me, passThroughByte, strX)
				SyncLock client.GetStream
					'Continue the asynchronous read from the NetworkStream
					Me.client.GetStream.BeginRead(readByte, 0, 1, AddressOf ReceiveOneByte, Nothing)
				End SyncLock

			Case RequestTags.ByteTransfer
				'Here we receive a user-defined one-byte message
				SyncLock client.GetStream
					client.GetStream.Read(readByte, 0, 1)
				End SyncLock
				'pass byte on to end user
				RaiseEvent MessageReceived(Me, readByte(0))
				SyncLock client.GetStream
					'Continue the asynchronous read from the NetworkStream
					Me.client.GetStream.BeginRead(readByte, 0, 1, AddressOf ReceiveOneByte, Nothing)
				End SyncLock

		End Select

	End Sub

#Region "Overloaded methods to send data between client(s) and server"

	Public Sub Send(ByVal msgTag As Byte)
		' This subroutine sends a one-byte response
		SyncLock client.GetStream
			Dim writer As New BinaryWriter(client.GetStream)
			'notify that 1-byte is coming
			writer.Write(RequestTags.ByteTransfer)
			'Send user defined message byte
			writer.Write(msgTag)
			' Make sure all data is sent now.
			writer.Flush()
		End SyncLock
	End Sub

	Public Sub Send(ByVal msgTag As Byte, ByVal strX As String)
		'sends a string of max length PACKET_SIZE
		SyncLock client.GetStream
			Dim writer As New StreamWriter(client.GetStream)
			'Notify other end that a string block is coming
			writer.Write(Chr(RequestTags.StringTransfer))
			'Send user defined message byte
			writer.Write(Chr(msgTag))
			'Send the string
			writer.Write(strX)
			'make sure all data gets sent now
			writer.Flush()
		End SyncLock
	End Sub

	''' <summary>
	''' Dont Perform a buffer overflow with this :)
	''' </summary>
	''' <param name="msgTag"></param>
	''' <param name="byteData"></param>
	''' <remarks></remarks>
	Public Sub Send(ByVal msgTag As Byte, ByVal byteData() As Byte)
		'sends array of byte data
		SyncLock client.GetStream
			Dim writer As New BinaryWriter(client.GetStream)
			'Notify that byte data is coming
			writer.Write(RequestTags.DataTransfer)
			'send user-define message byte
			writer.Write(msgTag)
			'send length of data block
			writer.Write(byteData.Length)
			'send the data
			writer.Write(byteData)
			'make sure all data is sent
			writer.Flush()
		End SyncLock
	End Sub

	''' <summary>
	''' Max File Size is 2GB
	''' </summary>
	''' <param name="msgTag"></param>
	''' <param name="FilePath"></param>
	''' <remarks></remarks>
	Public Sub SendFile(ByVal msgTag As Byte, ByVal FilePath As String)
		'max filesize is 2GB
		Dim byteArray() As Byte
		Dim fs As FileStream = New FileStream(FilePath, FileMode.Open, FileAccess.Read)
		Dim r As New BinaryReader(fs)

		SyncLock client.GetStream
			Dim w As New BinaryWriter(client.GetStream)
			'notify that file data is coming
			w.Write(RequestTags.DataTransfer)
			'send user-define message byte
			w.Write(msgTag)
			'send size of file
			w.Write(CInt(fs.Length))
			'Send the file data
			Do
				'read data from file
				byteArray = r.ReadBytes(PACKET_SIZE)
				'write data to Network Stream
				w.Write(byteArray)
			Loop While byteArray.Length = PACKET_SIZE
			'make sure all data is sent
			w.Flush()
		End SyncLock
	End Sub
#End Region


	''' <summary>
	''' Get this clients remote IP (Server Use Only)
	''' </summary>
	''' <returns></returns>
	''' <remarks></remarks>
	Public Function GetClientIP() As String
		Dim a As String = String.Empty
		Dim clientInfo As IPEndPoint = CType(client.Client.RemoteEndPoint, IPEndPoint)
		a = clientInfo.Address.ToString
		Return a
	End Function

	Private esusername As String = ""
	Public Property Username() As String
		Get
			Return esusername
		End Get
		Set(ByVal value As String)
			esusername = value
		End Set
	End Property
#End Region
End Class


Was This Post Helpful? 2
  • +
  • -

#7 TerraEnvy  Icon User is offline

  • New D.I.C Head

Reputation: 1
  • View blog
  • Posts: 39
  • Joined: 07-November 08

Posted 24 August 2010 - 05:17 PM

So, Sorry for being not very knowledgeable about this but
What kind of projects are these supposed to be made in?
Windows Form, console, class library ect ect ect?
Sorry, I'm still semi new and want to learn this.
I am using Visual Studios 2010

This post has been edited by TerraEnvy: 24 August 2010 - 06:34 PM

Was This Post Helpful? 0
  • +
  • -

#8 cornetto456  Icon User is offline

  • D.I.C Regular

Reputation: 21
  • View blog
  • Posts: 438
  • Joined: 03-January 11

Posted 23 March 2011 - 05:10 AM

View PostTerraEnvy, on 24 August 2010 - 05:17 PM, said:

So, Sorry for being not very knowledgeable about this but
What kind of projects are these supposed to be made in?
Windows Form, console, class library ect ect ect?
Sorry, I'm still semi new and want to learn this.
I am using Visual Studios 2010

The server Will be probably a console and the chat will be an Form's application


EDIT i think the server is also a win forms app ;)

Hope this help's


Arno(Cornetto456)

This post has been edited by cornetto456: 23 March 2011 - 05:18 AM

Was This Post Helpful? 0
  • +
  • -

#9 _HAWK_  Icon User is offline

  • Master(Of Foo)
  • member icon

Reputation: 1062
  • View blog
  • Posts: 4,138
  • Joined: 02-July 08

Posted 24 March 2011 - 06:36 AM

They are classes you add to your project. Server class to the server and client class to the remote client.
Was This Post Helpful? 1
  • +
  • -

#10 MarkC  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 20
  • Joined: 23-March 11

Posted 27 March 2011 - 02:00 AM

Howdy Hawk,

I've seen your reply in my post and am just checking out this article, i bet its going to be a loooong night^^ thanks for the link too.

View Posthawkvalley1, on 24 March 2011 - 06:36 AM, said:

They are classes you add to your project. Server class to the server and client class to the remote client.

Was This Post Helpful? 0
  • +
  • -

#11 MarkC  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 20
  • Joined: 23-March 11

Posted 28 March 2011 - 12:39 PM

Hi Asscotte,


I was wondering if the client code has no receive function like the server has to receive message data. can the code be just the same as the server's?


Thanks!
Was This Post Helpful? 0
  • +
  • -

#12 MarkC  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 20
  • Joined: 23-March 11

Posted 28 March 2011 - 12:59 PM

Hi again,


My bad, i have located the receive event of the client side^^

View PostMarkC, on 28 March 2011 - 12:39 PM, said:

Hi Asscotte,


I was wondering if the client code has no receive function like the server has to receive message data. can the code be just the same as the server's?


Thanks!

Was This Post Helpful? 0
  • +
  • -

#13 BassGhost  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 1
  • Joined: 21-February 12

Posted 21 February 2012 - 11:56 AM

Is there a link to a sample of using this tutorial code in a VB.NET app? I see allot of people have asked that question and it was never answered.
Was This Post Helpful? 0
  • +
  • -

#14 Stramel  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 1
  • Joined: 28-February 13

Posted 28 February 2013 - 11:21 AM

Sorry for bringing this back but I have a question for asscotte.

When I close down the client, it seems to close down the server too. Not sure why this is happening either.
Was This Post Helpful? 0
  • +
  • -

#15 maousnater  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 1
  • Joined: 29-April 13

Posted 29 April 2013 - 08:33 AM

hi I a novice trying your Advanced P2P - Chatroom, I can't wrap my mind around the structure of the classes can you gentlemen provide me an assistance ?
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1