CAVEATS
Caveat One: Just because you have called TCPSocket.Connect does not guarantee that you are connected to the remote side. All it means is that the connection process has begun. Sometimes, calling TCPSocket.Connect (especially to localhost, or 127.0.0.1) will result in what seems like an instant connection. Do not be fooled by this into thinking it will work that way always! Due to network latency, among other issues, it is possible for your socket to take a long time to finish the connection process. Because of this functionality, you should not call TCPSocket.Write until you know you are connected.
The two ways to know that you are connected are to either wait until you receive a TCPSocket.Connected event, or to test the return value of SocketCore.IsConnected. If you fail to adhere to this, you either cause the connection process to halt, resulting in a lost connection error (102), or an out of state error (106).
Caveat Two: When you say TCPSocket.Write, you are beginning the process of sending data across the wire. Certain low-level socket service providers have limits on the maximum amount of data the socket can send in one batch. This is dependent on a few factors; among them are which library is providing the TCP/IP services (such as OpenTransport on Mac Classic, WinSock on Windows, etc.), and how much data you are trying to send.
You might think that the provider will only affect transfers of large data, but this is not true. Never assume how much data REALbasic will send between calls to TCPSocket.SendProgress. It is natural to see this fluctuate. Each provider that RB uses specifies the max and min amount of data it will send.
If you are trying to send data larger than the max, it will not be sent all in one chunk. Instead, RB will loop until your data is completely sent, giving you periodic TCPSocket.SendProgress events. If you try to send too little data, the underlying provider will queue your data up. This doesn’t always mean your data has been sent (though you WILL receive a TCPSocket.SendProgress and SocketCore.SendComplete event).
This is due to the underlying provider implementing the Nagle algorithm, which helps network productivity. For every chunk of data that is sent across the network, there is a header attached to the beginning of that data. You never will have to deal with these headers, because they are taken care of for you by the underlying provider. The reason this is important, though, is that if you are sending one and two bytes at a time across the network, you are also attaching these 40 or so bytes of header to each send. This can bog down a network extremely easily, unless the Nagle algorithm is implemented. All network providers that we use implement this algorithm.
Currently, REALbasic does not allow the user to turn this feature off, and leaves it set to the default. Note that, if you send only one byte of data, and never send anymore, the system will still send your one byte out even though the Nagle algorithm is enabled.
The conclusion of this caveat is: do not assume knowledge of when your data will have been completely sent. Rely on the SocketCore.SendComplete event to tell you when the send has completed. Also, do not rely on the bytesSent parameter of the TCPSocket.SendProgress event to be the same value every time. This value will change based on how many bytes of data the underlying provider was able to send.
Note: if you are going to be sending small chunks of data across a network (especially a small network), it might make more sense to use the UDPSocket class instead.
Caveat Three: One of the new features of sockets in REALbasic 5.0 is the ability to orphan a socket. (This is a necessity because of the ServerSocket class.) In making this new functionality possible, we have introduced some new behavior to the socket class. When you call SocketCore.Connect, TCPSocket.Listen, or return a socket in ServerSocket.AddSocket (*see caveat 3a), your socketÕs reference count is incremented.
This means that the socket does NOT have to be owned by the window in order for it to continue functioning. This proves helpful in certain circumstances. Example: You write your own socket subclass that implements all of the events for the socket, called MySpiffySocket. Then somewhere in the action event for a push button, say, you use the following snippet of code:
dim s as MySpiffySocket
s = new MySpiffySocket
s.port = 7000
s.address = "somecool.server.com"
s.connect
The socket will continue to live and stay connected, even though there is nothing owning a reference to it (except the within the push button’s action event).
Due to this new functionality, a socket will continue to live until you tell it to die. If you have dragged a socket to a window, and then called SocketCore.Connect or TCPSocket.Listen before closing the window, there will be two references to the socket, whereas in previous versions of REALbasic there was only one reference (the window’s reference). In this case, the socket will continue to function until its connection is terminated, even after the window has been closed.
The termination can be done either locally (by calling TCPSocket.Close) or remotely (with the remote host terminating the connection). If you have not called Connect or Listen for your socket, then there will be only one reference to it (the windowÕs), and it will be destroyed appropriately when the window closes. In either case, once the application terminates, all sockets are released gracefully, and your app will not leak memory.
Caveat Three-A: The reference count isn’t incremented as soon as you return a socket in ServerSocket.AddSocket. Instead, the socket is pooled internally, and its reference count is incremented when the server hands off a connection to that socket. So if the server socket is destroyed before it uses one of these pooled sockets, the unused sockets get destroyed as well. Until that time, the ServerSocket is the parent of the TCPSocket, and so the TCPSocket will stick around. If a socket returned from the ServerSocket.AddSocket event has been handed a connection, and then the ServerSocket is destroyed, the socket will remain connected and continue to function.
Caveat Three-B: The new functionality described above tells you that a socket can be orphaned. This does not hold true for a ServerSocket or a UDPSocket. Each of these sockets MUST have a reference holder. If it does not, then once the socket goes out of scope in your code, it is destroyed. However, when the ServerSocket is destroyed, it will not terminate any of your already-made connections (if there are any). It will only destroy TCPSockets that have not been connected.
Caveat Four: A ServerSocket can only return a TCPSocket (or a subclass of TCPSocket) in its AddSocket event. Since UDP is a connectionless protocol (see description of the UDP protocol), it does not make sense for a ServerSocket to deal with UDPSockets, or any subclass of a UDPSocket.
Caveat Five: This really is more of a “watch out for this” than a caveat. And it’s been around since the dawn of time with EVERY application that uses sockets, not just REALbasic.
When you say TCPSocket.Write, the string gets added to an internal buffer, and we start writing the data out to the socket. If you have multiple calls to TCPSocket.Write in sequential order, sometimes the writes will get strung together.
Example: if you have a chat program, and the user clicks the send button 5 or 6 times in a row really fast to send the string
Hello World
to another socket, the other socket will sometimes receive
Hello WorldHello World
This is because you have added information to the buffer fast enough that the previous send hasn’t completed yet, so you have two of your messages in the buffer for the next time through the send loop.
This is not a bug! It’s expected functionality. In order to avoid this process, I recommend you packetize your information. Include a header with your data. Example: instead of just “Hello World”, send “Hello World”. You have a beginning tag that your receiver can parse out, followed by data and an ending tag. Then if the information gets strung together into
you can parse it, and realize there are two messages there instead of one. Another approach is to have the length of the packet in the header so you know how much data belongs to one packet.
Caveat Six: Due to the nature of the UDP protocol, there are certain things you cannot take for granted with a UDPSocket that you can with a TCPSocket. UDP does not guarantee that your data will make it to its intended target. Also, UDP does not guarantee the order in which you send packets out will be the same as the order in which the remote side receives the packets. See the discussions about the TCP and the UDP protocols for more details.
Caveat Seven: Due to the way the RAS Manager works on Windows, REALbasic cannot determine which connection in your dialup connection list is the default. This is a limitation of the APIs in the operating system. Because of this, if you call System.PPPConnect in non-user interactive mode (by passing false), RB will use the first entry it finds in the connection list.
Caveat Eight: When using UDPSockets, most operations require that you be bound to a local port. For example, you cannot set the SendToSelf flag if you have not bound yourself (using the SocketCore.Connect method). This is also the case for setting RouterHops and Join/LeaveMulticastGroup. So before you make these calls, be sure to set the SocketCore.Port property and call SocketCore.Connect on the socket, otherwise you will get an out-of-state error (106).
Caveat Nine: Due to the speed increases with REALbasic 5.0 sockets, calling TCPSocket.Connect from within the TCPSocket.Error event can cause stack overflow exceptions. This situation will occur if you are flooding a server with requests that it is denying. The connection will occur, and the error will fire immediately. Then, from within the error event, you try to connect again, which (in turn) fires another error event. Use caution with socket events so that you do not get yourself into this type of situation. One workaround for this behavior is to use a timer to cause the connection process to happen. Another work-around is to set a flag before calling the initial TCPSocket.Connect call and checking the state of that flag before starting a new connection attempt.
Caveat Ten: Know your connection types when using SSLSockets. Not all servers will accept a connection with the default ConnectionType (SSLv23). This is server-specific, and generally not known beforehand. I suggest working around it by making multiple connection attempts to the server. If the initial attempt is rejected (causes a 102 error), then try again with a different ConnectionType property set. Just be sure to have a way to terminate this process if none of the connection types works, or if you get an error other than 102 (*see Caveat Nine).
Caveat Eleven: When you call ServerSocket.Listen, this begins an extensive process. The first thing that occurs is that the ServerSocket needs to fill its internal pool of handoff sockets. It does so by calling the AddSocket event. This event will be called until we have enough sockets in the internal pool of available sockets. Currently (as of 5.5), we will fill up to the MinimumSocketsAvailable plus ten extras. Note that if you return nil from this event, it will throw a NilObjectException. Only after this process has completed is the ServerSocket ready to hand off connections. Connections that come in while the server is populating its pool are rejected. To know when the ServerSocket is ready to accept incoming connections, check the ServerSocket.IsListening property.
Caveat Twelve: On Mac OS X and Linux, attempting to bind to a port < 1024 will cause a SocketCore.Error event to fire with an error 105 unless your application is running with root permissions. This is due to security issues that can arise from allowing sockets to listen on privileged ports. This is not a bug, but a security feature that is provided in some operating systems.
Caveat Thirteen: There is a limit to the number of sockets your application can have opened concurrently on Mac OS X (prior to OS 10.3). This is because BSD sockets use a file descriptor for each open socket (one that is currently bound to any port on the machine). The standard limit on OS X is set to 256 file descriptors, but this limit can fluctuate based on the amount of RAM in your machine.
This means that you can have, at most, 256 sockets connected at once per application. In practice, this number tends to be less than 256, because your application might have files open, or the underlying API calls might be using a file descriptor for their purposes. This is not an issue on Windows, Mac OS 9 or (to a certain extent) Linux, and it is not a bug in REALbasic. It is a caveat of the underlying BSD system. For more information, and a possible workaround,Note that you can run into this issue on Linux, but it tends to be far less likely. The same Mach-O call can be made on Linux as well to reset the file descriptor limit for the user.
Caveat Fourteen: One caveat to the message-based system we have implemented is that REAL Software reserves all command IDs less than 0 for internal use. That means, when you are sending messages, you should not use a command ID < 0 as it may very well cause issues with other classes (such as the AutoDiscovery class).
Caveat Fifteen: Even though you have access to the TCPSocket.Write, Read and ReadAll methods in the EasyTCPSocket 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. The same is true for the EasyUDPSocket and AutoDiscovery classes.
Caveat Sixteen: The easy networking classes were created to help you communicate with other REALbasic applications easier. As such, you cannot use things like the EasyTCPSocket class to write your own HTTPSocket. This is because we enforce a protocol under the hood (on both the sending and the receiving ends) that does not just send out raw data (like a regular TCPSocket or UDPSocket would).
So, if you need to communicate with another application over the network (like an FTP server, or some other protocol), chances are, you will not be able to use the easy networking classes provided. This also applies to the AutoDiscovery class. AutoDiscovery is not Rendezvous (or Zeroconf); it is a proprietary protocol under the hood. Because of this, you will not be able to auto-discover things like iChat over your network.
Caveat Seventeen: The UDP protocol allows you to send small packets across the network in a low-latency fashion. But with this extra freedom comes a few problems you need to watch out for. In addition to the fact that packets may be dropped or rearranged before they reach their destination, there is a concept of a maximum transmission unit (also called MTU). This MTU limit can fluctuate from system to system (on some systems, it’s a user-specific setting that can be changed), but is typically around 1500 bytes.
To be safe, always try to keep the packets you send out to having less than 1024 bytes of payload data. Failure to do so can cause the packets to be dropped by routers or rejected by network transports.
Leave a Reply
You must be logged in to post a comment.
Pages: 1 2 3 4 5 6 7 8 9 10 11 12 13