Class
EasyTCPSocket
Description
Communicates with remote Xojo applications with a proprietary protocol that is implemented over TCP. It is provided so that a user who is new to TCP/IP communications can use a higher-level class than the TCPSocket class to network their applications.
Properties
Name |
Type |
Read-Only |
Shared |
---|---|---|---|
✓ |
|||
✓ |
|||
✓ |
|||
✓ |
|||
✓ |
|||
✓ |
Methods
Name |
Parameters |
Returns |
Shared |
---|---|---|---|
encoding As TextEncoding = Nil |
|||
count As Integer |
|||
Timeout As Integer |
|||
Data As String |
|||
Constants
These constants indicate which error occurred. They are the same error codes returned by SocketCore. When an Error event occurs, check the value of the passed parameter Code against these class constants.
Error Code |
Class Constant |
---|---|
100 |
OpenDriverError |
102 |
LostConnection |
103 |
NameResolutionError |
105 |
AddressInUseError |
106 |
InvalidStateError |
107 |
InvalidPortError |
108 |
OutOfMemoryError |
Property descriptions
EasyTCPSocket.Address
Address As String
The TCP/IP address to try to connect to.
In this example, the address has been entered into a TextField.
TCPSocket1.Address = TextField1.Text
EasyTCPSocket.BytesAvailable
BytesAvailable As Integer
The number of bytes of data are available in the internal receive buffer.
This property is read-only.
TextField1.Text = Me.BytesAvailable.ToString
EasyTCPSocket.BytesLeftToSend
BytesLeftToSend As Integer
The number of bytes left in the queue remaining to be sent.
This property is read-only.
This enables you to create a synchronous socket without needing to subclass it.
TextField1.Text = Me.BytesLeftToSend.ToString
EasyTCPSocket.Handle
Handle As Integer
This is the socket's internal descriptor and it can be used with Declare statements.
This property is read-only.
On Windows, Handle is a Socket, suitable for use in Declares on Windows.
On macOS and Linux, Handle is a UNIX socket descriptor.
The descriptor is platform-specific. If Handle is less than zero, the descriptor is not available.
EasyTCPSocket.IsConnected
IsConnected As Boolean
Indicates whether the socket is currently connected.
This property is read-only.
For TCPSockets, a connection means you can send and receive data and are connected to a remote machine. For UDPSockets, this means that you are bound to the port and are able to send, receive, join or leave multicast groups, or set socket options.
If EasyUDPSocket1.IsConnected Then
' proceed using the connection
Else
MessageBox("Connection failed!")
End If
EasyTCPSocket.LocalAddress
LocalAddress As String
The local IP address of the computer.
This property is read-only.
Var localIP As String = Socket1.LocalAddress
EasyTCPSocket.NetworkInterface
NetworkInterface As NetworkInterface
Specifies which network interface the socket should use when binding.
You can get the network interface(s) of the user's computer by calling the GetNetworkInterface method of the System module.
Leaving this property set to Nil will use the currently selected interface. In the case of UDPSockets, if you assign a non-Nil value, the socket may not be able to receive broadcast messages. The behavior is OS-dependent; it appears to work on Windows but not on other supported operating systems. If you wish to send broadcast packets out, then you should not bind to a specific interface because the behavior is undefined.
This example specifies that the TCPSocket will use the first Network Interface on the user's computer.
TCPSocket1.NetworkInterface = System.NetworkInterface(0)
EasyTCPSocket.Port
Port As Integer
The port to bind on or connect to.
On most operating systems, attempting to bind to a port less than 1024 causes a Error event to fire with an error number 107 unless the application is running with administrative permissions. This is due to security features built into the underlying OS.
You need to set the port property explicitly before any call to Listen or Connect as the Port property will be modified to reflect what the actual bound port is during the various stages of operation.
For instance, if you listen on port 8080 and a connection comes in, you can check the Port property to ensure that you're still listening on port 8080 (that the port hasn't been hijacked). Or, if you connect to a socket on port 8080, once the connection occurs, you can check to see what port the OS has bound you to. This will be a random-seeming port number.
This trick can be very useful when you do things like Listen on port 0. In that case, the OS will pick a port for you and listen on it. Then you can check the Port property to see which port the OS picked. This functionality is used for various protocols, such as FTP.
This example sets the Port to 8080.
TCPSocket1.Port = 8080
EasyTCPSocket.RemoteAddress
RemoteAddress As String
The address of the remote machine you are connected to.
This property is read-only.
Use this instead of the Address property to determine the address of the machine you are actually connected to.
This example reports the address of the remote machine that the user is connected to. It is in the Connected event.
TextField1.Text = Me.RemoteAddress
Method descriptions
EasyTCPSocket.Close
Close
Closes the socket's connection, closes any connections the socket may have, and resets the socket.
The only information that is retained after calling Close is the socket's port, address (in the case of TCPSockets), LastErrorCode properties, and data left in the socket's receive buffer. All other information is discarded.
This example closes the EasyTCPSocket that were open. The sockets were added to the main window.
Connector.Close
Listener.Close
EasyTCPSocket.Connect
Connect
Attempts to connect.
For TCPSockets, the address and port properties must be set. For UDPSockets, the port property must be set. The Connect method binds a socket to a port. After calling Connect, the Port property will report the actual port you are bound to.
EasyTCPSocket.Disconnect
Disconnect
Disconnects the socket, resets it, and fires a SocketCore Error event with a 102 error to let you know that the socket has been disconnected.
This example disconnects the EasyTCPSocket that were opened.
Connector.Disconnect
Listener.Disconnect
EasyTCPSocket.EndOfFile
EndOfFile As Boolean
Returns True when there's no more data left to read.
This code reads the rows and columns of data from a tab-delimited text file into a ListBox:
Var f As FolderItem
Var textInput As TextInputStream
Var rowFromFile As String
f = FolderItem.ShowOpenFileDialog("text/plain") ' defined as a FileType
If f <> Nil Then
textInput = TextInputStream.Open(f)
textInput.Encoding = Encodings.UTF8
Do
rowFromFile = textInput.ReadLine
Var values() As String = rowFromFile.ToArray(String.Chr(9))
ListBox1.ColumnCount = values.Count
ListBox1.AddRow("")
Var col As Integer
For Each value As String In values
ListBox1.CellTextAt(ListBox1.LastAddedRowIndex, col) = value
col = col + 1
Next
Loop Until textInput.EndOfFile
textInput.Close
End If
This example reads each pair of bytes from a file and writes them in reverse order to a new file. The user chooses the source file using the Open-file dialog box and saves the new file using the Save as dialog box. The EOF property is used to terminate the Do...Loop.
Var readFile As FolderItem = FolderItem.ShowOpenFileDialog("text")
If readFile <> Nil Then
Var ReadStream As BinaryStream = BinaryStream.Open(readFile, False)
ReadStream.LittleEndian = True
Var writeFile As FolderItem = FolderItem.ShowSaveFileDialog("", "")
If writeFile <> Nil Then
Var writeStream As BinaryStream = BinaryStream.Create(writeFile, True)
writeStream.LittleEndian = True
Do Until ReadStream.EndOfFile
writeStream.WriteInt8(ReadStream.ReadInt8)
Loop
writeStream = Nil
End If
readStream = Nil
End If
EasyTCPSocket.Flush
Flush
Immediately sends the contents of internal write buffers to disk or to the output stream.
This function can be useful in point-to-point communication over sockets and similar connections: To optimize for transmission performance, some types of output streams try to collect small pieces of written data into one larger piece for sending instead of sending each piece out individually. By calling Flush, the data collection is stopped and the data is sent without further delay, reducing latency.
When using this on a stream that ends up as a file on disk, it is useful, too: Any short parts of previously written data are written to disk right away, ensuring the data is actually on disk if the application terminates abruptly, e.g. due to a crash.
Avoid calling this method too often. For example, do not call it between successive Write calls because you'll slow down performance without getting much benefit.
A typical use case would look like this:
mySocket.Write("you typed: ")
mySocket.Write(key)
mySocket.Write(".")
mySocket.Flush
EasyTCPSocket.Listen
Listen
Attempts to listen for incoming connections on the currently specified port.
After calling Listen, the Port property will report the actual port you are bound to.
EasyTCPSocket.Lookahead
Lookahead(encoding As TextEncoding = Nil) As String
Returns a String, containing the data that is available in the internal queue without removing it.
The optional encoding parameter enables you to specify the text encoding of the data to be returned. The default is Nil. Use the Encodings module to specify an encoding.
This example adds the contents of the internal queue to a TextArea. The Listener EasyTCPSocket has been added to the window.
TextArea1.AddText(listener.Lookahead)
EasyTCPSocket.Poll
Poll
Polls the socket manually, which allows a socket to be used synchronously.
The EasyTCPSocket "Listener" has been added to the window.
Listener.Poll
EasyTCPSocket.Purge
Purge
Removes all data from the socket's internal receive buffer. It does not affect the socket's internal send buffer.
Listener.Purge
EasyTCPSocket.Read
Read(count As Integer) As String
Reads Count bytes from the input stream and returns a String.
If provided, the optional parameter Enc specifies the text encoding to be defined for the String to be read.
If Count is higher than the amount of bytes currently available in the stream, all available bytes will be returned. Therefore, make sure to always consider the case that you get less than you requested. To see if you received all requested bytes, check the returned string's String property (avoid using Length as it may give a different number if the encoding is not nil).
If not enough memory is available, you get back an empty string.
This example reads the first 1000 bytes from a BinaryStream.
Var readFile As FolderItem = FolderItem.ShowOpenFileDialog("text/plain")
If readFile <> Nil Then
Var ReadStream As BinaryStream = BinaryStream.Open(readFile, False)
ReadStream.LittleEndian = True
TextArea1.Text = ReadStream.Read(1000, Encodings.UTF8)
End If
EasyTCPSocket.ReadAll
ReadAll As String
Reads all the data from the internal buffer.
This example reads all the data in the buffer into a TextArea.
TextField1.AddText(listener.ReadAll)
EasyTCPSocket.ReadError
ReadError As Boolean
If True then an error occurred during reading.
EasyTCPSocket.SendMessage
SendMessage(Command As Int32, Data As String)
Sends a message, consisting of the code command and the text, data.
Effective with 2017r3, the command parameter is Int32 instead of Integer to prevent incorrect behavior in 64-bit apps.
EasyTCPSocket.WaitForConnection
WaitForConnection(Timeout As Integer) As Boolean
Waits for a connection until Timeout elapses. Timeout is in seconds.
Returns True if a connection is made; otherwise it returns False.
If EasyTCPSocket1.WaitForConnection(10) Then
' execute communications
Else
' connection failed
End If
EasyTCPSocket.WaitForMessage
WaitForMessage(Command As Int32, Timeout As Integer) As String
Waits for a message identified by the value of Command.
Effective with 2017r3, the command parameter is Int32 instead of Integer to prevent incorrect behavior in 64-bit apps.
Returns a String, containing the message text. The timeout is the amount of time in seconds that the socket will wait for a message before stopping.
The command parameter can be used as a code to identify the type of data that is sent. For example, you could send a command ID of 100 to mean that the string data is actually a memory block containing a FolderItem. Or, you could define ID 101 as the username of a remote application. This message mode is enforced on you in that you cannot use an arbitrary Write command. If you'd like to send arbitrary data, then you can make up a miscellaneous command ID and send your arbitrary data.
Command IDs less than 0 are reserved for internal use. When you are sending messages, you should not use a command ID less than 0, as it may very well cause issues with other classes.
EasyTCPSocket.Write
Write(Data As String)
Writes the passed data to the output stream.
Note that in order to make sure that the data actually ends up on disk or gets sent to the socket it is connected to, the stream must either get closed or the Flush method be called. Otherwise, the data, if small, may end up temporarily in a write buffer before either a certain time has passed or more data is written. This buffering increases performance when writing lots of small pieces of data, but may be causing unwanted delays when another process, e.g. the other end of a socket connection, is waiting for the data. Consider calling the Flush method to reduce latencies that this buffering may cause in such cases.
If Write fails, an IOException will be raised.
This example displays the Save As dialog box and writes the contents of the TextArea1 to a text file.
Var f As FolderItem
Var stream As BinaryStream
f = FolderItem.ShowSaveFileDialog(FileTypes1.Text, "Untitled.txt")
If f<> Nil Then
stream = BinaryStream.Create(f, True)
stream.Write(TextArea1.Text)
stream.Close
End If
EasyTCPSocket.WriteError
WriteError As Boolean
If True then an error occurred during writing.
Event descriptions
EasyTCPSocket.Connected
Connected
Executes when the connection is established with the server.
EasyTCPSocket.Error
Error(code As Integer)
Occurs when an error occurs with the socket.
These error codes provide you with key information about your socket, and it is not advisable to ignore them.
Error Code |
Description |
---|---|
0 |
No error occurred. |
100 |
There was an error opening and initializing the drivers. |
101 |
This error code is no longer used. |
102 |
This code means that you lost your connection. |
103 |
The socket was unable to resolve the address that was specified. |
104 |
This error code is no longer used. |
105 |
The address is currently in use. |
106 |
This is an invalid state error, which means that the socket is not in the proper state to be doing a certain operation. |
107 |
This error means that the port you specified is invalid. |
108 |
This error indicates that your application has run out of memory. |
Information on additional error codes is available.
The following example in the Error event handler displays the error code.
MessageBox(Me.e.ErrorNumber.ToString)
EasyTCPSocket.ReceivedMessage
ReceivedMessage(Command As Int32, Data As String)
A message, consisting of an identifying integer, Command, and the text Data, has been received.
Effective with 2017r3, the command parameter is Int32 instead of Integer to prevent incorrect behavior in 64-bit apps.
EasyTCPSocket.SendComplete
SendComplete(UserAborted As Boolean)
Occurs when a send has completed.
Use this to determine when all your data has been sent. UserAborted will be True if the user aborted the send by returning True from the SendProgress event. You can use this information to update different status variables or to inform user about the success or failure of the transfer. If the send was completed, this value is False. UserAborted will always be False for UDP sockets.
EasyTCPSocket.SendProgress
SendProgress(BytesSent As Integer, BytesLeft As Integer) As Boolean
Occurs when your network provider queues your data in chunks and is about to send the next chunk.
The parameters indicate the amount of progress that has been made during the send. Returns a Boolean.
Returning True from this event causes the send to be cancelled. This does not close the socket's connection; it only clears the buffer. After all of the data has been transferred you will get a final SendProgress event followed by a SendComplete event.
bytesSent is the number of bytes that were sent in the chunk, not the total number of bytes sent.
Notes
Even though you have access to the Write, Read and ReadAll methods of the TCPSocket class, you should never call them. Doing so will cause a RuntimeException to be raised (with an appropriate message set). This is so the internal protocol is enforced.
If you are subclassing a EasyTCPSocket, you must call the Super class's constructor in your own subclass's constructor. The subclass will not work or exhibit “strange” behavior unless this is done. Use the Super keyword.
The Command parameter can be used as a code to identify the type of data that is sent. For example, you could send a command ID of 100 to mean that the string data is actually a memory block containing a FolderItem. Or, you could define ID 101 as the username of a remote application. This message mode is enforced on you in that you cannot use an arbitrary Write command. If you'd like to send arbitrary data, then you can make up a miscellaneous command ID and send your arbitrary data.
Command IDs less than 0 are reserved for internal use. When you are sending messages, you should not use a command ID less than 0, as it may very well cause issues with other classes.
The EasyTCPSocket class allows you to establish connections and communicate via the TCP protocol with a remote machine. The main difference between the EasyTCPSocket class and the regular TCPSocket class is the message-based aspects of the protocol. The connection process is identical to a regular TCPSocket. However, when you want to send data to a remote machine you must use the SendMessage method to do so.
When you receive data, you are not given a DataAvailable event, as is you are for TCPSocket. Instead, the entire message is passed to you via the ReceivedMessage event. Because of this, we do not allow you to read in arbitrary data using the Read or ReadAll methods of the TCPSocket class.When you receive a message sent via this protocol, you handle it via the ReceivedMessage event handler.
For synchronous communications, there is a WaitForConnection method which will synchronously wait a predetermined amount of time for a connection to be established. If the connection is made, it returns True, otherwise, it returns False.
For synchronous communications, use the WaitForMessage method. This method waits for a message to come in with the command ID you specify. Once that message comes in, it will return the string data portion of that message. If a message comes in with a command ID that is different from the one you are expecting, it will drop that message.
The EasyTCPSocket class is designed only for easy communication among Xojo applications on the network. It is not designed to be the basis for custom TCP-based communication protocols. It works only for other applications that implement the EasyTCPSocket protocol.
Compatibility
Desktop and web project types on all supported operating systems.
See also
TCPSocket parent class; AutoDiscovery, EasyUDPSocket, TCPSocket, UDPSocket classes.