Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / TcpClient

Socket_Control DLL Resource and Tutorial

5.00/5 (2 votes)
10 May 2013CPOL7 min read 26K   164  
A DLL resource to help beginner to intermediate developers open and use sockets in a P2P application.

Introduction

This artical distributes a DLL resource for helping developers with sockets and P2P applications, as well as give them an understanding of the classes and functions in the DLL. The purpose of this DLL is to make it easier to interface with TCP connections and opening/using ports.

Background

This is not a tutorial on how to use DLLs in your respective language, it is a reference and distribution for the Socket_Control.DLL, if you would like to learn how to import and use DLLs, look up one of the many tutorials on this very site.

Using the code

To first use this DLL, you must define one of the classes as an object in your code, the two classes this DLL contains are:

C++
Client_Socket()
Server_Socket()

Next there are a few properties to be set

For the server there's:

  • Port Sets the port that the server will listen on (Default 55433)
  • MaxClients Sets the max amount of clients that are able to join at one time (Default 25)

And for the client we have:

  • IP Sets the IP where the server is located (Default 127.0.0.1)
  • Port Sets the port where the client will connect through (Default 55433)

Now call the Connect() function for the client or the Start() function for the server to initialize the rest of the objects before calling any of the other functions.

All the properties, events, and functions for Server_Socket():

Name Type Description
Port Property Assigns the port on witch the server will listen on (Default 55433)
MaxClients Property Assigns the amount of clients that can be connected at one time (Default 25)
ConnectionEstablished(int ID) Event Called when a new client connects and returns the ID of the client
ClientDisconnect(int ID) Event Called when a client disconnects and returns the client ID
Start() Function Starts listening to the port assigned to the Port property
objInit(int ClientID) Read Only Property Takes integer client ID as input returns true if there is a client in that client ID slot
Increment() Function Increments the property MaxClients by one
Terminate(int ClientID) Function Terminates connection to a client
Stream(int ClientID) Read Only Property Returns a clients data stream if available otherwise returns the string "%False%"
DataSend(String data, int ID) Function Sends data to client ID

All the properties, events, and functions for Client_Socket()

Name Type Description
IP Property Sets the IP where the server is located (Default 127.0.0.1)
Port Property Assigns the port that the client will connect through (Default 55433)
Connected() Read Only Property Returns true if connected to server
Connect() Function Connects to server IP:Port
Stream() Read Only Property Returns a clients data stream if available otherwise returns the string "%False%"
DataSend(String data, int ID) Function Sends data to client ID
Close() Function

Disconnects from server and de-initializes socket until next connect

Example(VB.NET)

Server (Console Application):

VB.NET
Imports System.Text.RegularExpressions

Module Module1
    Dim WithEvents Socket As New Socket_Control.Server_Socket
    Dim inStream As New Threading.Thread(AddressOf Streaming)

    Sub Main()
        msg("Max Client Slots:")
        Console.Write(" >> ")
        Dim max As String = Console.ReadLine()
        msg("Port: ")
        Console.Write(" >> ")
        Dim port As String = Console.ReadLine()
        Socket.MaxSlots = max
        Socket.Port = port
        Socket.Start()
        msg("Now Monitoring Port: " & Socket.Port)
        inStream.Start()
        While True

        End While
    End Sub

    Private Sub Streaming()
        While True
            Dim Count As Integer = 0
            While Not Count = Socket.MaxSlots
                Dim Stream As String = Socket.Stream(Count)
                If Not Stream = "%False%" Then
                    Dim Parsed() As String = Regex.Split(Stream, " ")
                    If Parsed(1) = "/close" Then
                        Socket.DataSend("%Closed%", Count)
                        Socket.Terminate(Count)
                        GoTo skip
                    End If
                    msg("[CLIENT " & Count + 1 & "] " & Stream)
                    Dim ID As Integer = 0
                    While Not ID = Socket.MaxSlots
                        If Not ID = Count AndAlso Socket.objInit(ID) Then
                            Socket.DataSend(Stream, ID)
                        End If
                        ID += 1
                    End While
skip:
                End If
                Count += 1
            End While
        End While
    End Sub

    Private Sub connectionEstablished(ByVal ID As String) Handles Socket.ConnectionEstablished
        msg("CLIENT " & ID + 1 & " Connected")
    End Sub

    Private Sub clientDisconnect(ByVal ID As String) Handles Socket.ClientDisconnect
        msg("CLIENT " & ID + 1 & " Disconnected")
    End Sub

    Private Sub msg(ByVal Message As String)
        Console.WriteLine(" >> " & Message)
    End Sub
