Can I ask about synchronous sockets?

I may have missed lengthy conversation on the forums about this, and if I have, please point me to where I can read up:

I know that sockets are inherently event-driven, and merely suggesting that I want to use them in a synchronous manner will likely cause all sorts of flame-ridden vitriol to be thrown my way… but here goes:

I really prefer to use sockets in a synchronous manner in some instances… not always, but sometimes it is hugely convenient to be able to do something like this:

//In the middle of a method doing various things
//Discover I need to ask my webservices something
//Construct a new socket and send it a message, and get a response without leaving this method.
dim s as new SpiffySynchronousSocket()
dim result as Text = s.get("someURL", 10)  //old sockets had a synchronous timeout - here set to 10 seconds.
//Act on the response from the socket.
if result == "Super Fun Guy" then 
//let the user do whatever
else
//oh, ok, they are not a super fun guy.
end if
//Do more logic stuff here, etc.

I don’t care if my UI locks up for the time that the socket is communicating with the webservices - it’s HUGELY more complex to have to break the logic into multiple methods driven by event handlers in a custom socket subclass.

Am I the only one who feels this way?

Is there any way to do synchronous sockets on iOS yet? Is it safe for me to hack a socket together that behaves synchronously by sitting in a while loop until either dataAvailable fires or a timeout is hit?

You’re not the only one who feels this way so you should ignore any vitriol that is sent in your direction. :wink:

I’m pretty sure that the requirement to have async sockets on iOS is Apple’s constraint, not Xojo’s, but I know there is some code on this forum to solve your issue. I just can’t find it at the moment.

One thing I will say, however, is that I have built a commercial iOS app using async sockets and it is possible to live with them and it even can be desirable in terms of making your UI more responsive. It is, though, more complex as you say.

The OS will kill your process if it isn’t responding to events.

How quickly? Most of my network dips need well less than a second to complete. Why take away such a useful tool for those who know how to use it within the limitations that the OS imposes?

Also, if I’m in a non-UI thread doing this logic, the app would stay responsive even if my thread is blocked waiting for a network response…

FWIW this example from http://developer.xojo.com/xojo-net-httpsocket seems to me extremely simple :

Dim outputFile As Xojo.IO.FolderItem = Xojo.IO.SpecialFolder.Documents.Child("data.html") Socket1.Send("GET", "http://fontmenu.com", outputFile)

I do not believe it is possible to render the process synchronous, because you cannot use a While/Wend or Do Until to monitor a variable that will be sent by PageReceived. Xojo iOS does not have the infamous App.DoEvents that would permit running a tight loop while enabling events to take place. I tried, and as I suspected, the app freezes, which is highly taboo and will get you eternal damnation from Apple’s heaven.

From the code you posted, all you have to do is to stop the method after you call get, then in PageReceived check if all went well, and if so, continue the code in a new method where you place the end of your processing. Not very complicated.

I am not going to flame you and would have sincerely liked to give you a way to synchronize. But if I may, synchronous operations are a remnant of procedural programming, which remind me of an long past era. Sure, on the surface, they seem easier. In practice, event driven is not much more than breaking up long methods into smaller chunks.

For the simplistic example I provided, sure, changing that to be asynchronous would be relatively trivial… the issue becomes several orders of magnitude more difficult when I’m doing a synchronization of all the tables in my application database against a set of webservices. Say I have 60ish tables in my local database, and assume further that there are dependencies on the tables such that I don’t synchronize table B until table A has completed. Suddenly I’m writing a huge spaghetti mess of sync code with tons of custom sockets - one for each table type - that are all interdependent on each other because the dataAvailable event for the Table A sync socket fires up a Table B sync socket, which in turn may have to deal with tables G, M, and Q in it’s data available event, etc.

Forcing asynchronous approaches to what are really more efficiently handled in a serial (and synchronous) manner makes the programming MUCH more difficult, because instead of having all my database synchronization logic in one class or method, I have to splinter it all over the place, breaking up what is essentially a linear process into many little pieces. This makes code maintenance more difficult, and makes it much more difficult to grok the process in a year’s time when I’m chasing a bug in the sync code.

