Option Strict On
Imports System.ComponentModel
Imports System.ComponentModel.Design
Imports System.Drawing
Imports System.Net
<ToolboxBitmap(GetType(Winsock), "Winsock.png")> _
<DefaultEvent("ErrorReceived")> _
<DesignerAttribute(GetType(WinsockDesigner), GetType(IDesigner))> _
Public Class Winsock
Inherits Component
Implements IWinsock
Public Sub New()
_localPort = 8080
_remotePort = 8080
_remoteHost = "localhost"
_maxPendingConnections = 1
_legacySupport = False
_protocol = WinsockProtocol.Tcp
_wsState = WinsockStates.Closed
_asSock = New AsyncSocket(Me)
End Sub
#Region " Events "
''' <summary>
''' Triggers an event declared at module level within a class, form, or document in a thread-safe manner.
''' </summary>
''' <param name="ev">The event to be raised.</param>
''' <param name="args">The arguements for the event.</param>
Private Sub RaiseEventSafe(ByVal ev As System.Delegate, ByRef args() As Object)
Dim bFired As Boolean
If ev IsNot Nothing Then
For Each singleCast As System.Delegate In ev.GetInvocationList()
bFired = False
Try
Dim syncInvoke As ISynchronizeInvoke = CType(singleCast.Target, ISynchronizeInvoke)
If syncInvoke IsNot Nothing AndAlso syncInvoke.InvokeRequired Then
bFired = True
syncInvoke.BeginInvoke(singleCast, args)
Else
bFired = True
singleCast.DynamicInvoke(args)
End If
Catch ex As Exception
If Not bFired Then singleCast.DynamicInvoke(args)
End Try
Next
End If
End Sub
''' <summary>
''' Occurs when connection is achieved (client and server).
''' </summary>
Public Event Connected(ByVal sender As Object, ByVal e As WinsockConnectedEventArgs) Implements IWinsock.Connected
''' <summary>
''' Occurs on the server when a client is attempting to connect.
''' </summary>
''' <remarks>Client registers connected at this point. Server must Accept in order for it to be connected.</remarks>
Public Event ConnectionRequest(ByVal sender As Object, ByVal e As WinsockConnectionRequestEventArgs) Implements IWinsock.ConnectionRequest
''' <summary>
''' Occurs when data arrives on the socket.
''' </summary>
''' <remarks>Raised only after all parts of the data have been collected.</remarks>
Public Event DataArrival(ByVal sender As Object, ByVal e As WinsockDataArrivalEventArgs) Implements IWinsock.DataArrival
''' <summary>
''' Occurs when disconnected from the remote computer (client and server).
''' </summary>
Public Event Disconnected(ByVal sender As Object, ByVal e As System.EventArgs) Implements IWinsock.Disconnected
''' <summary>
''' Occurs when an error is detected in the socket.
''' </summary>
''' <remarks>May also be raised on disconnected (depending on disconnect circumstance).</remarks>
Public Event ErrorReceived(ByVal sender As Object, ByVal e As WinsockErrorReceivedEventArgs) Implements IWinsock.ErrorReceived
''' <summary>
''' Occurs while the receive buffer is being filled with data.
''' </summary>
Public Event ReceiveProgress(ByVal sender As Object, ByVal e As WinsockReceiveProgressEventArgs) Implements IWinsock.ReceiveProgress
''' <summary>
''' Occurs when sending of data is completed.
''' </summary>
Public Event SendComplete(ByVal sender As Object, ByVal e As WinsockSendEventArgs) Implements IWinsock.SendComplete
''' <summary>
''' Occurs when the send buffer has been sent but not all the data has been sent yet.
''' </summary>
Public Event SendProgress(ByVal sender As Object, ByVal e As WinsockSendEventArgs) Implements IWinsock.SendProgress
''' <summary>
''' Occurs when the state of the socket changes.
''' </summary>
Public Event StateChanged(ByVal sender As Object, ByVal e As WinsockStateChangedEventArgs) Implements IWinsock.StateChanged
''' <summary>
''' Raises the Connected event.
''' </summary>
Public Sub OnConnected(ByVal e As WinsockConnectedEventArgs) Implements IWinsock.OnConnected
RaiseEventSafe(ConnectedEvent, New Object() {Me, e})
End Sub
''' <summary>
''' Raises the ConnectionRequest event.
''' </summary>
Public Sub OnConnectionRequest(ByVal e As WinsockConnectionRequestEventArgs) Implements IWinsock.OnConnectionRequest
RaiseEventSafe(ConnectionRequestEvent, New Object() {Me, e})
If e.Cancel Then
e.Client.Disconnect(False)
e.Client.Close()
End If
End Sub
''' <summary>
''' Raises the DataArrival event.
''' </summary>
Public Sub OnDataArrival(ByVal e As WinsockDataArrivalEventArgs) Implements IWinsock.OnDataArrival
RaiseEventSafe(DataArrivalEvent, New Object() {Me, e})
End Sub
''' <summary>
''' Raises the Disconnected event.
''' </summary>
Public Sub OnDisconnected() Implements IWinsock.OnDisconnected
RaiseEventSafe(DisconnectedEvent, New Object() {Me, New System.EventArgs})
End Sub
''' <summary>
''' Raises the ErrorReceived event.
''' </summary>
Public Sub OnErrorReceived(ByVal e As WinsockErrorReceivedEventArgs) Implements IWinsock.OnErrorReceived
RaiseEventSafe(ErrorReceivedEvent, New Object() {Me, e})
End Sub
''' <summary>
''' Raises the ReceiveProgress event.
''' </summary>
Public Sub OnReceiveProgress(ByVal e As WinsockReceiveProgressEventArgs) Implements IWinsock.OnReceiveProgress
RaiseEventSafe(ReceiveProgressEvent, New Object() {Me, e})
End Sub
''' <summary>
''' Raises the SendComplete event.
''' </summary>
Public Sub OnSendComplete(ByVal e As WinsockSendEventArgs) Implements IWinsock.OnSendComplete
RaiseEventSafe(SendCompleteEvent, New Object() {Me, e})
End Sub
''' <summary>
''' Raises the SendProgress event.
''' </summary>
Public Sub OnSendProgress(ByVal e As WinsockSendEventArgs) Implements IWinsock.OnSendProgress
RaiseEventSafe(SendProgressEvent, New Object() {Me, e})
End Sub
''' <summary>
''' Raises the StateChanged event.
''' </summary>
Private Sub OnStateChanged(ByVal e As WinsockStateChangedEventArgs) 'Implements IWinsock.OnStateChanged
If _wsState <> e.New_State Then
_wsState = e.New_State
RaiseEventSafe(StateChangedEvent, New Object() {Me, e})
End If
End Sub
#End Region
#Region " Private Members "
Private _asSock As AsyncSocket
Private _wsState As WinsockStates
Private _localPort As Integer
Private _maxPendingConnections As Integer
Private _remoteHost As String
Private _remotePort As Integer
Private _legacySupport As Boolean
Private _protocol As WinsockProtocol
#End Region
#Region " Helper Methods "
''' <summary>
''' Encapsulates the OnStateChanged methods so the AsyncSocket
''' doesn't have to build the EventArgs parameter all the time.
''' </summary>
''' <param name="new_state">The new state of the Winsock.</param>
Protected Friend Sub ChangeState(ByVal new_state As WinsockStates) Implements IWinsock.ChangeState
OnStateChanged(New WinsockStateChangedEventArgs(_wsState, new_state))
End Sub
''' <summary>
''' When the port is set dynamically by using port 0, the socket can now update the property of the component.
''' </summary>
''' <param name="new_port">The port we are now listening on.</param>
Protected Friend Sub ChangeLocalPort(ByVal new_port As Integer) Implements IWinsock.ChangeLocalPort
_localPort = new_port
End Sub
#End Region
#Region " Public Properties "
''' <summary>
''' Gets or sets a value indicating the interal size of the byte buffers.
''' </summary>
Public Property BufferSize() As Integer
Get
Return _asSock.BufferSize
End Get
Set(ByVal value As Integer)
_asSock.BufferSize = value
End Set
End Property
''' <summary>
''' Gets a value indicating whether the buffer has data for retrieval.
''' </summary>
<Browsable(False)> _
Public ReadOnly Property HasData() As Boolean
Get
Return _asSock.BufferCount > 0
End Get
End Property
''' <summary>
''' Gets or sets a value indicating if Legacy support should be used or not.
''' </summary>
''' <remarks>Legacy support is to support older winsock style connections.</remarks>
Public Property LegacySupport() As Boolean Implements IWinsock.LegacySupport
Get
Return _legacySupport
End Get
Set(ByVal value As Boolean)
If Not value AndAlso Protocol = WinsockProtocol.Udp Then
Throw New Exception("LegacySupport is required for UDP connections.")
End If
_legacySupport = value
End Set
End Property
''' <summary>
''' Gets the local machine's IP address(es).
''' </summary>
<Browsable(False)> _
Public ReadOnly Property LocalIP() As String()
Get
Dim h As System.Net.IPHostEntry = System.Net.Dns.GetHostEntry(System.Net.Dns.GetHostName)
Dim s(h.AddressList.Length - 1) As String
For i As Integer = 0 To h.AddressList.Length - 1
s(i) = CType(h.AddressList.GetValue(i), Net.IPAddress).ToString
Next
Return s
End Get
End Property
''' <summary>
''' Gets or sets a value indicating the port the <see cref="Winsock" /> control should listen on.
''' </summary>
''' <remarks>Cannot change while listening, connected, or connecting - but can change while closing.</remarks>
Public Property LocalPort() As Integer
Get
Return _localPort
End Get
Set(ByVal value As Integer)
Select Case State
Case WinsockStates.Listening
Throw New Exception("Cannot change the local port while already listening on a port.")
Case WinsockStates.Connected
Throw New Exception("Cannot change the local port of a connection that is already active.")
Case Else
If State <> WinsockStates.Closed AndAlso State <> WinsockStates.Closing Then
Throw New Exception("Cannot change the local port while the component is processing, it may have adverse effects on the connection process.")
End If
End Select
_localPort = value
End Set
End Property
''' <summary>
''' Gets or sets a value that control the length of the maximum length of the pending connections queue.
''' </summary>
''' <remarks>Cannot change while listening.</remarks>
Public Property MaxPendingConnections() As Integer
Get
Return _maxPendingConnections
End Get
Set(ByVal value As Integer)
Select Case State
Case WinsockStates.Listening
Throw New Exception("Cannot change the pending connections value while already listening.")
End Select
_maxPendingConnections = value
End Set
End Property
''' <summary>
''' Gets a NetworkStream that this Winsock object is based on.
''' </summary>
<Browsable(False)> _
Public ReadOnly Property NetworkStream() As System.Net.Sockets.NetworkStream
Get
Return _asSock.UnderlyingStream
End Get
End Property
''' <summary>
''' Gets or sets the winsock protocol to use when communicating with the remote computer.
''' </summary>
<RefreshProperties(RefreshProperties.All)> _
Public Property Protocol() As WinsockProtocol Implements IWinsock.Protocol
Get
Return _protocol
End Get
Set(ByVal value As WinsockProtocol)
If State <> WinsockStates.Closed Then
Throw New Exception("Cannot change the protocol while listening or connected to a remote computer.")
End If
_protocol = value
End Set
End Property
''' <summary>
''' Gets or sets a value that determines what remote computer to connect to, or is currently connected to.
''' </summary>
''' <remarks>Can only change if closed or listening.</remarks>
Public Property RemoteHost() As String Implements IWinsock.RemoteHost
Get
Return _remoteHost
End Get
Set(ByVal value As String)
If State <> WinsockStates.Closed AndAlso State <> WinsockStates.Listening Then
Throw New Exception("Cannot change the remote host while already connected to a remote computer.")
End If
_remoteHost = value
End Set
End Property
''' <summary>
''' Gets or sets a value that determines which port on the remote computer to connect on, or is currently connected on.
''' </summary>
''' <remarks>Can only change if closed or listening.</remarks>
Public Property RemotePort() As Integer Implements IWinsock.RemotePort
Get
Return _remotePort
End Get
Set(ByVal value As Integer)
If State <> WinsockStates.Closed AndAlso State <> WinsockStates.Listening Then
Throw New Exception("Cannot change the remote port while already connected to a remote computer.")
End If
_remotePort = value
End Set
End Property
''' <summary>
''' Gets the state of the <see cref="Winsock">Winsock</see> control.
''' </summary>
<Browsable(False)> _
Public ReadOnly Property State() As WinsockStates Implements IWinsock.State
Get
Return _wsState
End Get
End Property
#End Region
#Region " Public Methods "
''' <summary>
''' Places a <see cref="Winsock">Winsock</see> in a listening state.
''' </summary>
Public Sub Listen()
_asSock.Listen(LocalPort, MaxPendingConnections)
End Sub
''' <summary>
''' Places a <see cref="Winsock">Winsock</see> in a listening state.
''' </summary>
''' <param name="port">The port <see cref="Winsock">Winsock</see> should listen on.</param>
Public Sub Listen(ByVal port As Integer)
If port < 0 Then
Throw New ArgumentException("Port cannot be less than zero.", "port")
End If
LocalPort = port
Listen()
End Sub
''' <summary>
''' Places a <see cref="Winsock">Winsock</see> in a listening state.
''' </summary>
''' <param name="ip">The IP address the <see cref="Winsock">Winsock</see> should listen on. This must be an ip address.</param>
Public Sub Listen(ByVal ip As String)
If ip Is Nothing Then
Listen()
Else
Dim ipAddr As IPAddress = Nothing
If Not IPAddress.TryParse(ip, ipAddr) Then
Throw New ArgumentException("IP address specified is not a valid IP address.", "ip")
End If
_asSock.Listen(LocalPort, MaxPendingConnections, ipAddr)
End If
End Sub
''' <summary>
''' Places a <see cref="Winsock">Winsock</see> in a listening state.
''' </summary>
''' <param name="ip">The IP address the <see cref="Winsock">Winsock</see> should listen on.</param>
''' <param name="port">The port <see cref="Winsock">Winsock</see> should listen on.</param>
Public Sub Listen(ByVal ip As String, ByVal port As Integer)
If port < 0 Then
Throw New ArgumentException("Port cannot be less than zero.", "port")
End If
LocalPort = port
If ip Is Nothing Then
Listen()
Else
Dim ipAddr As IPAddress = Nothing
If Not IPAddress.TryParse(ip, ipAddr) Then
Throw New ArgumentException("IP address specified is not a valid IP address.", "ip")
End If
_asSock.Listen(LocalPort, MaxPendingConnections, ipAddr)
End If
End Sub
''' <summary>
''' Accepts a client connect as valid and begins to monitor it for incoming data.
''' </summary>
''' <param name="client">A <see cref="System.Net.Sockets.Socket">System.Net.Sockets.Socket</see> that represents the client being accepted.</param>
Public Sub Accept(ByVal client As Sockets.Socket)
If _asSock.Accept(client) Then
_localPort = _asSock.LocalPort
' also set remote host and port
End If
End Sub
''' <summary>
''' Creates an new <see cref="Winsock">Winsock</see> and accepts the client connection on it.
''' </summary>
''' <param name="client">A <see cref="System.Net.Sockets.Socket">System.Net.Sockets.Socket</see> that represents the client being accepted.</param>
''' <remarks>
''' This was created to be used by the listener, to keep the listener listening while
''' also accepting a connection.
''' </remarks>
Public Function AcceptNew(ByVal client As Sockets.Socket) As Winsock
Dim wskReturn As New Winsock()
wskReturn.Protocol = Me.Protocol
wskReturn.LegacySupport = Me.LegacySupport
wskReturn.Accept(client)
Return wskReturn
End Function
''' <summary>
''' Closes an open <see cref="Winsock">Winsock</see> connection.
''' </summary>
Public Sub Close()
_asSock.Close()
End Sub
''' <summary>
''' Establishes a connection to a remote host.
''' </summary>
Public Sub Connect()
_asSock.Connect(RemoteHost, RemotePort)
End Sub
''' <summary>
''' Establishes a connection to a remote host.
''' </summary>
''' <param name="remoteHostOrIP">A <see cref="System.String">System.String</see> containing the Hostname or IP address of the remote host.</param>
''' <param name="remote_port">A value indicating the port on the remote host to connect to.</param>
Public Sub Connect(ByVal remoteHostOrIP As String, ByVal remote_port As Integer)
RemoteHost = remoteHostOrIP
RemotePort = remote_port
Connect()
End Sub
''' <summary>
''' Sends an object to a connected socket on a remote computer.
''' </summary>
''' <param name="data">The object to send.</param>
''' <remarks>
''' The object is first serialized using a BinaryFormatter - unless
''' it is already a byte array, in which case it just sends the byte array.
''' </remarks>
Public Sub Send(ByVal data As Object)
Dim byt() As Byte
If LegacySupport AndAlso data.GetType Is GetType(String) Then
byt = System.Text.Encoding.Default.GetBytes(CStr(data))
Else
byt = ObjectPacker.GetBytes(data)
End If
_asSock.Send(byt)
End Sub
Public Sub SendFileCMD(ByVal data As String)
Send("!CMD_File:" & data)
End Sub
''' <summary>
''' Sends a file to a connected socket on a remote computer.
''' </summary>
''' <param name="filename">The full path to the file you want to send.</param>
''' <remarks>
''' Creates a special file object to send, so the receiving end knows what to do with it.
''' </remarks>
Public Sub SendFile(ByVal filename As String)
Dim wsf As New WinsockFileData()
Dim filesize As Long
filesize = My.Computer.FileSystem.GetFileInfo(filename).Length
Try
If Not wsf.ReadFile(filename) Then
Throw New Exception("File does not exist, or there was a problem reading the file.")
End If
If LegacySupport Then
' Send(wsf.FileData)
Else
' Send(wsf)
SendFileCMD(filename + "|" + filesize.ToString())
End If
Catch ex As Exception
SharedMethods.RaiseError(Me, ex.Message)
End Try
End Sub
''' <summary>
''' Gets the next object from the buffer, removing it from the buffer.
''' </summary>
''' <returns>
''' A Deserialized object or if it can't be deserialized the byte array.
''' </returns>
Public Function [Get]() As Object
Dim byt() As Byte = _asSock.GetData()
If byt Is Nothing Then Return Nothing
Return ObjectPacker.GetObject(byt)
End Function
''' <summary>
''' Gets the next object from the buffer as the supplied type, removing it from the buffer.
''' </summary>
''' <typeparam name="dataType">The System.Type you wish to have the data returned as.</typeparam>
''' <returns>
''' A Deserialized object converted to the data type you wish.
''' </returns>
''' <remarks>
''' This function was added to make it easier for Option Strict users.
''' It allows for easier conversion instead of the user using CType, DirectCast, or the like.
''' Can throw an error if you specify the wrong type.
''' </remarks>
Public Function [Get](Of dataType)() As dataType
Dim byt() As Byte = _asSock.GetData()
If byt Is Nothing Then Return Nothing
Dim obj As Object
If LegacySupport AndAlso GetType(dataType) Is GetType(String) Then
obj = System.Text.Encoding.Default.GetString(byt)
Else
obj = ObjectPacker.GetObject(byt)
End If
Return DirectCast(obj, dataType)
End Function
''' <summary>
''' Gets the next object from the buffer, leaving it ing the buffer.
''' </summary>
''' <returns>
''' A Deserialized object or if it can't be deserialized the byte array.
''' </returns>
Public Function Peek() As Object
Dim byt() As Byte = _asSock.PeekData()
If byt Is Nothing Then Return Nothing
Return ObjectPacker.GetObject(byt)
End Function
''' <summary>
''' Gets the next object from the buffer as the supplied type, leaving it in the buffer.
''' </summary>
''' <typeparam name="dataType">The System.Type you wish to have the data returned as.</typeparam>
''' <returns>
''' A Deserialized object converted to the data type you wish.
''' </returns>
''' <remarks>
''' This function was added to make it easier for Option Strict users.
''' It allows for easier conversion instead of the user using CType, DirectCast, or the like.
''' Can throw an error if you specify the wrong type.
''' </remarks>
Public Function Peek(Of dataType)() As dataType
Dim byt() As Byte = _asSock.PeekData()
If byt Is Nothing Then Return Nothing
Dim obj As Object
If LegacySupport AndAlso GetType(dataType) Is GetType(String) Then
obj = System.Text.Encoding.Default.GetString(byt)
Else
obj = ObjectPacker.GetObject(byt)
End If
Return DirectCast(obj, dataType)
End Function
#End Region
End Class
园子里向来高手如云,废话就不说了直接发资源。
源码示例全在附件里。
下载地址