Version | Adjustment |
---|---|
1.0 (2021-04-15) | Initial version |
If you want to exchange data between two smartphones via TCP, this is only possible if one of the devices takes on the server role, i.e. accepts connection requests. The (TCP) client logs on to the (TCP) server (connect), the server accepts the request (accept). A valid TCP connection then exists, which enables data to be exchanged in both directions.
Inhaltsverzeichnis
The UrsAI2TcpServer ZIP archive for download. The archive contains the source code, the compiled binary for uploading to the App Inventor and a sample application.
Notice:
The extension works perfectly if the smartphone and the remote station are in the same (local) network. If the smartphone is only connected via a cellular network, it is usually not reachable. The reason is that the smartphone is not directly connected to the Internet, but only to the local network of the mobile phone provider.
A device in your own LAN can be reached from outside via port forwarding on your own router (if necessary via DDNS). You won't be able to influence the provider's router. So sending from the smartphone to a device in the LAN works, the other way around is not possible.
The same also applies to TCP. If the smartphone is only connected to the cellular network, the connection can only be established from the smartphone. The device in the LAN must act as a server, it waits for an incoming connection request. The smartphone acts as a client, i.e. it initiates the connection. Once the connection has been set up, the routers have coordinated internally of addresses and ports. The data transfer is then possible in both directions.
The extension UrsAI2TcpServer enables TCP clients to establish a TCP connection to another Android device. Text messages can be exchanged via TCP. The text is transmittet and received line by line. A line is terminated by an end-of-line identifier (CR, LF, CRLF). If such an identifier is recognized upon receipt, the characters received up to that point are reported to the application via an event.
The Start method starts the server. It is now ready to accept connection requests from clients on the port specified by the LocalPort property. The IP address of the server can be obtained from the LocalHost property. Stop stops the server. If Start is called while the server is running, the server is first stopped and then restarted with the possibly changed settings. All settings for the server are taken over at startup. A change in the configuration only has an effect the next time Start is called.
The ServerStarted and ServerStopped events provide information about changes in the status. ServerStopped is also triggered if the server was stopped due to a (network) error. The event combination ServerStarted and ServerStopped is also triggered if the server does not even start due to an error. The IsRunning property provides information about whether the server is active.
If a client connects to the server, the ClientConnected event is triggered. Parameters are the client's IP address (ClientIP) and a numeric ID (ClientID) with which it is managed internally. If the client disconnects the ClientDisconnected event is triggered. The ConnectedClients property returns the number of clients currently connected to the server and the GetClientIDs function supplies a list with their IDs.
An incoming message from the client triggers the MessageReceived event. In addition to the actual message, the ClientID is also transferred so that the server can reply to the cleint directly via the Write and Writeln functions. Write puts the specified text into the output buffer. The immediate sending of the message is not guaranteed. Writeln writes the specified text in the output buffer and adds a end-of-line identifier which id defined by the LineDelimiterCrLf property. With true, CRLF (0x0D + 0x0A, for Windows-based servers) is appended and with false only LF (0x0A). Then the OutputStream.flush() method is called internally, which forces the data not yet sent to be sent.
The data is sent as a byte sequence. To do this, the text must be coded accordingly. The coding depends on the character set used. It is important that the sender and receiver use the same coding (the same character set). The character set used is determined by the Charset property. The name of the character set must be entered. To avoid spelling errors, the common names can be called up using the Charset_... properties.
With a TCP connection, it should actually be guaranteed that data is either sent correctly or an error is reported. Unfortunately, this is not the case with the Java implementation - at least the one on my smartphone (Java 7). Disconnections are only recognized after two write operations with a sufficiently long time interval (see java-detect-lost-connection). This also applies when the remote terminal properly closes the connection (disconnect, close,...). The time interval is necessary because the Nagle's algorithm cannot be switched off (see Java Socket Option TCP_NODELAY). The call to OutputStream.flush() does not change this beavior, thow it should trigger an immediate dispatch.
This extension offers two possibilities to detect disconnections with a high probability.
Mostly the Write method does not send the data immediately, but buffers the data. The transfer is forced with Writeln. If the CrLfDelay property has the value 0, the end-of-line identifier is appended and the message is sent immediately. If the value is greater than 0, initially only the message is sent. The end-of-line identifier is sent after a delay that is determined by CrLfDelay. If the connection is interrupted, the sending of the end-of-line identifier triggers an error and thus the ClientDisconnected event is triggered. With my smartphone, a time delay of 200 ms was sufficient.
This mechanism reduces the data rate and increases the latency times. The decision must be made between security and performance.
The TestConnection method sends two characters specified by the IgnoreTestChar property with a time delay (see above). The test character must be ignored by the recipient. Usually an invisible character is used. The character is specified as a numeric character code. The default setting is 6 (ACK, Acknowledge).
If the connection is interrupted, sending the second character triggers an error and thus the ClientDisconnected event.
Errors are indicated by error numbers (ErrorCode). Errors are reported via the ErrorOccurred or ServerStopped events. Further information on the error can be retrieved by the LastError... properties
Code | Meaning | Text | Comment |
---|---|---|---|
0 | No error | ||
1 | The server cannot be started. | Cannot create server socket. | Affected function Start. Usually the port is invalid or already in use. The error is reported via the ServerStopped event. Details can be obtained from the properties described in the Error handling section. |
2 | The server was stopped due to an error. | Server stopped due to an error. | The error is reported via the ServerStopped event. Details can be obtained from the properties described in the Error handling section. |
3 | Data could not be transmitted due to a connection error. | Connection fault. | Affected function Write, Writeln. The error is reported via the ServerStopped event. Details can be obtained from the properties described in the Error handling section. |
4 | The specified client ID is invalid. | Invalid ClientID. | Affected function Write, Writeln, Writeln. The error is reported via the ServerStopped event. |
This app sets up a TCP server that accepts connection requests on port 8083. Clients can connect to the server and send and receive text messages. After receiving a message, the server sends the text "Echo" plus the received text back to the client. The server can be tested with the UrsAI2TcpClient extension. |
Note: Appropriate endpoint data must still be entered in the Designer.
I have gathered some tips for creating your own extensions: AI2 FAQ: Developing extensions.