End Module

First we import System.Text.RegularExpressions, This will be used to parse data later on.

Then we define a few variables.

  • Socket - This is our instance of Socket_Control.Server_Socket, we dim it WithEvents so we can handle events raised with it later on.
  • inStream - This is a new thread we define to monitor data going in and out of the server. We assign the execution sub to Streaming().

Now to our main sub routine. First we ask the user for the maximum amount of clients they want to be able to be connected at one time and assign their input to a variable called max. Then we ask them for the port they want the server to listen on and assign it to a variable called port. Then we assign the properties MaxClients and Port to max and port respectively then start the server.

You might have noticed me using a sub routine called msg() earlier on, the contents of the sub are above but ill put them below as well:

VB.NET
Private Sub msg(ByVal Message As String)
    Console.WriteLine(" >

Here we us that sub again to tell the user that the server has started, then we start the execution of that thread we created earlier and then we set an infinite loop, to keep the program running while the thread executes.

Now we have arrived at our thread, first we create and infinite loop, so our our block of code will repeat until the program has ended. Then we give ourselves a integer, to monitor our next while loop. We then make a while loop, while the integer count does not equal the maximum amount of slots available do this. We do this because we want it to loop through all the array values, arrays start at 0, so if you want 4 slots in your array, you actually want to make it 3, because the available slots will be 0, 1, 2, 3 four slots, so the array size in the client array is maxslots -1 so if we've reached maxslots, stop.

Now we grab the client stream as string, with the client ID being Count. After this, we use the regular expressions we imported earlier, to split the stream, with the delimiter 'Space' into the array Parsed(). The Socket.Stream returns "%False%" if there is no data available, so we check that here. If there is data available it checks it, otherwise, it does nothing. I have the client set up to send the data: "[nickname] data" so we have to get the second place in the array, so we evaluate Parsed(1) because remember, arrays start at 0. If it equals "/close" then we send the client "%closed%" to tell the client that the connection was closed then we terminate that clients connection. Otherwise, we send out the data to the rest of the clients. To achieve this we set another integer to monitor our next while loop, and set up the while loop like before. If the ID isn't the id of the client that sent the data it sends the data to that client.

Here we have arrived at our handlers, the handler is called whenever an event happens, these handle when someone connects, and then disconnects. Each event handler just sends a simple message.

Client (Windows Forms Application):

Set up the form like above

Everything is left at their default names, the richtextbox is set to readonly and the text is as follows:

/connect <IP> <port> - Opens connection on <IP>:<port>
/close - Disconnects from current connection
/nick <nickname> - Sets your Nickname 

the text in ToolStripStatusLabel1 is "Not Connected", also add a timer with interval 100 leave it disabled.

Code:

VB.NET
Imports System.Text.RegularExpressions

Public Class Form1
    Dim Socket As New Socket_Control.Client_Socket
    Dim Connected As Boolean = False
    Dim Stream As String
    Dim Prev As String = "/connect localhost 55433"
    Dim Cur As String = ""
    Dim Nick As String = "[Default]"

    Private Sub Connect(ByVal IP As String, port As Integer)
        Socket.IP = IP
        Socket.Port = port
        Try
            Socket.Connect()
            ToolStripStatusLabel1.Text = "Connected To: " & Socket.IP & ":" & Socket.Port
            msg("Connection Opened On: " & Socket.IP & ":" & Socket.Port)
            Connected = True
            Timer1.Enabled = True
        Catch ex As Exception
            If Not ex.Message = Nothing Then msg(ex.Message)
            GoTo Skip
        End Try
Skip:
    End Sub

    Private Sub msg(ByVal Message As String)
        RichTextBox1.HideSelection = False
        RichTextBox1.Text &= Environment.NewLine & " >> " & Message
        RichTextBox1.SelectionStart = RichTextBox1.TextLength
    End Sub

    Private Sub Timer1_Tick(sender As System.Object, e As System.EventArgs) Handles Timer1.Tick
        Stream = Socket.Stream
        If Not Stream = "%False%" Then
            If Stream = "%Closed%" Then
                msg("Connection To '" & Socket.IP & ":" & Socket.Port & "' Terminated")
                Connected = False
                ToolStripStatusLabel1.Text = "Not Connected"
                Timer1.Enabled = False
                Socket.Close()
            Else
                msg(Stream)
                Beep()
            End If
        End If
        Stream = ""
    End Sub

    Private Sub Form1_FormClosing(sender As System.Object, _
                e As System.Windows.Forms.FormClosingEventArgs) Handles MyBase.FormClosing
        If Not Socket.Connected Then GoTo ender
        Try
            Socket.DataSend("[] /close")
        Catch ex As Exception
            GoTo ender
        End Try
        Do Until Connected = False
            Application.DoEvents()
        Loop
ender:
        Try
            Socket.Close()
        Catch ex As Exception

        End Try
    End Sub

    Private Sub TextBox2_KeyDown(sender As System.Object, e As System.Windows.Forms.KeyEventArgs) Handles TextBox2.KeyDown
        Dim Parsed() As String = Regex.Split(TextBox2.Text, " ")
        If e.KeyValue = Keys.Enter Then
            e.SuppressKeyPress = True
            Prev = TextBox2.Text
            Cur = ""
            If Parsed(0) = "/connect" Then
                If Connected Then
                    msg("Connection Already Open")
                    msg("type /close to disconnect")
                ElseIf Not Parsed.Length = 3 Then
                    msg("Usage: /connect <IP> <port>")
                Else
                    Connect(Parsed(1), Parsed(2))
                End If
            ElseIf Parsed(0) = "/nick" Then
                If Not Parsed.Length = 2 Then
                    msg("Usage: /nick <nickname>")
                Else
                    Dim mesg As String = ""
                    For Count As Integer = 1 To Parsed.Length - 1
                        If Not Count = Parsed.Length - 1 Then
                            mesg &= Parsed(Count) & " "
                        Else
                            mesg &= Parsed(Count)
                        End If
                    Next
                    msg("Nickname Changed To: " & mesg)
                    If Connected Then
                        Try
                            Socket.DataSend(Nick & " Changed Their Nickname: " & mesg)
                        Catch ex As Exception
                            Connected = False
                            ToolStripStatusLabel1.Text = "Not Connected"
                            Timer1.Enabled = False
                            Socket.Close()
                            msg("Connection closed by remote host")
                        End Try
                    End If
                    Nick = "[" & mesg & "]"
                End If
            ElseIf Connected = True Then
                Try
                    Socket.DataSend(Nick & " " & TextBox2.Text)
                    msg("[ME] " & TextBox2.Text)
                Catch ex As Exception
                    Connected = False
                    ToolStripStatusLabel1.Text = "Not Connected"
                    Timer1.Enabled = False
                    Socket.Close()
                    msg("Error: Connection closed by remote host")
                End Try
            Else
                    msg("Error: Not Connected")
            End If
Skip:
            TextBox2.Text = Nothing
        ElseIf e.KeyValue = Keys.Up AndAlso Not TextBox2.Text = Prev Then
            Cur = TextBox2.Text
            TextBox2.Text = Prev
        ElseIf e.KeyValue = Keys.Down AndAlso Not Cur = "" Then
            TextBox2.Text = Cur
        End If
    End Sub
End Class

As you can see again we import regular expressions for later data parsing use.

Again we define a few variables

  • Socket - Our instance of Socket_Control.Client_Socket
  • Connected - A global boolean value defaulting to false letting the application know weather its connected to a server or not
  • Prev - Holds the last thing that the user typed for use with the up arrow recalling last command
  • Cur - Holds what you typed before pressing the up arrow
  • Nick - Holds the users nickname

Here we create a sub routine called Connect(IP, port) its pretty straight forward. It assigns the IP and Port properties to IP and port respectively, then it tries to connect, if it can it sends out a message, sets Connected to True and starts the timer.

We have arrived at a simple sub routine (msg()), it does the same thing as the other msg sub, it sends a message to the interface. and scrolls down on the richtextbox

What we have here, is the timer tick handler, every time the timer ticks it checks the stream, if the stream doesn't equal "%False%" then it continues to check it. If it equals "%Closed%" then it sends a connection terminated message, disables the timer, and closes the socket. otherwise it sends the stream to the interface, and beeps as an alert to the user.

Here we are at the form closing event, here, it tries to close the socket, for a clean exit.

At this sub routine (Key Press Handler), it checks to see if the key press is enter, if it is enter, it checks for all the commands and sends the stream, just like the server. If the keypress is up, it saves the textbox value to cur and sets the textbox value to prev, if the keypress is down, it does the opposite.

Release

NOTE:
I need your guy's feedback so I can release updates, it will never get better if I don't know how to make it better. 

History

  • 03/31/13: 1.0.0.0 Launched 
  • 04/01/13: 2.0.0.0 Build started
  • 04/05/13: Organized stream IO into a sub-class
  • 04/06/13: added GetStrring() and GetBytes() Functions 

Source/Collaborate

To collaborate with developer on project or get source code for your own use contact croug@bimbots.tk.

License

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