I’ve been using a PUSH/PULL pattern in an application and it works as expected except when I switch off abruptly the computer or remove the ethernet cable in the PULL-side.
The PUSH-side keeps working with other PULL-sockets, but maintains switched off socket as if still were alive.
I have modified TCP-parameters (interval, count...) without results.
Is it possible to avoid this connection even when the host computer is switched off or the ethernet cable removed?
EDIT:
This is a small test i've made
server.py
import zmq
import time
context = zmq.Context()
socket = context.socket(zmq.PUSH)
socket.setsockopt(zmq.RCVHWM, 1)
socket.setsockopt(zmq.SNDHWM, 1)
socket.setsockopt(zmq.LINGER, 0)
socket.setsockopt(zmq.IMMEDIATE, 1)
print(socket.sndtimeo)
socket.sndtimeo = 0
socket.setsockopt(zmq.TCP_KEEPALIVE,1)
socket.setsockopt(zmq.TCP_KEEPALIVE_CNT,1)
socket.setsockopt(zmq.TCP_KEEPALIVE_IDLE,1)
socket.setsockopt(zmq.TCP_KEEPALIVE_INTVL,1)
socket.bind('tcp://*:5555')
count= 0
while True:
print('Sending', count)
try:
socket.send(str(count).encode('utf-8'), zmq.NOBLOCK)
count+= 1
print('Ok')
except zmq.error.Again:
print('Error')
time.sleep(0.1)
client.py
import zmq
import time
import sys
#from common import time_utils
context = zmq.Context()
socket = context.socket(zmq.PULL)
server = '127.0.0.1:5555'
try:
server = sys.argv[1]
except IndexError:
pass
socket.setsockopt(zmq.TCP_KEEPALIVE,1)
socket.setsockopt(zmq.TCP_KEEPALIVE_CNT,1)
socket.setsockopt(zmq.TCP_KEEPALIVE_IDLE,1)
socket.setsockopt(zmq.TCP_KEEPALIVE_INTVL,1)
socket.setsockopt(zmq.RCVHWM, 1)
socket.connect(server)
while True:
# Wait for next request from client
message = socket.recv()
print("Received request: ", message)
Running one instance of the server and 2 clients (one in the same machine that runs the server and one in other computer). Removing the ethernet cable of the second computer results in that the server keeps sending messages to the second client for a while.
As you can see I have tested all setsockopt.
Q : Is it possible to avoid this connection even when the host Computer is switched off?
For connection-oriented transport-classes, you may .setsockopt( zmq.IMMEDIATE, 1 ) so as to avoid storing outgoing messages on the PUSH-side for a dead connection.
As an additional step, one may add another, explicit ACK/NACK signalling-flow, that may help independently and explicitly detect any such event of a dead-man not responding on the ACK/NACK-loop(s).
Try using the ZMTP ping/pong options. These should detect the connection being lost as it runs at a higher level than the TCP sockets (which can be held open after the connection is down)
ZMQ_HEARTBEAT_IVL, ZMQ_HEARTBEAT_TIMEOUT and ZMQ_HEARTBEAT_TTL
http://api.zeromq.org/4-3:zmq-setsockopt
Related
I have a question. If your socket program is already connected to a user suppose like 192.168.0.25:4545 and in the middle of communication if I run a connect((host,port)) to that ip and port it still accepts the connection.So, is it possible to make something that would connect to the server if a prior connection to that server doesn't already exist. I tried using the router assigned port cuz its unique for each connection, but its getting overly complicated if I do it that way.
Here is the Code dealing with this question
if __name__ == "__main__":
HOST, PORT = "192.168.0.25", 4545
counter_check = 1
while True:
try:
time.sleep(8)
s = Client(HOST, PORT)
s.enable_attempt_reconnect()
if counter_check == 1:
proc = multiprocessing.Process(target=s.start_code)
proc.start() #starting the thread for reverse shell
counter_check += 1
elif proc.is_alive():
proc.terminate() #forcefully close the previous thread
proc = multiprocessing.Process(target=s.start_code)
proc.start() #start a new thread
except Exception:
continue
enable_attempt_reconnect()
def enable_attempt_reconnect(self):
while True:
time.sleep(3)
try:
self.soc.connect((self.host, self.port))
break
except Exception:
continue
Esentially what I am trying to do is if the connection from the client is lost, the client is actively looking for other ways to connect to the server, if another connection comes up, its probably because the current connection one was disconnected, so the client would would proc.terminate() the inital connection and start a newer connection.
I am using CherryPy to speak to an authentication server. The script runs fine if all the inputted information is fine. But if they make an mistake typing their ID the internal HTTP error screen fires ok, but the server keeps running and nothing else in the script will run until the CherryPy engine is closed so I have to manually kill the script. Is there some code I can put in the index along the lines of
if timer >10 and connections == 0:
close cherrypy (< I have a method for this already)
Im mostly a data mangler, so not used to web servers. Googling shows lost of hits for closing CherryPy when there are too many connections but not when there have been no connections for a specified (short) time. I realise the point of a web server is usually to hang around waiting for connections, so this may be an odd case. All the same, any help welcome.
Interesting use case, you can use the CherryPy plugins infrastrcuture to do something like that, take a look at this ActivityMonitor plugin implementation, it shutdowns the server if is not handling anything and haven't seen any request in a specified amount of time (in this case 10 seconds).
Maybe you have to adjust the logic on how to shut it down or do anything else in the _verify method.
If you want to read a bit more about the publish/subscribe architecture take a look at the CherryPy Docs.
import time
import threading
import cherrypy
from cherrypy.process.plugins import Monitor
class ActivityMonitor(Monitor):
def __init__(self, bus, wait_time, monitor_time=None):
"""
bus: cherrypy.engine
wait_time: Seconds since last request that we consider to be active.
monitor_time: Seconds that we'll wait before verifying the activity.
If is not defined, wait half the `wait_time`.
"""
if monitor_time is None:
# if monitor time is not defined, then verify half
# the wait time since the last request
monitor_time = wait_time / 2
super().__init__(
bus, self._verify, monitor_time, self.__class__.__name__
)
# use a lock to make sure the thread that triggers the before_request
# and after_request does not collide with the monitor method (_verify)
self._active_request_lock = threading.Lock()
self._active_requests = 0
self._wait_time = wait_time
self._last_request_ts = time.time()
def _verify(self):
# verify that we don't have any active requests and
# shutdown the server in case we haven't seen any activity
# since self._last_request_ts + self._wait_time
with self._active_request_lock:
if (not self._active_requests and
self._last_request_ts + self._wait_time < time.time()):
self.bus.exit() # shutdown the engine
def before_request(self):
with self._active_request_lock:
self._active_requests += 1
def after_request(self):
with self._active_request_lock:
self._active_requests -= 1
# update the last time a request was served
self._last_request_ts = time.time()
class Root:
#cherrypy.expose
def index(self):
return "Hello user: current time {:.0f}".format(time.time())
def main():
# here is how to use the plugin:
ActivityMonitor(cherrypy.engine, wait_time=10, monitor_time=5).subscribe()
cherrypy.quickstart(Root())
if __name__ == '__main__':
main()
I am working on a GUI based chat program.
I am using someone else's server which has worked well for many people so I am assuming the problem is with my client's code.
When I run a single instance of the client it works perfectly, but if I run two instances of the client on the same computer the listener stops responding when the 2nd client logs in.
# server is from socket module
# chat_box is a tkinter ListBox
# both are copies of global variable
class listener_thread(threading.Thread):
def __init__(self, server, chat_box):
super(listener_thread, self).__init__()
self.server = server
self.chat_box = chat_box
def run(self):
try:
update = self.server.recv(1024)
msg = update.decode("utf-8")
if msg != "":
self.chat_box.insert(END, msg)
except Exception as e:
print(e)
I've verified that the server is putting each client on a different port. The server is receiving the messages. When 'Michael' logs in and says 'Hi' it updates in his chat_box.
Though, the clients are no longer updating their histories after 'Dave' logs in.
Yet, the server continues to show that it is receiving the messages from both clients.
#This is the server output
#Hi is Michael
#Yo is Dave
#So Michael is still connecting and transmitting after Dave connects
Michael - ('127.0.0.1', 56263) connected
Hi
Dave - ('127.0.0.1', 56264) connected
Yo
Hi
The network connection is working properly. It just locks up the list_box updating threads.
No exceptions are being thrown.
I solved my own problem.
I needed to make the chat_history_listbox as a ListBox initially, instead of None
I needed to put the receive code into a function, with a loop and an exit condition
def receive_func():
global server, chat_history_listbox
while True:
try:
update = server.recv(1024)
except OSError as e:
update = None
break
connect()
msg = update.decode("utf-8")
if msg != "":
chat_history_listbox.insert(END, msg)
I needed to make the thread call a function and make it a daemon
listener = Thread(target=receive_func, daemon=True)
listener.start()
This got it working with multiple clients
So, I have a server script that receives an image from a client script and is supposed to send an acknowledgement saying "OK". But the acknowledgement never goes through.
Server script -
import socket,sys
s = socket.socket()
print("Socket successfully created")
port =80
s.bind(('', port))
print("socket binded to %s" %(port))
s.listen(5)
print("socket is listening")
while True:
c, addr = s.accept()
print('Got connection from', addr)
file_name=s.recv(1024)
file_name=fil_ename.decode("utf-8")
with open(file_name,"wb")as f:
while True:
data=c.recv(1024)
if not data:
break
f.write(data)
c.send(bytes('Thank you ! File received.',"utf-8"))
c.close()
Client script -
import socket
s = socket.socket()
# Define the port on which you want to connect
port = 80
s.connect(('IP address of my server', port))
s.send(bytes("hand.jpeg","utf-8"))
f=open("back.jpeg","rb")
data=f.read(512)
while data:
s.send(data)
data=f.read(512)
f.close()
print(s.recv(10))
The server does not send any acknowledgement and seems to get stuck in the for loop. But if i remove the line c.send(bytes('Thank you ! File received.',"utf-8")) from the server script, the code works well. Also, if I remove the receive part from server side and just send the acknowledgent part , i.e c.send(bytes('Thank you ! File received.',"utf-8")) , the client receives the message. But If a combination of receive(the image file) and the acknowledgement is made in the server side as shown in the code, the server side fails to respond.
Important thing to note is that on KeyBoardInterrupt-ing the above program, it shows that the server side script is hanged/stuck in the data=c.recv(1024) line. But the same problem vanishes if the acknowledgement line is removed.
Note:- The client side script is running on my local machine and the server side script is running on a Google Cloud VM Instance.
Please help.
Thank you.
Hmm... I don't think I completely believe your description of the behavior. But I do know what's wrong. It's entirely reasonable that your server is sitting in the receive loop, because the client hasn't signaled EOF to the connection. Under what circumstances do you believe that this will actually break?
if not data:
break
The answer is that the client needs to either close the socket, or use shutdown(SHUT_WR) to indicate that it will not be sending any more data. So to do what you want, on the client side:
...
f.close()
s.shutdown(socket.SHUT_WR)
...
Now the next time the server calls recv, it will get an empty string returned and the break above will be taken.
This leaves the connection open in one direction but not the other. So the client will not be able to send any more data. However, the server will still be able to send to the client until it closes the socket (or uses shutdown itself).
There is another more subtle problem. You are assuming that your first server-side recv will receive only and exactly the bytes containing your file name. 99.9% of the time that will work. But it's possible that the data from your next client-side send will also be available when the server calls recv for the first time. That will likely give you a bogus file name (though not necessarily an illegal one) and will certainly mean that your file is not transferred faithfully.
You should never assume that the data provided by a single send by one peer will be received by a corresponding single recv on the other side. The data received could be more or less and it's up to the application to frame the data to ensure that it receives exactly the intended amount.
Here
while True:
data=c.recv(1024)
if not data:
break
f.write(data)
it loops back to waiting for a message after it has received one because you don't break the while loop after receiving data. the if not data: doesn't do anything since recv() stops and waits until it gets a message, and thus data is never nothing. You should either break the loop after receiving a message by adding a break after f.write(data), or send the OK in the loop.
using python 3, I'm trying to send a file from a server to a client as soon as the client connects to the server, problem is that the client do only continue from recv when I close it (when the connection is closed)
I'm running the client in blender game engine, the client is running until it gets to recv, then it just stops, until i exit the game engine, then I can see that the console is receiving the bytes expected.
from other threads I have read that this might be bco the recv never gets an end, that's why I added "\n\r" to the end of my bytearray that the server is sending. but still, the client just stops at recv until I exit the application.
in the code below I'm only sending the first 6 bytes, these are to tell the client the size of the file. after this i intend to send data of the file on the same connection.
what am I doing wrong here?
client:
import socket
import threading
def TcpConnection():
TCPsocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
TCPsocket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
server_address = ('localhost', 1338)
TCPsocket.connect(server_address)
print("TCP Socket open!, starting thread!")
ServerResponse = threading.Thread(target=TcpReciveMessageThread,args=(TCPsocket,))
ServerResponse.daemon = True
ServerResponse.start()
def TcpReciveMessageThread(Sock):
print("Tcp thread running!")
size = Sock.recv(6)#Sock.MSG_WAITALL
print("Recived data", size)
Sock.close()
Server:
import threading
import socket
import os
def StartTcpSocket():
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind(('localhost', 1338))
server_socket.listen(10)
while 1:
connection, client_address = server_socket.accept()
Response = threading.Thread(target=StartTcpClientThread,args=(connection,))
Response.daemon = True # thread dies when main thread (only non-daemon thread) exits.
Response.start()
def StartTcpClientThread(socket):
print("Sending data")
length = 42
l1 = ToByts(length)
socket.send(l1)
#loop that sends the file goes here
print("Data sent")
#socket.close()
def ToByts(Size):
byt_res = (Size).to_bytes(4,byteorder='big')
result = bytearray()
for r in byt_res:
result.append(r)
t = bytearray("\r\n","utf-8")
for b in t:
result.append(b)
return result
MessageListener = threading.Thread(target=StartTcpSocket)
MessageListener.daemon = True # thread dies when main thread (only non-daemon thread) exits.
MessageListener.start()
while 1:
pass
if the problem is that the client don't find a end of the stream, then how can solve this without closing the connection, as I intend to send the file on the same connection.
Update #1:
to clarify, the print in the client that say "recived" is printed first when I exit the ge (the client is closing). The loop that sends the file and recives it where left out of the question as they are not the problem. the problem still occurs without them, client freeze at recv until it is closed.
Update #2:
here are a image of what my consoles are printing when i run the server and client:
as you can see it is never printing the "Recived" print
when i exit the blender game engine, I get this output:
now, when the engine and the server script is exited/closed/finished i get the data printed. so recv is probably pausing the thread until the socket is closed, why are it doing this? and how can i get my data (and the print) before the socket is closing? This also happens if I set
ServerResponse.daemon = False
here are a .blend (on mediafire) of the client, the server running on python 3 (pypy). I'm using blender 2.78a
Update #3:
I tested and verified that the problem is the same on windows 10 and linux mint. I also made a Video showing the problem:
In the video you can see how I only receive data from the server when i exit blender ge. After some research I besinning to suspect that the problem is related to python threading not playing well with the bge.
https://www.youtube.com/watch?v=T5l9YGIoDYA
I have observed a similar phenomenon. It appears that the Python instance doesn't receive any execution cycles from Blender Game Engine (BGE) unless a controller gets invoked.
A simple solution is:
Add another Always sensor that is fired on every logic tick.
Add another Python controller that does nothing, a no-op.
Hook the sensor to the controller.
I applied this to your .blend as shown in the following screen capture.
I tested it by running your server and it seems to work OK.
Cheers, Jim