Socket_Control DLL 资源和教程
一个 DLL 资源,旨在帮助初学者到中级开发人员在 P2P 应用程序中打开和使用套接字。
引言
本文档分发了一个 DLL 资源,用于帮助开发人员处理套接字和 P2P 应用程序,并让他们了解 DLL 中的类和函数。此 DLL 的目的是简化与 TCP 连接的接口以及端口的打开/使用。
背景
这不是一个关于如何在你的特定语言中使用 DLL 的教程,而是一个关于 Socket_Control.DLL 的参考和分发。如果你想学习如何导入和使用 DLL,请在本网站上查找大量的教程。
使用代码
要首先使用此 DLL,你必须在你自己的代码中将其中一个类定义为一个对象。此 DLL 包含两个类:
Client_Socket()
Server_Socket()
接下来需要设置一些属性
对于服务器来说,有:
Port
设置服务器将要监听的端口(默认 55433)MaxClients
设置一次最多能加入的客户端数量(默认 25)
对于客户端,我们有:
-
IP
设置服务器所在的 IP 地址(默认 127.0.0.1) Port
设置客户端将要连接的端口(默认 55433)
现在,为客户端调用 Connect()
函数,或为服务器调用 Start()
函数来初始化其余的对象,然后再调用任何其他函数。
Server_Socket()
的所有属性、事件和函数
名称 | 类型 | 描述 |
---|---|---|
端口 |
属性 | 设置服务器将要监听的端口(默认 55433) |
MaxClients |
属性 | 设置一次可以连接的客户端数量(默认 25) |
ConnectionEstablished(int ID) |
事件 | 当新客户端连接时调用,并返回客户端的 ID |
ClientDisconnect(int ID) |
事件 | 当客户端断开连接时调用,并返回客户端 ID |
Start() |
函数 | 开始监听分配给 Port 属性的端口 |
objInit(int ClientID) |
只读属性 | 以整数客户端 ID 作为输入,如果该客户端 ID 插槽中有客户端,则返回 true |
Increment() |
函数 | 将 MaxClients 属性加一 |
Terminate(int ClientID) |
函数 | 终止与客户端的连接 |
Stream(int ClientID) |
只读属性 | 返回客户端的数据流(如果可用),否则返回字符串 "%False%" |
DataSend(String data, int ID) |
函数 | 将 data 发送给客户端 ID |
Client_Socket()
的所有属性、事件和函数
名称 | 类型 | 描述 |
---|---|---|
IP |
属性 | 设置服务器所在的 IP 地址(默认 127.0.0.1) |
端口 |
属性 | 设置客户端将要连接的端口(默认 55433) |
Connected() |
只读属性 | 如果连接到服务器,则返回 true |
Connect() |
函数 | 连接到服务器 IP:Port |
Stream() |
只读属性 | 返回客户端的数据流(如果可用),否则返回字符串 "%False%" |
DataSend(String data, int ID) |
函数 | 将 data 发送给客户端 ID |
Close() |
函数 | 断开与服务器的连接,并取消初始化套接字,直到下次连接 |
示例(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
首先,我们导入 System.Text.RegularExpressions
,稍后将用于解析数据。
然后我们定义一些变量。
-
Socket
- 这是我们Socket_Control.Server_Socket
的实例,我们使用WithEvents
声明它,以便稍后可以处理它引发的事件。 -
inStream
- 这是一个新的线程,我们定义它来监控进出服务器的数据。我们将执行子程序分配给Streaming()
。
现在来到我们的主子程序。首先,我们询问用户他们希望同时连接的最大客户端数量,并将他们的输入分配给一个名为 max
的变量。然后,我们询问他们希望服务器监听的端口,并将其分配给一个名为 port
的变量。然后,我们将 MaxClients
和 Port
属性分别分配给 max
和 port
,然后启动服务器。
你可能已经注意到我之前使用了名为 msg()
的子程序。该子程序的原始内容在上面,但我也会将其放在下面
Private Sub msg(ByVal Message As String)
Console.WriteLine(" >
在这里,我们再次使用该子程序来告诉用户服务器已启动,然后我们启动之前创建的线程的执行,然后设置一个无限循环,以使程序在线程执行时保持运行。
现在我们来到了我们的线程。首先,我们创建一个无限循环,以便我们的代码块会重复执行,直到程序结束。然后,我们创建一个整数来监视我们的下一个 while 循环。然后,我们设置一个 while 循环,当整数计数不等于可用插槽的最大数量时执行此操作。我们这样做是因为我们希望它循环遍历所有数组值。数组从 0 开始,所以如果你想要 4 个数组插槽,你实际上需要将其设置为 3,因为可用插槽将是 0、1、2、3,共 4 个插槽。因此,客户端数组中的数组大小是 maxslots - 1。如果达到了 maxslots,则停止。
现在,我们将客户端流获取为字符串,客户端 ID 为 Count
。在此之后,我们使用之前导入的正则表达式,以 'Space' 作为分隔符将流拆分到 Parsed()
数组中。如果数据不可用,Socket.Stream
将返回 "%False%",因此我们在此处进行检查。如果数据可用,它会进行检查,否则什么也不做。我已经将客户端设置为发送数据:"[nickname] data",所以我们需要获取数组中的第二个位置,因此我们计算 Parsed(1)
,因为请记住,数组从 0 开始。如果它等于 "/close",那么我们将向客户端发送 "%closed%" 来告知客户端连接已关闭,然后终止该客户端的连接。否则,它会将数据发送给其他客户端。为了实现这一点,我们设置了另一个整数来监视我们的下一个 while 循环,并像以前一样设置 while 循环。如果 ID 不是发送数据的客户端的 ID,则将数据发送给该客户端。
这里我们来到了处理程序。每当发生事件时,就会调用处理程序。这些处理程序会处理有人连接和断开连接的情况。每个事件处理程序都只是发送一条简单的消息。
客户端(Windows 窗体应用程序)
像上面一样设置窗体
所有内容都保留其默认名称,richtextbox 被设置为只读,文本内容如下
/connect <IP> <port> - Opens connection on <IP>:<port>
/close - Disconnects from current connection
/nick <nickname> - Sets your Nickname
ToolStripStatusLabel1
中的文本是 "Not Connected",还有一个间隔为 100 的计时器,保持禁用状态。
代码
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
再次,我们导入正则表达式以供以后进行数据解析。
再次,我们定义一些变量
Socket
- 我们的Socket_Control.Client_Socket
实例Connected
- 一个全局布尔值,默认为 false,用于告知应用程序它是否已连接到服务器。Prev
- 保存用户上次键入的内容,用于向上箭头调出上次输入的命令。Cur
- 保存用户在按下向上箭头之前的输入内容。Nick
- 保存用户的昵称
在这里,我们创建了一个名为 Connect(IP, port)
的子程序,它非常直接。它将 IP
和 Port
属性分别分配给 IP
和 port
,然后尝试连接。如果成功,它会发送一条消息,将 Connected
设置为 True,并启动计时器。
我们来到一个简单的子程序(msg()
),它的功能与另一个 msg 子程序相同,它将消息发送到界面,并在 richtextbox 中向下滚动。
这里是计时器的 Tick 事件处理程序。每次计时器 Tick 时,它都会检查流。如果流不等于 "%False%",则继续检查。如果等于 "%Closed%",则发送连接已终止的消息,禁用计时器,并关闭套接字。否则,它将流发送到界面,并发出蜂鸣声作为用户警报。
这里是窗体关闭事件。在这里,它尝试关闭套接字,以实现干净的退出。
在这个子程序(按键处理程序)中,它会检查按键是否为 Enter。如果是 Enter,它会检查所有命令,并发送流,就像服务器一样。如果按键是向上,它会将文本框的值保存到 cur,并将文本框的值设置为 prev
。如果按键是向下,则执行相反的操作。
Release
- 3/31/13 1.0.0.0 Socket_Control.DLL
注意
我需要你们的反馈,这样我才能发布更新。如果我不知道如何改进,它永远不会变得更好。
历史
- 03/31/13:1.0.0.0 发布
- 04/01/13:2.0.0.0 开始构建
- 04/05/13:将流 I/O 组织到一个子类中
- 04/06/13:添加了 GetStrring() 和 GetBytes() 函数
源代码/协作
要与开发者协作项目或获取自己的源代码,请联系 croug@bimbots.tk。