Interest in a Networking Sockets Workaround
-
Oh...Wait a minute....
I'm at work so I can't test this but.....
Are you supposed to (For each and every piece of Ruby code you want to execute):
(1)Put your code in normal RDE console
(2)Execute SUB script via Toolbar->Macro->SUBI assumed that the bridge was a constant bridge and that you just execute it once....then input and "run" ruby code as normal in RDE.
-
@unknownuser said:
(1)Put your code in normal RDE console
(2)Execute SUB script via Toolbar->Macro->SUByup, that is the workflow to use SketchUp Bridge. there is no need to install separately Ruby 1.8.6, but it helps in developing (checking source, running quick tests outside Sketchup in an automated way, ...)
-
Thanks TBD.
I just didn't pay close enough attention to your instructions...which clearly state what to do.
-
back to the original post... since there's seems to be some interest in networking sockets for sketchup. I'll tell you my findings so far...
While, I would also be interested in a C++ networking bridge, I have had success using ruby sockets in sketchup 8 on windows 7. This might be easier for people who only know ruby. Ruby sockect class comes from the socket.so file found in the 1.8.6 full ruby install. Once you have that file, just require it in your code:
require 'socket'
as you can probably guess I copied the socket.so file to the /plugins directory. That seems to work fine.
For my example there are two ruby apps. One will run in the ruby console (outside of sketchup) I'll call it the "server" and the other is sketchup itself, I'll call that the "client".
Next, I initialize a UDPsocket object and bind it to an ip and port. For my purposes I am using UDP instead of TCP because I need to send lots of little messages very often and I don't care if one gets lost. If you needed to do TCP with ruby, it can do that too.
socket = UDPSocket.new socket.bind(ip, port)
"ip" is your localhost ip address, "localhost" will work if it's just local communication. and "port" can be whatever port you want as long as it's available. I use 2000 for the server app and I use 0 for the client which causes it to generate a dynamic port number.
On the server side, I setup a loop to check for incoming messages, send any new messages, and repeat:
while connection == true begin message = socket.recvfrom_nonblock(maxlen) # messages look like this; # ["message string", ["AF_INET", 4913, "localhost", "127.0.0.1"]] # the second item of the array is the address information of the sender client_ip = message[1][3] client_port = message[1][1] new_message = true rescue Errno;;EWOULDBLOCK # fires if there is no new message new_message = false rescue Errno;;ECONNRESET # fires if something goes wrong on the client side. new_message = false connection = false break end if new_message == true # do something here with the incoming message and send a reply socket.send("got it, thanks.", 0, client_ip, client_port) end end
As you can see, I had to do some error catching on the receive. This is the only way I've figured out how to get non-blocking to work. I also left out the "do something" part to keep it simple.
On the client/Sketchup side, I make a similar loop but this time I have to use a UI.start_timer instead of a while statement because I need to give control back to sketchup each loop so that sketchup can keep doing it's thing:
timer_id = UI.start_timer(0.1, true) { begin message = socket.recvfrom_nonblock(maxlen) new_message = true rescue Errno;;EWOULDBLOCK # fires if there is no new message new_message = false rescue Errno;;ECONNRESET # fires if something goes wrong on the server side. new_message = false UI.stop_timer @timer_id break end if new_message == true # do something here with the incoming message end if outgoing_message != nil socket.send(outgoing message, 0, server_ip, server_port) end }
Couple notes here. One, I have the timer set to 1/10th of a second. Haven't really tested other speeds but this seems to work pretty good. Two, "outgoing_message" for me is something created by observers. Three, I just hard code in the server_ip, and server_port("127.0.0.1", 2000). this won't change in my application.
In this example I am sending useful information to the server, not the other way. you can reverse it or go both ways. I have also left out any acknowledgment systems you might need to confirm the other side got what you sent. I believe TCP has this built in. UDP over the internet is unreliable but if it's just meant to be local, the packet gets there pretty much every time.
Anyway, just thought I would share. I'm sure there are probably some benefits to a C++ solution but I only know ruby so I'm stuck working with what I've got. If anyone looks at this and thinks this it completely wrong, let me know. I'm still learning.
-Mike
-
One last question....Did you figure out the method of ruby integration through some documentation? or did you simply poke around enough?
I guess if you are already familiar with he inner working of Ruby at the object file level then you would already recognize some stuff you'd find in Sketchups directories.
I was learning the sketchup API as a reason to learn Ruby >.<.
Anyways...thanks a lot for the treasure trove of information you've just presented me...now to do something useful.
-
@rabidcicada said:
One last question....Did you figure out the method of ruby integration through some documentation? or did you simply poke around enough?
The old "Pick-Axe" book has a chapter on how applications embed Ruby as a scripting extension. See the chapter Extending Ruby, and scroll down to the section "Embedding a Ruby Interpreter".
However, that example seems to use a standard Ruby install... Sketchup did a few custom things.. so yes a bit of poking around, trial and error, was needed to understand.@rabidcicada said:
I guess if you are already familiar with the inner working of Ruby at the object file level then you would already recognize some stuff you'd find in Sketchups directories.
Not really. Most people who learn standard Ruby first, are not familar with a Ruby implemented for embedding in applications. They expect the Ruby dirs and files to be in the standard locations.
And then Sketchup distro's with only the Core classes, and none of the standard fare of extended libraries.@rabidcicada said:
I was learning the sketchup API as a reason to learn Ruby
Same Same. Sketchup introduced me to Ruby.
-
@dan rathbun said:
You don't have a choice. The only way to have Sketchup perform an event-driven task, (because Sketchup "owns" the event loop,) is to use one of the Ruby API's observer classes that reacts to changes in a list-like object.
I stand corrected. I was thinking event-driven.
mtalbott, showed a polling means using the UI.start_timer block. Forget about that... should be much eaiser to implement.
-
@rabidcicada said:
Does Sketchup have it's own local copy of Ruby 1.8.6 etc?
Yes, BUT only the interpreter, which loads ONLY the Ruby Core modules and classes. (Sketchup then loads it's own API extension modules and classes, and additions to a few of the Core classes: Array, Length, Numeric and String.)
On MS Windows, the interpreter binary that Sketchup loads, is in the Sketchup program folder, and is named msvcrt-ruby18.dll; and is an exact copy of the dll (of the same name,) that resides in the bin folder of a full install.
Win32 Sketchup vers 6 & 7, have the v1.8.0 (initial release) interpreter DLL.
Win32 Sketchup ver 8 has the v1.8.6-p287 interpreter DLL.On Mac, for vers 6 thru 8 (current MR,) the interpreter Sketchup loads (by default,) is a framworkized Ruby v1.8.5 (initial release,) Core only, that resides in subdirectories, beneath the Sketchup application directory.
@rabidcicada said:
Or are you saying that I must use that version if I am to successfuly drive sketchup externally?
It certainly helps to use the same version that Sketchup loads.
On Windows, it is very easy to force Sketchup to load a specific Ruby version (in the 1.8.x branch,) by replacing the interpreter DLL in the Sketchup program folder.)
See my post on this subject: Ruby Interpreter DLLs (Win32).On Mac, it requires the changing of symbolic links.
This Stackoverflow post shows how, but realize you will be overwriting the default links. (Mac users should backup the originals first.)@rabidcicada said:
Should I separately install Ruby 1.8.6?
Ruby v1.8.6-p287 Windows One-Click Installer (self-extracting zip installer.)
Since MS Windows does not come "out-of-the-box" with a full Ruby install (like a Mac does,) it will be to your benefit to do a full Ruby install, so you can have access to the extended Ruby library files.
See my !load_paths.rb script, to add paths for the standard lib folders, to the $LOAD_PATH array in Sketchup embedded Ruby.@rabidcicada said:
Thanks for the pointer to Alexs stuff...I'll play with that also.
Alex's SCF Plugin topic: [plugin] Ruby Code Editor
which links to his website: SketchUp Ruby Code Editor@rabidcicada said:
I am SEVERELY unfamiliar with hacking up sketchup...FYI.
When you install the full Ruby, you will have the CHM Ruby Language reference for both the Core and the Extended Libraries, in the doc folder. (Make shortcuts to them.. or copy the CHM files someplace, your desktop, wherever you can find them easily, as you will be refering to them constantly.) Or... (in the interim,) you can download the CHM from my post in the SCF Ruby References topic here.
Also, the full install comes with a PDF of Huw Collingbourne's THE BOOK OF RUBY which may help.You can click the Ruby Resources link in my signature... this will lead you to a multitude of info, (tutorials, downloadable books etc.)
See the [Code Snippets] sticky post on C/C++ Extensions
.. which has a link to the C source for Ruby. You may wish to read the source for Ruby's standard Socket library for ideas.
EDIT: (2011-05-08) Sorry.. had the one-click installer link pointing to the C source. Corrected links.
-
Sorry... had the link in my previous post pointing to the C sourcecode archive. (Corrected links in original post.)
Ruby v1.8.6-p287 Windows One-Click Installer (self-extracting zip installer.)
Advertisement