OCaml flush strange behaviour (exiting all threads) - sockets

I try to implement a CLI with 2 commands:
run that spawns an unix socket at /my/path/file.sock and produces output
watch that connects to the socket and forward the output to its own output
When I kill the watch command, I can't understand why the run command is also killed. They don't raise any exception nor sys signal. I noticed that the problems comes from the flush function. Once called, it acts like a exit 0. How come?
Here the sources: https://github.com/soywod/comodoro

The server has to listen for client disconnection and remove the connection from the conn list.
Something like this might work:
let client_thread conn =
let in_ch = in_channel_of_descr conn in
while true do
try input_line in_ch |> ignore
with End_of_file ->
(* Remove conn from !conn and close the conn *)
done
in
let add_conn () =
(* ... *)
Thread.create client_thread conn |> ignore;
(* ... *)
in

Related

LWT simple interaction with a subprocess

Here is a simple program that uses the Unix module to interact with a subprocess. I just launch a cat shell command, send it a string and read it back:
#load "unix.cma";; (* Needed if you are in the toplevel *)
let () =
let sin, sout, serr = Unix.open_process_full "cat" [||] in
output_string sout "test\n";
flush sout;
input_line sin |> print_string;
flush stdout;
Unix.close_process_full (sin, sout, serr) |> ignore;;
Recently I started studying the Lwt library, and I wanted to reproduce the same functionality with it. I though that the following should have exactly the same result:
#use "topfind";; (* *)
#thread;; (* Also only for the toplevel *)
#require "lwt.simple-top";; (* *)
let () =
let open Lwt in
let process = Lwt_process.open_process_full ( "cat" , [||] ) in
Lwt_io.write_line process#stdin "test\n"
>>= ( fun () -> Lwt_io.flush process#stdin )
>>= ( fun () -> Lwt_io.read process#stdout )
>>= ( fun str -> Lwt_io.print str )
>>= ( fun () -> Lwt_io.flush Lwt_io.stdout )
|> Lwt_main.run
But it doesn't work as I expect it to -- apparently it reads and then prints an empty string.
I guess I have some fundamental confusion on how Lwt should work, but I cannot figure it out. Can someone show me how one can communicate with a subprocess using Lwt?
Use Lwt_process.shell to make a proper command, in your case, the proper command is the following:
Lwt_process.shell "cat";;
- : Lwt_process.command = ("", [|"/bin/sh"; "-c"; "cat"|])
Also, I suspect, that after you will run your program in a proper way, you will be wondering, why is your program blocking. This reason is because cat process will not finish until you write an EOF to it's input channel. That's why the Lwt_io.read call will not ever finish. A solution would be to close the stdin channel.

hGetContents vs hGetLine

I have a program in Haskell that get all input from socket and print it.
main = withSocketsDo $ do
sock <- listenOn $ PortNumber 5002
netLoop sock
netLoop sock = do
(h,_,_) <- accept sock
hSetBuffering h NoBuffering
forkIO $ workLoop h
netLoop sock
workLoop :: Handle -> IO ()
workLoop h = do
str <- hGetContents h
putStr str
--do any work
But the problem is that this solution is closing a socket, but I want to write out the results of computation to the same socket.
But if I try to use hGetLine instead hGetContents I faced with some strange behaviour. My program show nothing until I press Ctrl-C, and then I see the first line of my network data sended. I suggest that this behaviour related with lasy execution, but why hGetContents works as expected and hGetLine not?
You need to use LineBuffering if you want to read line-by-line using hGetLine. I got it working with
import Network
import System.IO
import Control.Concurrent
main :: IO ()
main = withSocketsDo $ do
sock <- listenOn $ PortNumber 5002
netLoop sock
netLoop :: Socket -> IO ()
netLoop sock = do
putStrLn "Accepting socket"
(h,_,_) <- accept sock
putStrLn "Accepted socket"
hSetBuffering h LineBuffering
putStrLn "Starting workLoop"
forkIO $ workLoop h
netLoop sock
workLoop :: Handle -> IO ()
workLoop h = do
putStrLn "workLoop started"
str <- hGetLine h
putStrLn $ "Read text: " ++ str
-- do any work
And tested it using the python script
import socket
s = socket()
s.connect(('127.0.0.1', 5002))
s.send('testing\n')
s.close()
And I got the output
Accepting socket
Accepted socket
Starting workLoop
workLoop started
Accepting socket
Read text: testing
And I get the same behavior if I change it to NoBuffering and hGetContents

Python 3: Server socket not closing properly, infinite loop of blank messages received

EDIT: I solved this question myself, look at the first answer if you have a similar issue
I am new to sockets and made a client-server test modifying one example, it sends and receives data ok but when closing the server get caught in a loop receiving blank messages and I can't find out why even though I use shutdown(socket.SHUT_RDWR) to close the connection immediately according to the documentation.
I had to use two cmd of windows for each one (server and client) because when running first the server in idle and then the client I got in client_example ConnectionRefusedError: [WinError 10061] No connection could be made because the target machine actively refused it here is the code. Anyways, here it is the sequence I tried:
(in the client console):
c:\python33\python client_example.py
SEND( TYPE q or Q to Quit):Hi
SEND( TYPE q or Q to Quit):q
(in the server console):
c:\python33\python server_example3.py
TCPServer Waiting for client on port 7000
I got a connection from ('127.0.0.1', 49263)
RECEIVED: b'Hi'
RECEIVED: b''
RECEIVED: b''
RECEIVED: b''
RECEIVED: b''
RECEIVED: b''
.... <---After I did CTRL+C
Traceback (most recent call last):
File "server_example.py", line 19, in <module>
print("RECEIVED:",data)
File "c:\python33\lib\encodings\cp850.py", line 19, in encode
return codecs.charmap_encode(input,self.errors,encoding_map)[0]
KeyboardInterrupt
Here is the code of the server and client:
server_example.py:
#TCP server example
import socket
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind(("", 7000))
server_socket.listen(5)
print("TCPServer Waiting for client on port 7000")
while 1:
client_socket, address = server_socket.accept()
print("I got a connection from ", address)
while 1:
data = client_socket.recv(32)
if (data == 'q' or data == 'Q'):
client_socket.shutdown(socket.SHUT_RDWR)
client_socket.close()
break;
else:
print("RECEIVED:",data)
client_example.py:
# TCP client example
import socket
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.connect(("localhost", 7000))
while 1:
data = input( "SEND( TYPE q or Q to Quit):" )
if (data != 'Q' and data != 'q'):
my_bytes = bytearray()
for c in data:
my_bytes.append(ord(c))
client_socket.send(my_bytes)
else:
client_socket.shutdown(socket.SHUT_RDWR)
client_socket.close()
break;
Well, I feel dumb that I solved this thing after 11 minutes of posting the question when I was unable to solve it for 2 hours...
The problem was that I was comparing data with the string 'q' which was correct in python 2 but in python 3 what is being sent are bytes, b'q' <> 'q' ...
Here is the corrected code:
server_example.py
#TCP server example
import socket
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind(("", 7000))
server_socket.listen(5)
print("TCPServer Waiting for client on port 7000")
while 1:
client_socket, address = server_socket.accept()
print("I got a connection from ", address)
while 1:
data = client_socket.recv(32)
print("RECEIVED:",data)
if (data == b'q' or data == b'Q'):
## client_socket.shutdown(socket.SHUT_RDWR)
client_socket.close()
break;
break;
client_example.py
# TCP client example
import socket
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.connect(("localhost", 7000))
while 1:
data = input( "SEND( TYPE q or Q to Quit):" )
if (data != 'Q' and data != 'q'):
my_bytes = bytearray()
for c in data:
my_bytes.append(ord(c))
client_socket.send(my_bytes)
else:
my_bytes = bytearray()
my_bytes.append(ord(data))
client_socket.send(my_bytes)
## client_socket.shutdown(socket.SHUT_RDWR)
client_socket.close()
break;
You're assuming you're going to get the Q. You should also engage in the same processing when you get EOS from read, whatever form that takes in Python.
#EJP : By EOS you mean end of stream? If so you are right, this example was a very simple one to get started in which I overlooked details like these.
Anyway I found that using this check in the server it is solved:
data = input( "SEND( TYPE q or Q to Quit):" )
if (data == b''):
break;

How to continuously show os command output in erlang?

I need continuously show stdout/stderr from os command in erlang.
In ruby I can implement it with following code:
s1, s2 , s3, t = Open3.popen3('for %a in (1 2 3 4 5 6 7 8 9) do (echo message & sleep 2 ) 2>&1 ')
s2.each do |l|
puts l
end
it will show 'message\n message\n' in 'real time' - does not wait end of process.
I've tried os:cmd(..)
and
1> P5 = erlang:open_port({spawn, "ruby rtest.rb"}, [stderr_to_stdout, in, exit_s
tatus, binary,stream, {line, 255}]).
#Port<0.505>
2> receive {P5, Data} -> io:format("Data ~p~n",[Data]) end.
Data {data,{eol,<<>>}}
ok
but both of them wait end of process.
Are the any optional for continuously stdout reading in Erlang?
EDIT:
In other words I look for a popen (c/c++; proc_open(php) and etc) function in erlang
EDIT2
Code, that works on linux (tested on centos6.2). Thanks for vinod:
-module(test).
-export([run/0]).
run() ->
P5 = erlang:open_port({spawn, "sh test.sh"},
[stderr_to_stdout, in, exit_status,stream, {line, 255}]),
loop(P5).
loop(P) ->
receive{P, Data} ->
io:format("Data ~p~n",[Data]),
loop(P)
end.
Output:
10> c(test).
{ok,test}
11> test:run().
Data {data,{eol,"1"}}
Data {data,{eol,"2"}}
Data {data,{eol,"3"}}
Data {data,{eol,"4"}}
Data {data,{eol,"5"}}
Data {data,{eol,"6"}}
Data {data,{eol,"7"}}
Data {data,{eol,"8"}}
Data {data,{eol,"9"}}
Data {data,{eol,"10"}}
Data {exit_status,0}
If I understand correctly, you want to continue to execute your program in concurrent with the os command. In Erlang you can just spawn a process which does that and you can continue. For example
1> spawn(fun() ->
P5 = erlang:open_port({spawn, "ruby rtest.rb"},
[stderr_to_stdout, in, exit_status,
binary,stream, {line, 255}]),
receive {P5, Data} ->
io:format("Data ~p~n",[Data])
end
end).
<0.32.0>
2> 5+5.
10
3>
Better to write in a module so that you can understand it better.

Moai: Graphics that reacts to commands via Sockets

I need a program that can create pre-defined shapes on screen according to that commands I send to it via TCP.
I'm trying to listen to a port and so that I can use them. Before waiting of a command (via network) I have the commands required to create a square (I plan to change its attributes via network commands)
The problem is it is not creating any graphics or opening the window as it should be..
require "socket"
require "mime"
require "ltn12"
host = "localhost"
port = "8080"
server, error = socket.bind(host, port)
if not server then print("server: " .. tostring(error)) os.exit() end
screen=MOAISim.openWindow ( "test", 640, 640 )
viewport = MOAIViewport.new (screen)
viewport:setSize ( 640, 640 )
viewport:setScale ( 640, 640 )
layer = MOAILayer2D.new ()
layer:setViewport ( viewport )
MOAISim.pushRenderPass ( layer )
function fillSquare (x,y,radius,red,green,blue)
a = red/255
b = green/255
c = blue/255
MOAIGfxDevice.setPenColor ( a, b, c) -- green
MOAIGfxDevice.setPenWidth ( 2 )
MOAIDraw.fillCircle ( x, y, radius, 4 ) -- x,y,r,steps
end
function onDraw ( )
fillSquare(0,64,64, 0,0,255)
end
scriptDeck = MOAIScriptDeck.new ()
scriptDeck:setRect ( -64, -64, 64, 64 )
scriptDeck:setDrawCallback ( onDraw)
prop = MOAIProp2D.new ()
prop:setDeck ( scriptDeck )
layer:insertProp ( prop )
while 1 do
print("server: waiting for client command...")
control = server:accept()
command, error = control:receive()
print(command,error)
error = control:send("hi from Moai\n")
end
It is waiting of the command from client at control = server:accept() but it is not opening up the graphics window as it should.. Is there any command to force it to open or render
Thank you
MOAI doesn't run your scripts in a separate thread. A blocking call (server:accept) or forever loop (while true do) will block your MOAI app and it will appear to freeze while it merrily sits in your script forever.
So you have to do two things:
Use non-blocking calls. In this case, you need to set your server's timeout to 0. That makes server:accept return immediately. Check it's return value to see if you got a connection.
Put your while loop in a coroutine and yield once per iteration.
You'll need to handle the client the same way, using non-blocking calls in a coroutine loop.
function clientProc(client)
print('client connected:', client)
client:settimeout(0) -- make client socket reads non-blocking
while true do
local command, err = client:receive('*l')
if command then
print('received command:', command)
err = client:send("hi from Moai\n")
elseif err == 'closed' then
print('client disconnected:', client)
break
elseif err ~= 'timeout' then
print('error: ', err)
break
end
coroutine.yield()
end
client:close()
end
function serverProc()
print("server: waiting for client connections...")
server:settimeout(0) -- make server:accept call non-blocking
while true do
local client = server:accept()
if client then
MOAICoroutine.new():run(clientProc, client)
end
coroutine.yield()
end
end
MOAICoroutine.new():run(serverProc)
Set the timeout for the server socket, since the accept is a blocking call.
server:settimeout(1)
Thanks Mud...I found that before u replied so the following coroutine works
function threadFunc()
local action
while 1 do
stat, control = server:accept()
--print(control,stat)
while 1 do
if stat then
command, error = stat:receive()
print("Comm: ", command, error)
if command then
stat:close()
print("server: closing connection...")
break
else
break
end
--[[
error = stat:send("hi")
if error then
stat:close()
print("server: closing connection...",error)
break
end ]] --
else
break
end
end
coroutine.yield()
end
end
That was very helpful though