I clearly understand the benefits of async socket communication, and I have read on the apple developer forums the rationale they have behind the deprecation of NSURLConnection::sendSynchronousRequest, but in some cases it really is better to have a synchronous option available.

Where / when we’ve needed to do this in the XDC app we basically break the method in two
The fist part does its thing
Starts the request & when you get the response then the rest of the method is there (at least conceptually)
Now that does pose some issues in terms of preserving whatever state from portion before the request to the portion after the request
So you can use properties on the owner or a state object that has all the things you need to carry over
That means you’re not blocking BUT the net effect is your code still runs sequentially from a user perspective

I understand. Problem is, I do not think even Xojo engineers could conjure up a Synchronous socket even if they tried to.

You cannot shoehorn an asynchronous socket into a synchronous process, but you can can shoehorn procedural code into asynchronous, I believe. Once again, I am going to take your very simple example, but that is the principle :

Sub Procedure(LineNumber as integer, Result) Select case LineNumber case 0 //In the middle of a method doing various things //Discover I need to ask my webservices something //Construct a new socket and send it a message, and get a response without leaving this method. dim s as new SpiffySynchronousSocket() dim result as Text = s.get("someURL", 10) //old sockets had a synchronous timeout - here set to 10 seconds. Return case 1 //Act on the response from the socket. if result == "Super Fun Guy" then //let the user do whatever Procedure(2, "") else //oh, ok, they are not a super fun guy. end if Return case 2 //Do more logic stuff here, etc. Return end select End Sub

Now essentially it is procedural code. The only difference is the LineNumber parameter that branches execution to different parts of the code.

First time around the first part is executed, and exits.

Then in PageReceived, you call

Procedure(1, TextResult) // TextResult is Content converted to Text

Just an idea…

Thing is if you don’t do this, as Joe notes, watch dog will kill your app

And not knowing exactly how long a synchronous call WILL take 100% of the time means sometimes your app will just execute the magic “return to home screen feature” in iOS
Basically that is when your app crashed or was killed but the phone still runs so it returns the user to the home screen.

Watchdog is pretty aggressive. And as far as I know Apple has not documented time limits before it kills your app
https://developer.apple.com/library/ios/qa/qa1693/_index.html

A state machine of some kind (either manually like I described breaking the method apart), michels or something more elaborate will undoubtedly be more work BUT worth it

It seems (I haven’t tried it in any way) that you might be able to achieve a fairly synchronous behavior using a thread.

If calls to the sending code slept your thread, and the correct response (whatever that might be) woke it back up, then the order of execution from the thread’s point of view would be fairly synchronous.

It would require a smarter than average socket subclass, and you wouldn’t be able to interact with the UI directly, but a fairly complicated multi-step process wouldn’t be strewn all over hell’s 1/2 acre.

it might be worth a try…

+1 for this turn of phrase.

[quote=224603:@jean-paul devulder]hi,

i made free simple class (encrypted)

check if working [/quote]

Great. Thank you. This works just like the synchronous method of classic HTTPSocket, except for the timeOut. I suppose it uses the standard timeout of iOSHTTPSocket of something like 30 seconds ? That would be quite long in a phone if the server does not respond.

@Kimball Larsen : If the data you expect to download is small enough, it can be what you where looking for.

[quote=224747:@jean-paul devulder]hi Michel,
i put new version with timeout selection in few hours[/quote]

Great :slight_smile:

[quote=224603:@jean-paul devulder]hi,

i made free simple class (encrypted)

check if working [/quote]
I gave this a spin as well, and it does appear to do a synchronous get. I would not be able to use it as is for a few reasons:

  1. I need to be able to set custom headers and content for my requests
  2. I will need to be able to do all request types (PUT, GET, POST, etc)
  3. I generally won’t use encrypted classes that I can’t see the source of - do you plan to make this available in source form as a paid module or plugin?

Thanks!

I don’t think it’s a case of making an async socket. I think it’s a case of some features that are missing or forbidden in the Main Thread.

Today I tried to make a synchronous gets() for my SSLsocket subclass. Well, I can issue the socket.ReadAll(), but I’ve no way to sleep/wait/pause execution at that point and have it awoken/resumed from an event handler (such as socket.connected, socket.error, or a timer going off). What seems to be missing is something like a socket.wait() method, with execution being resumed by any event firing.