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:
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):
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:
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:
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.