Dear John, How Do I... Communicate Using Winsock?

Applications connect to the Internet through an IP address and a port number. The combination of an IP address and a port number is called a socket. You establish a connection between two machines by creating a pair of sockets that match.

Use the Winsock control (MSWINSCK.OCX) to create matching sockets for use with UDP or TCP. Your choice of protocol depends on the type of communication you wish to establish:

The following sections show how to use the Winsock control to create Internet applications with UDP and TCP. Before you get carried away and start programming your own mail system, however, you should realize that Winsock is a low-level tool. There are already implementations of application-level protocols for Visual Basic. These include the Internet Transfer control (MSINET.OCX) for FTP and HTTP and other commercially available controls for Post Office Protocol (POP), audio, and three-dimensional (3D) data. Information about third-party controls is available on the Internet. Here are some starting points:

Broadcasting with UDP

Using the Winsock control with UDP is a two-part process: you use one set of steps to send data and another set to receive them.

To send data, add a Winsock control to a form and then follow these general steps:

  1. Set the RemotePort property to the port number used by other machines to receive the data you are going to send.

  2. Set the RemoteHost property. This is the IP address or the friendly name of the host computer which will receive your data.

  3. Use the Bind method to open a local port from which to send the data.

  4. Use the SendData method to transmit the data.

To receive data using UDP, follow these general steps:

  1. Set the RemotePort property to the port number used by the Bind method in step 3 of the previous procedure.

  2. Use the Bind method to open a local port over which to receive the data. This is the same port number used in the RemotePort property in step 1 of the previous procedure.

  3. Use the GetData method in the DataArrival event procedure to retrieve the data sent.

A Broadcasting Sample

Because you don't need to identify the remote host when receiving data, UDP can be used to get messages from many different computers. This many-to-one relationship lets you create administrative tools that monitor the status of the workstations on a network, such as the Systems Status Monitor (SysStat.VBP) shown in Figure 7-4.

Figure 7-4. The Systems Status Monitor reports the amount of free disk space from workstations to an administrative machine.

The Systems Status Monitor has two functions: When invoked with a command line, it sends the percentage of free disk space from the local machine to the remote machine identified in the command line. When invoked without a command line, the Systems Status Monitor acts as the passive recipient of disk information sent from workstations.

The following Form_Load event procedure shows how the Winsock control is set to send or receive data, depending on the command line.

Option Explicit
`Create object for log file
Dim fsysLog As New Scripting.FileSystemObject

`Command line specifies the name or IP address of
`the machine to send data to
Private Sub Form_Load()
    `Start this application in send mode
    `if a command line is specified

    If Command <> "" Then
        `Set a remote port to send to
        sckUDP.RemotePort = 1002
        `Identify the host to send to
        sckUDP.RemoteHost = Command
        `Bind to a local port to send from
        sckUDP.Bind 1001
        `Send information
        sckUDP.SendData ShowStats
        `End this application
        Unload Me
    `Start in receive mode if no
    `command line
    Else
        `Specify remort port to listen for
        sckUDP.RemotePort = 1001
        `Specify local port to receive from
        sckUDP.Bind 1002
        `Display information along with this
        `machine's "friendly" name
        Me.Caption = Me.Caption & ": " & sckUDP.LocalHostName
    End If
End Sub

The Winsock control's Error event procedure is called if there is no Internet connection or if the specified remote host name is invalid. Because the Systems Status Monitor uses UDP, error checking is minimal. The Systems Status Monitor simply displays any errors that occur, as shown here:

`Handle transmission errors
Private Sub sckUDP_Error(ByVal Number As Integer, _
    Description As String, ByVal Scode As Long, _
    ByVal Source As String, ByVal HelpFile As String, _
    ByVal HelpContext As Long, CancelDisplay As Boolean _
)
    `Display error messages
    MsgBox Number & " " & Description, vbCritical, App.Title
End Sub

The Winsock control's DataArrival event procedure is called when data is received over the bound port. The GetData method retrieves the data that has arrived and clears the receive buffer so that the next item in the queue is available.

`Handle data as it comes in
Private Sub sckUDP_DataArrival(ByVal bytesTotal As Long)
    Dim strData As String
    `Retrieve the data
    sckUDP.GetData strData
    `Display it
    ShowText strData
    `Save data in log file if check box selected
    If chkLog.Value Then
        fsysLog.CreateTextFile(CurDir & "\stats.log", _
            True).Write txtReceive.Text
    End If
End Sub

The amount of data that can be sent via UDP as a single chunk is determined by your network. You can experiment to find the upper limit, but it is not a good idea to rely on UDP for exchanging large amounts of data. For that, you should use TCP.

One-on-One Chatting with TCP

To use the Winsock control with TCP, you must establish a connection before attempting to transmit data. Creating the connection has two parts: one machine requests a connection, and the other machine accepts it.

To request a connection, add a Winsock control to a form and then follow these general steps:

  1. Set the RemoteHost property. This is the IP address or the friendly name of the host computer which will receive the data you are going to send.

  2. Set the RemotePort property to the port used by other machines to receive your data.

  3. Use the Connect method to request a connection to the other machine.

  4. Use the SendData method to transmit the data.

