The server is at https://github.com/EmeraldHaze/Socketd/blob/master/Serv.py ; the process is at https://github.com/EmeraldHaze/QFTSOM/blob/master/main.py
A client too test this is at http://www.kongregate.com/games/EmeraldHaze/this-is-why-we-have-maps ; port forwarding and whatnot is set up correctly.
The point is that someone connecting too the server sends something like {"IP":"123.456.789.012"}, then a process is made for him, then the IO streams of the process and the user are connected. The reality is that the process outputs something, the user sees it, the user gives some input, the server gets it (and logs it), then nothing happens. Any ideas why? The buffers should be flushed.
Uh, I solved this. It was becouse sys.stdin.readline() stops blocking when it gets a \n, but either twisted or the client strip them off, meaning it will block indefinitly despite getting input.
Related
I use python socket to send data to server, and the code like:
When I close the server, it will send the data twice, and then, it will go to the "except" code. If I set the SEND_INTERVAL too long, it will be a disaster. So, how to get the error immediately when the server is closed or downtime?
Nothing happens immediatly over the network. That's one thing.
Secondly the underlying OS will detect broken connections (and Python gets that info in the form of an exception), but usually this takes time. And that's why you still send messages even though the connection is already dead. But since OS operates on network layer (as opposed to the application layer) then there's an issue: the connection may be dead but OS may never detect this. For example this will happen when the server is dead but behind alive proxy.
Thirdly the most reliable way to know that a server is alive is when it sends something back to the client. So you should always .recv() (with timeout) after .sendall() call and the server should always .sendall() after .recv() (the request-response pattern, even when the response is a simple "I received message"). If you can't modify the server side and (in worst case) if the server doesn't send anything back to the client then there's no reliable way to know this.
That's why you need some form of framing/correctness protocol. Simple .sendall() won't do.
I am trying to readlines from the tcp server that I ran in the same script. I am able to send one command and reads its output but at the end (after reading all outputs) it looks like that program hangs in readline, I have tried almost all the solutions here and here but still it hangs.
Most of these solutions propose to check if output of readline is none or not but in my case program never returns from last read and just hangs in there.
tcp server is not in my control, or say I just have to test server script therefore I can not modify it. Also, is it possible to send commands to runing server using python without using subprocess? any better alternative?
def subprocess_cmd(command):
process=subprocess.Popen(command,stdin=subprocess.PIPE,stderr=subprocess.STDOUT,stdout=subprocess.PIPE, shell=True)
for cmd in ['python3 -u tcp_server.py 123 port1']:
subprocess_cmd(cmd)
process.stdin.write('command like print_list')
process.stdin.flush()
while True:
line=process.stdout.readline()
if line == '':
break
readline hangs because your TCP connection is still open and readline expects more data to come in. You must close the connection from server side to notify readline that there is nothing more to read. Usually it is done by closing socket on client side notifying the server that there will not be any more requests to it. When server finishes processing all your commands it closes socket too. And this is the signal for you that you have received all the data that server sent to you.
Or, alternatively, if you don't want to close the connection, you must invent delimiters which will mark end of response. So the client will stop calling readline when such delimiter is read.
A lot of resources, including the example in the official documentation at telnetlib suggest that at the end before you do a read_all(), you need to write exit after the command as:
tn.write("ls\n")
tn.write("exit\n")
Can someone please help me understand why is this needed ?
If I try doing it without the exit, the telnet connection hangs (or at least looks like it is hung) as the output of the command executed does not show on the terminal.
Also, another way of making it work, as I found in some resources was to use 'exec' to fire up the command and then you don't need the exit thing anymore.
Please help me understand this as well.
read_all() reads all the output until EOF. In other words, it waits until remote server closes connection and returns you all the data it has sent. If you have not previously notified the server with an "exit" command that you have no more commands for it, it will wait for them. And a deadlock occurs: you are holding open connection because you are waiting for server to tell you that it has sent everything it intended to say, and server waits for new orders from you and is ready to add more data to it's output.
I have a program with 2 threads. Every thread sends different commands to remote host and redirect output to file. Threads use different remote hosts. I've created a connection with pxssh and trying to send commands to remote hosts with 'sendline':
s = pxssh.pxssh()
try:
s.login (ip, user, pswd)
except:
logging.error("login: error")
return
logging.debug("login: success")
s.sendline("ls / >> tmpfile.log")
s.prompt()
I can send fixed number of commands (about 500 commands on every host) and after that 'sendline' stops working. Connection is ok, but I can't get commands on remote hosts. It looks like some resources run out... what can it be?
Reposting as an answer, since it solved the issue:
Are you reading in between each write? If the host is producing output and you're not reading it, sooner or later a buffer will fill up and it will block until there's room to write some more. Make sure that before each write, you read any data that's available in the terminal, even if you don't want to do anything with it.
If you really don't care about the output at all, you could create a thread that constantly reads in a loop, so that your main thread can skip reading altogether. If your code needs to do anything with any part of the output, though, don't do this.
This may or may not being a coding issue. It may also be an xinetd deamon issue, i do not know.
I have a python script which is triggered from a linux server running xinetd. Xinetd has been setup to only allow one instance as I only want one machine to be able to connect to the service, which is therefore also limited by IP.
Currently when the client connects to xinetd the service works correctly and the script begins sending its output to the client machine. However, when the client disconnects (i.e: due to reboot), the process is still alive on the server, and this blocks the ability for the client to connect once its finished rebooting or so on.
Q: How can i detect in python that the client has disconnected. Perhaps i can test if stdout is no longer being read from by the client (and then exit the script), or is there a much eaiser way in xinetd to have the child process be killed when the client disconnects ?
(I'm using python 2.4.3 on RHEL5 linux - solutions for 2.4 are needed, but 3.1 solutions would be useful to know also.)
Add a signal handler for SIGHUP. (x)inetd sends this upon the socket disconnecting.
Monitor the signals sent to your proccess. Maybe your script isn't responding to the SIGHUP sent by xinet, monitor the signal and let it die.
You don't seem to get a SIGHUP, but you do get a SIGPIPE, at least so long as you are attempting any IO on the connection. If the application spends long periods of time not doing any IO, then you could just start a thread reading stdin to ensure you get the SIGPIPE as soon as the disconnection occurs. This was good enough for my application but then I didn't use any pipes other than the ones xinetd gave me.
I've seen several places on the net where people talk about the SIGHUP getting sent on client disconnection, so I've written an inetd python script to test out a couple of servers (one inetd and another xinetd), so you could use that to check on the signals getting sent. It just logs what it finds to /var/log/test.log. Perhaps it will be useful.
#!/usr/bin/python
import os, signal, sys
skip = ["SIGKILL", "SIG_DFL", "SIGSTOP", "SIG_IGN", "SIGCLD", "SIGCHLD"]
name_map = {}
identifiers = [i for i in dir(signal) if i.startswith("SIG") and not i in skip]
for i in identifiers:
name_map[getattr(signal, i)] = i
def handler(num, frame):
signame = name_map[num]
os.system("echo handled %s >> /var/log/test.log" % signame)
if __name__ == "__main__":
for id, name in name_map.iteritems():
signal.signal(id, handler)
while True:
print sys.stdin.readline()
sys.stdout.flush()