I am following the tutorial: http://www.tutorialspoint.com/ruby/ruby_socket_programming.htm and using it to set up the "Simple Client".
The code is as follows:
require 'socket' # Sockets are in standard library
hostname = 'localhost'
port = 2000
s = TCPSocket.open(host, port)
while line = s.gets # Read lines from the socket
puts line.chop # And print with platform line terminator
end
s.close # Close the socket when done
When I execute a single s.gets statement, I get the first response line from the server. When I do s.gets again, I get the second response line, etc. However, the moment I get to the end of the response and do s.gets then the program goes into a frozen state. (This is if I test the above program from the Rails Console). The same happens when I run the code - the freeze occurs when the while statement does the final s.gets. Any ideas on how to solve this?
For information: The server is a C# server that sends response messages using the following C# code (each line of the response uses the same code and the final line in the response is not treated any differently from the other lines):
socket.Send(Encoding.ASCII.GetBytes(msg + "\r\n"));
So I am thinking the client freezes because it probably doesn't interpret the servers "end of response" properly. Any ideas?
It seems like there is a problem with reading the nil value from the socket. Still not sure why this happens, but using a selector as suggested in Recovering from a broken TCP socket in Ruby when in gets() solves the problem very nicely (would have upvoted his answer, but don't have enough rep).
Solution I followed was to add the selector in a method as follows:
def next_line_readable?(socket)
readfds, writefds, exceptfds = select([socket], nil, nil, 0.1)
p :r => readfds, :w => writefds, :e => exceptfds
readfds #Will be nil if next line cannot be read
end
and then in main program to use it like:
socket = TCPSocket.open(host, port)
while next_line_readable?(socket)
puts socket.gets.chop
end
Try this am writing a tcp client and server in ruby
def sendto(str)
begin
socket.write(str)
puts "Sent Message to:" + socket.peeraddr[2]
rescue Exception=>e
puts red("Error Make sure the target is connected")
end
end
Check it out works perfectly until 4hours then disconnects
Connection to ruby based server
Try using the socket.read or socket.recvfrom methods instead of socket.gets.
Is it the same behavior?
use recv instead of gets
server = TCPServer.new 53492 # Server bound to port 53492
loop do
client = server.accept
ansiString = client.recv(100).chomp
client.puts result
client.close
end
you can convert it into the thread also as:
server = TCPServer.new 53492 # Server bound to port 53492
Thread.start(server.accept) do |client|
loop do
client = server.accept
ansiString = client.recv(100).chomp
client.puts result
client.close
end
end
Related
I'm currently doing an assignment where I want my program to be able to read and update a database. The database itself runs on oracle and was provided by my university (I have my own schema I believe?)
Right now I can connect via SSH using programs such as teraterm or putty, once I log in it takes me to an interactive menu which allows me to select a few various options. One of which is shell. Once I select that I am able to use bash commands to log into the SQL section and use these:
bash$ export ORACLE_HOME=/opt/oracle/product/client/11.2.0
bash$ export TWO_TASK=SSID
bash$ $ORACLE_HOME/bin/sqlplus
to connect to the SQL database. Easy.
However, I want to be able to do that through my program and it is proving difficult for me. I am using SSH.NET and can connect via SSH seemingly well. The problem is I cannot access the SQL section. When I run the commands the first two work correctly I believe, but the last one does not. It seems to not be able to see the anything past $ORACLE_HOME. When I "echo $ORACLE_HOME /*" it even tells me that /bin is a folder:
/bin /boot /dev /etc /export /hey.php /home /lib /lib64 /local /lost+found /media /misc
/mnt /opt /proc /root /sbin /selinux /srv /stage /sys /tmp /usr /var
But instead, when I run the last line of code I get the error message:
Error = "bash: /bin/sqlplus: No such file or directory\n"
I'm not sure whether there is an easier way of accessing the SQL stuff... But I am very close using SSH.NET but I just can't see why I can't open the SQL section like I can in putty or teraterm...
Any help would be greatly appreciated, thank you for your time.
My actual C# code is this:
//Connection information
string user = "SSHusername";
string pass = "password";
string host = "address";
//Set up the SSH connection
using (var client = new SshClient(host, user, pass))
{
//Start the connection
client.Connect();
var output = client.RunCommand("export ORACLE_HOME=/opt/oracle/product/client/11.2.0");
Console.WriteLine(output.Result);
output = client.RunCommand("export TWO_TASK=SSID");
Console.WriteLine(output.Result);
output = client.RunCommand("$ORACLE_HOME/bin/sqlplus");
Console.WriteLine(output.Result);
output = client.RunCommand("username");
Console.WriteLine(output.Result);
output = client.RunCommand("password");
Console.WriteLine(output.Result);
output = client.RunCommand("SELECT * FROM users;");
Console.WriteLine(output.Result);
client.Disconnect();
Console.WriteLine(output.Result);
}
1.I suggest you use native C# package for connect Oracle. You will get wrong format of output.
I see your variable is not work. Because SQLPLUS client should be under
$ORACLE_HOME/bin/sqlplus. But your code show /bin/sqlplus. Means $ORACE_HOME not work.
You can directly change code and run directly sqlplus like /opt/oracle/product/client/11.2.0/bin/sqlplus user/pass#SSID
You can set some script on remote oracle server and get result over that or upload script from C# host to remote each time.
If you're using the SSH.NET library, using a Shell instead of separate Commands should work - something like (untested):
using (var client = new SshClient(host, user, pass)) {
client.Connect();
client.CreateCommand("export ORACLE_HOME=/opt/oracle/product/client/11.2.0").Execute();
client.CreateCommand("export TWO_TASK=SSID").Execute();
client.CreateCommand("$ORACLE_HOME/bin/sqlplus").Execute());
...
client.Disconnect();
}
Original source code found at SSH.NET example
I am sending commands to a Zebra QLn220 for it to print labels (naturally). I also have code, though, that assigns values to certain printer settings, such as:
const string quote = "\"";
string keepPrinterOn = string.Format("! U1 setvar {0}power.dtr_power_off{0} {0}off{0}", quote);
string advanceToBlackBar = string.Format("! U1 setvar {0}media.sense_mode{0} {0}bar{0}", quote);
string advanceToGap = string.Format("! U1 setvar {0}media.sense_mode{0} {0}gap{0}", quote);
PrintUtils.SendCommandToPrinter(keepPrinterOn);
if (radbtnBar.Checked)
{
PrintUtils.SendCommandToPrinter(advanceToBlackBar);
}
else if (radbtnGap.Checked)
{
PrintUtils.SendCommandToPrinter(advanceToGap);
}
This works - after running that code with radbtnBar checked, those settings are now (as seen via running "! U1 getvar "allcv"" in the Zebra Setup Utilities app):
power.dtr_power_off : off , Choices: on,off
media.sense_mode : bar , Choices: bar,gap
The problem is that after setting those values via the code above, and then attempting to print labels (after a lapse of at least 20 seconds, and have tested up to more than a minute), the first couple of attempts to print a label silently fail (there is no err msg, it is just that no printing takes place). On the third attempt, the label prints. Why would setting these vals cause the printer to temporarily "go deaf," and is there anything I can do to shake it back to wakefulness following the programmatic application of those settings so that it will print immediately?
Once the QLn220 finally regains responsiveness, it continues to print immediately on subsequent executions of the app with no delays; it's only after sending those commands ("power.dtr_power_off" and "media.sense_mode") that the printer is knocked out of its orbit for a season. A real zebra would never be as stubborn as a mule like this.
UPDATE
Banno's idea did the trick, apparently (appending crlfs ("\r\n")) to the commands to set the printer vars.
So it seems that what was happening was something like this:
Command 1 was sent to the printer to set a val (with no crlf).
Command 2 was sent to the printer to set another val (also with no crlf)
A label was then attempted to be printed; it didn't print. Seeing that it did have a crlf, though, the printer seemed to say, "Oh, you finally gave me one of the crlfs you owe me! But you're not getting off that easy - you still owe me one!"
A second attempt to print a label caused the printer to say, in effect, "Okay, then, you've paid your crlf debt; from now on, I will listen to the commands you send (as long as you terminate them with the crlf I so ravenously crave)."
UPDATE 2
Sometimes it still doesn't work (inconsistent behavior); I found that I had to "poke it" to get it to quit its somnambulism; see What Zebra QLn220 settings do I need to set (and to what value[s]) to get a setting to "stick"?
append "\r\n\" to each command
ok folks i have seen alot of questions about this but none that i can use or understand
What i am attempting to do is connect to putty from asp.net c# and then run a command to get the status
i will then use the results to draw a report every 3 seconds and display it on my web page
this is the first time a have attempted this so i am rather ignorant
private void connect_putty()
{
Process sh = new Process();
sh.StartInfo.FileName = "Putty.exe";
sh.StartInfo.UseShellExecute = false;
sh.StartInfo.CreateNoWindow = false;
sh.StartInfo.Arguments = "";
}
what i presently have which to be honest is pathetic any help will be appreciated
Thanks in advance
I would suggest using Tamir.SSH.
This will allow you to do everything from C#.
Also, I wrote some code once, it may help you.
https://github.com/daneb/Push2Linux/blob/master/Form1.cs
Sample:
SshShell ssh; // create our shell
ssh = new SshShell(aHost.host, aHost.username, aHost.password);
// Command Output
string commandoutput = string.Empty;
// Remove Terminal Emulation Characters
ssh.RemoveTerminalEmulationCharacters = true;
// Connect to the remote server
ssh.Connect();
//Specify the character that denotes the end of response
commandoutput = ssh.Expect(promptRegex);
PuTTY includes all the terminal emulation (hence the name), so assuming you mean 'connect via ssh', instead of the putty app specifically, then SSH.NET and SharpSSH are 2 good choices.
See this related question: C# send a simple SSH command
I have built an Instrumentation Cluster with the NVIDIA UI Composer Studio.
To control animations it uses the Lua Scripting Language. Now I'm really new to Lua and my question is the following:
I've got the following Code sequence in Lua which controls my Speedometer:
self.vehicleSpeedData = {} -- A lot of Values are put in here
function self.speedSim( inFrame, theController )
local timeInSec, dummy
timeInSec, dummy = getElapsedTime()
-- data based on 60fps
actualFrameNumber = math.floor(timeInSec * 60)
local theSample = ((actualFrameNumber-1) % #self.vehicleSpeedData) + 1
theController.value = self.vehicleSpeedData[theSample] *0.06
end
The array in this example is empty. So as you can see, the function reads out the Values of the Array.
But what I need is, that I can get this Data from an external Source (Such as RS232 or CAN Simulation) ... What I want to try is, if I can put Data from C# for example to that Lua Script.
It is hard do explain what I exactly want. My idea is that this Lua Script above listens and reads Data which I dynamically read in C# from my Data Source.
Thanks a lot for your help. This work is for my Bachelors Degree and I'm stuck at this point a long time and I'm nearly out of ideas.
It all kind of depends on what that Nvidia thing exposes to the user (in terms of API, and Lua base libraries).
Assuming it is available, you can use io.read to read in a datafile (say a csv) from another source, then parse it yourself into your table. If you can preprocess the file to have a valid Lua syntax (eg prepend a return {, have values separated by , , and end with a }, you could directly load the string with loadstring).
If they allow you to, you could use external libraries for interfacing with RS232, Excel, sockets, whatever.
PS: it's Lua not LUA (not an acronym, but the Portuguese noun for Moon ;))
Edit: example mkfifo
so in Linux it goes like this: make a fifo with mkfifo fff and feed it something echo ' '> fff to prevent Lua from blocking.
In Lua:
fh=io.open('fff','rb')
while true do
res = fh:read()
if res then
print(res)
end
end
Whatever cat into fff (eg cat 10 > fff) will come out in Lua. this way you can read out any available values and use them at each run of your function.
Another option is using standard input, but I'm not sure whether this composer thing lets you.
I hope your Bachelor's Degree turned out alright, what with this response being 1.5 years too late. :) Nonetheless:
As a member of the UI Composer team and a fellow Lua scripter, one technique I use often for streaming external data and events asynchronously into the runtime is to use the Lua Socket library. I have written an abstraction layer on top of it as a UIC behavior.
-- Expected message structure:
-- "<numbytes>,<optionaltag>\n<bytesofmessage>"
-- e.g. "11,simple\nHello World"
-- e.g. "40,\nThis has no tag,\nbut does have a newline"
local ok,socket = pcall(require,'socket')
if not ok then
output("Error loading socket: "..socket)
else
local output = output or print
local sscallbacks = {} -- indexed by simplesocket instance, then tag
SimpleSocket = {}
local SSMeta = {}
SSMeta.__index=SSMeta
function SimpleSocket:server(port,ip,timeout)
return self:create('server',port,ip,timeout)
end
function SimpleSocket:client(port,ip,timeout)
return self:create('client',port,ip,timeout)
end
function SimpleSocket:create(kind,port,ip,timeout)
if not port then port = 51423 end
if not ip then ip = '*' end
if not timeout then timeout = 10 end
local ss = setmetatable({
kind = kind,
ip = ip,
port = port,
timeout = timeout/1000,
queue = {}
},SSMeta)
sscallbacks[ss] = {}
return ss
end
function SSMeta:destroy()
if self.socket then self.socket:close() end
callbacks[self] = nil
end
function SSMeta:onData(callback,tag)
self:setCallback('handler',callback,tag)
end
function SSMeta:toEncode(callback,tag)
self:setCallback('encoder',callback,tag)
end
function SSMeta:toDecode(callback,tag)
self:setCallback('decoder',callback,tag)
end
function SSMeta:setCallback(type,callback,tag)
if not tag then tag = "" end
if not sscallbacks[self][tag] then sscallbacks[self][tag] = {} end
sscallbacks[self][tag][type] = callback
end
function self:onUpdate()
self:sendQueuedMessages()
self:receiveMessages()
end
function SSMeta:createSocket()
output("Creating new "..self.kind.." socket to "..self.ip..":"..self.port)
if self.kind=='server' then
self.socket = assert(socket.bind(self.ip,self.port))
self.socket:settimeout(self.timeout)
else
self.socket = assert(socket.connect(self.ip,self.port))
end
end
-- Attempts to send all messages from the queue
function self:sendQueuedMessages()
for ss,_ in pairs(sscallbacks) do
while ss.queue[1] do
if ss:sendMessage(message[1]) then
table.remove(ss.queue,1)
else
-- don't attempt any later messages, since ordering may be important
return
end
end
end
end
function self:receiveMessages()
for ss,callbacks in pairs(sscallbacks) do
if ss.kind=='client' then
if not ss.socket then ss:createSocket() end
ss.socket:settimeout(0) -- non-blocking for first byte
local char1, err = ss.socket:receive(1)
ss.socket:settimeout(ss.timeout) -- go back to blocking
if not char1 then
-- probably just timed out
else
local header, err = ss.socket:receive('*l')
if not header then
output(err)
else
header = char1..header
local comma = header:find(',')
local bytes = tonumber(header:sub(1,comma-1))
local tag = header:sub(comma+1)
local data,err = ss.socket:receive(bytes)
if not data then
output(err)
else
if callbacks[tag] and callbacks[tag].decoder then
data = callbacks[tag].decoder(data)
elseif callbacks[true] and callbacks[true].decoder then
data = callbacks[true].decoder(data)
end
if callbacks[tag] and callbacks[tag].handler then
callbacks[tag].handler(data)
elseif callbacks[true] and callbacks[true].handler then
callbacks[true].handler(data)
end
end
end
end
end
end
end
function SSMeta:send(data,tag)
return self:sendMessage(self:encodeMessage(data,tag))
end
function SSMeta:ensureSend(data,tag)
local message = self:encodeMessage(data,tag)
if not self:sendMessage(message) then
table.insert(self.queue,message)
end
end
-- Internal only; use send() or ensureSend()
function SSMeta:sendMessage(formattedMessage)
if not self.socket then self:createSocket() end
if not self.client then self.client = self.socket:accept() end
if self.client then
local lastbyte,err = self.client:send(formattedMessage)
if lastbyte then
-- TODO: verify that all bytes were sent
return true
else
output(err)
self.client:close()
self.client = nil
end
else
-- No client connected before the timeout
end
end
function SSMeta:encodeMessage(data,tag)
data = tostring(data)
local callbacks = sscallbacks[self]
if callbacks[tag] and callbacks[tag].encoder then
data = callbacks[tag].encoder(data)
elseif callbacks[true] and callbacks[true].encoder then
data = callbacks[true].encoder(data)
end
return tostring(#data)..","..(tag or "").."\n"..data
end
end
This allows multiple different systems to communicate on the same socket, with different tagged communication, and possibly different encoders/decoders to serialize/deserialize the data.
On the receiving end this is used for example like this:
local ss = require 'SimpleSocket'
local client = ss:client()
client:onData(function(d) print("Client got *: "..d) end,true)
I'm fighting here with System.Printing namespace of .net framework.
And what i always saw as a wired thing in all the tools by MS to manage my printservers is they lack Port and Driver managing functionality.
So I'm stuck here with a piece of code that works:
PrintServer _ps = new PrintServer(PServer,
PrintSystemDesiredAccess.AdministrateServer );
_ps.InstallPrintQueue(QToCreate.Name, QToCreate.Driver,new string [] {"LPT1:"}, "winprint", PrintQueueAttributes.None);
And it does create a Queue for me on remote server, using the driver i specify, but driver should be there on server already which i can live with, but i failed to find a way to create new TCP/IP port on my print server, so installing new print queues this way can be something usable. i don't see why am i allowed to only install new queues with existing ports. kinda fails me. If somebody knows how to create a port along with a queue, i'd like to see how.
gah.. and when there is no hope - do research more
short answer - "you can't add a port using system.printing"
long answer - use wmi
vb sample follows:
Set objWMIService = GetObject("winmgmts:")
Set objNewPort = objWMIService.Get _
("Win32_TCPIPPrinterPort").SpawnInstance_
' Use IP of Printer or Machine sharing printer
objNewPort.Name = "IP_192.168.1.1"
objNewPort.Protocol = 1
objNewPort.HostAddress = "192.168.1.1"
' Enter Port number you would like to use
objNewPort.PortNumber = "9999"
objNewPort.SNMPEnabled = False
objNewPort.Put_