To accept a connection, follow these general steps:

  1. Set the LocalPort property to the port specified by the RemotePort property in step 2 of the preceding procedure.

  2. Use the Listen method to open the local port for connection requests.

  3. Use the Accept method in the ConnectionRequest event procedure to establish the connection.

Once the connection is established, data can be exchanged using the SendData and GetData methods, just as with UDP. Unlike UDP, however, TCP requires that you use the Close method to end the existing connection before you can create a new connection.

A Chatting Sample

The Chat sample (Chat.VBP) demonstrates how to use Winsock with TCP to create a connection between two machines. Once the connection is established, two users can exchange messages by typing in the text box as shown in Figure 75.

Click to view at full size.

Figure 7-5. The Chat sample allows two users to send messages to one another by using TCP.

The Chat sample starts out listening for connection requests. The Form_Load event procedure sets the local port to listen on and then starts listening, as shown in the following code.

Option Explicit
 
`Start out listening for connection
`requests
Private Sub Form_Load()
    `Set the port to listen on
    sckTCP.LocalPort = 1002
    `Begin listening
    sckTCP.Listen
    `Update status bar
    ShowText "Listening"
End Sub

To initiate a connection, call the Connect method. The Chat sample allows users to specify a machine name or an IP address to connect through an InputBox, closes any existing connection, and then establishes the new connection as shown below.

Private Sub mnuConnect_Click()
    Dim strRemoteHost As String
    `Get the name of a computer to connect to
    strRemoteHost = InputBox("Enter name or IP address of computer " & _
        "to connect to.", vbOKCancel)
    `Exit if cancelled
    If strRemoteHost = "" Then Exit Sub
    `Close any open connections
    sckTCP.Close
    `Set the name of the computer to connect to
    sckTCP.RemoteHost = strRemoteHost
    `Specify a port number on remote host
    sckTCP.RemotePort = 1002
    `This seems to prevent some TCP errors
    DoEvents
    `Request the connection
    sckTCP.Connect
End Sub

The ConnectionRequest event occurs when the listening machine receives a request from another machine. The Chat sample accepts all requests, as shown below.

Private Sub sckTCP_ConnectionRequest(ByVal requestID As Long)
    sckTCP.Close
    sckTCP.Accept requestID
    ShowText "Accepting request from " & sckTCP.RemoteHostIP
End Sub

Once the listening machine accepts a connection, either machine can transmit data to the other using the SendData method. The Chat sample uses the txtChat text box to compose messages to send and display messages received. The KeyPress event procedure below keeps track of what the user types and sends the message when the user presses Enter.

Private Sub txtChat_KeyPress(KeyAscii As Integer)
    Static strSend As String
    `Make sure there is a connection
    If sckTCP.State <> sckConnected Then Exit Sub
    `Send data when user presses Enter
    If KeyAscii = Asc(vbCr) Then
        `Send the string
        sckTCP.SendData strSend
        `Clear the variable
        strSend = ""
    Else
        `Keep track of what is being typed
        strSend = strSend & Chr(KeyAscii)
    End If
End Sub

The SendData method above triggers the DataArrival event on the receiving side of the connection. The Chat sample uses GetData to retrieve information from the message queue and displays it in the txtChat text box as shown by the following code.

Private Sub sckTCP_DataArrival(ByVal bytesTotal As Long)
    Dim strText As String
    `Get data
    sckTCP.GetData strText
    `Display data received
    txtChat = txtChat & ">>" & strText & vbCrLf
    `Move cursor to end
    txtChat.SelStart = Len(txtChat)
    ShowText "Bytes received: " & bytesTotal
End Sub

To end the connection, simply call the Close method. The Chat sample includes a menu item to disconnect and return to listening as shown by the following code.

Private Sub mnuDisconnect_Click()
    sckTCP.Close
    DoEvents
    sckTCP.Listen
    ShowText "Listen"
End Sub

The Close method triggers the Close event on the other machine. When a Close event occurs, the Chat sample returns to listening for new connections as shown by the following code.

Private Sub sckTCP_Close()
    ShowText "Close"
    `When connection by remote machine, go back to listening
    sckTCP.Close
    sckTCP.Listen
    ShowText "Listen"
End Sub

TCP connections provide a great deal more error information than UDP connections, so it is important to display error information to the users. The Error event happens whenever an exception occurs in establishing or using a connection. The Chat sample displays errors using the following code.

`Display error information
Private Sub sckTCP_Error(ByVal Number As Integer, _
    Description As String, ByVal Scode As Long, _
    ByVal Source As String, ByVal HelpFile As String, _
    ByVal HelpContext As Long, CancelDisplay As Boolean _
)
    ShowText "Error " & Number & " " & Description
End Sub

For more information on events that occur during a TCP connection, see the Chat sample (Chat.VBP) included on the companion CD-ROM. Additional description is also available in the topic "Using the Winsock Control" in the Visual Basic online help.