468,544 Members | 1,767 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 468,544 developers. It's quick & easy.

socket closing problem


Hi,

I have a gui (made in wxPython) that enables a user to connect to a server
and issue some commands. The problem occurs when i try to disconnect the
client. It exits but it doesn't return to the prompt. I have to push
Ctrl-C in order to have it exit completely. The GUI is closed though.

This is a piece of code from the main class that connects to the server
and starts a thread that handles the connection:
======================= snippet =======================
Create a socket and start a thread to handle the connection:
#create an INET, STREAMing socket
self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

#now connect to the CheckServer
try:
self.s.connect((host, int(data)))
except socket.error, msg:
sys.stderr.write('connect failed: ' + repr(msg) + '\n')
sys.exit(1)

self.connection = client_connection(self.s, self)
self.connection.start()
======================= snippet =======================

client_connection is the thread that handles the connection.
Next, the client_connection class

======================= snippet =======================
BUF_SIZE = 1024

class client_connection(threading.Thread):
def __init__(self,client_socket,parent):
self.client_socket = client_socket
self.parent = parent
threading.Thread.__init__(self)

def run(self):
done = 0
try:
while not done:
print "ready to receive data"
try:
data = self.client_socket.recv(BUF_SIZE)
except socket.error, msg:
print "Error receiving data"
break
if not data:
print "all data received"
break

print "receiving data"
sys.stdout.write(data)
sys.stdout.flush()
self.parent.handleCommand(data)
finally:
self.client_socket.close()
print "Closing client socket"

def message(self,msg):
print "from client_connection", msg
self.client_socket.sendall(msg+"\n")

def close(self):
#self.message("bye")
done = 1
self.client_socket.settimeout(0)
self.client_socket.close()
======================= snippet =======================

So when the user pushes the exit button, i try to call the close
function of the client_connection class:
======================= snippet =======================
def OnFileExit(self,e):
self.connection.close()
time.sleep(5)
self.Close(true) # Close the frame.
======================= snippet =======================

I thought that this would trigger the
"data=self.client_socket.recv(BUF_SIZE)"
from the client_connection class in such a way that it would produce an
exception or return empty data so i could close the thread gracefuly.
Apparently this doesn't happen.

When the server initiates the closing of the socket, then all happens fine.
How can i solve this & what am i doing wrong?

Thanks,
Benedict
Jul 18 '05 #1
4 2136
try:
data = self.client_socket.recv(BUF_SIZE)
except socket.error, msg:
print "Error receiving data"
break
if not data:
print "all data received"
break
....

I thought that this would trigger the
"data=self.client_socket.recv(BUF_SIZE)"
from the client_connection class in such a way that it would produce an
exception or return empty data so i could close the thread gracefuly.
Apparently this doesn't happen.

When the server initiates the closing of the socket, then all happens
fine.
How can i solve this & what am i doing wrong?


Well, here is what you need to know:

1. First you should call select.select on the socket. Then you will know
if there is data arrived from the server.
2. If so then you should call client_socket.recv(). Please note that if
you call recv() BEFORE any data has arrived, it will block your program.
(Sockets are defaulting to blocking sockets.)
3. Then you should examine the data received. There are two possibilities:

a.) Your 'data' is not empty -> process the data
b.) Your 'data' is empty. -> it means that the server closed the
connection.

Conclusion: when select.select tells there is more data coming but you
can only recv an empty string >>> it means that the socket has been
closed from the other site. You need to call both select.select and recv
to detect if the socket is closed or not. The same procedure works on
the server side (with the client socket) too.

Another note: you can call select.select on the server socket if you
want to know when a client wants to connect to your server.

Best,

G
Jul 18 '05 #2
On Thu, 08 Jul 2004 07:10:30 GMT, flupke <fl****@nonexistingdomain.com> wrote:
So when the user pushes the exit button, i try to call the close
function of the client_connection class:
======================= snippet =======================
def OnFileExit(self,e):
self.connection.close()
time.sleep(5)
self.Close(true) # Close the frame.
======================= snippet =======================

I thought that this would trigger the
"data=self.client_socket.recv(BUF_SIZE)"
from the client_connection class in such a way that it would produce an
exception or return empty data so i could close the thread gracefuly.
Apparently this doesn't happen.


sockets are full-duplex, which means that there are two streams of data.
One stream runs from your send-side to the receive-side of the server,
and one stream runs in the other direction (from the send-side of the
server to the receive-side of your connection).
Other than the fact that both streams are connected to the same
processes, both streams are independant.

That means that actions you perform at the send-side are independant of
actions you perform at the receive-side.
Therefore, you cannot expect for the close() to have any effect at the
recv().

(unless the server co-operates of course, and closes its send-side as
reaction to you closing its receive-side. Even then, you still have to
be prepared to receive arbitrary amounts of data before you get EOF,
because you don't know how much data is in the connection between the
server and you).
So the answer to your problem is not to rely on the server reacting to
your close(), and organize you application such that you close both the
send-side and the receive-side (instead of waiting for the EOF).
Albert
--
Unlike popular belief, the .doc format is not an open publically available format.
Jul 18 '05 #3
Thanks Gandalf & Albert,

both your sollutions seem to be working.
This is what i've tried but as to what is the most natural sollution,
i'm not sure.

1) using select.select on the socket (Gandalf)

========================= snippet =======================
client _connection class:
...
in_socket = [self.client_socket]
try:
while not done:
print "ready to receive data"
try:
i, o, e = select.select(in_socket,[],[])
for x_socket in i:
data = x_socket.recv(BUF_SIZE)
except socket.error, msg:
print "Error receiving data"
break
...

main class:
...
def OnFileExit(self,e):
#self.s.close()
#wait until the thread dies
if ( self.s != None ):
self.s.settimeout(0)
self.connection.close()
#self.s.close()
time.sleep(5)
self.Close(true) # Close the frame.
...
========================= snippet =======================

Now, the exit closes the socket which triggers an exception, as
expected. This also triggers a "clean" closing of the connection on the
server.

2) Albert said: "herefore, you cannot expect for the close() to have any
effect at the recv()."
So in order to close, i made sure that part of closing of the client is
to first send a "bye" command to the server. This makes the server close
the socket which then also triggers the exception.

========================= snippet =======================
client _connection class:
...
try:
while not done:
print "ready to receive data"
try:
data = self.client_socket.recv(BUF_SIZE)
except socket.error, msg:
print "Error receiving data"
break
...
def close(self):
print "from client_connection close() "
self.message("bye")
done = 1
self.client_socket.settimeout(0)
self.client_socket.close()
========================= snippet =======================

Now, there are 2 ways to solve my problem but i'm not sure which one is
the nicest when you would aim for the most "logical" sollution.
Any thoughts?

Thanks,
Benedict
Jul 18 '05 #4
flupke wrote:
Thanks Gandalf & Albert,

both your sollutions seem to be working.
This is what i've tried but as to what is the most natural sollution,
i'm not sure.

1) using select.select on the socket (Gandalf)

========================= snippet =======================
client _connection class:
...
in_socket = [self.client_socket]
try:
while not done:
print "ready to receive data"
try:
i, o, e = select.select(in_socket,[],[])
for x_socket in i:
data = x_socket.recv(BUF_SIZE)
except socket.error, msg:
print "Error receiving data"
break
...

main class:
...
def OnFileExit(self,e):
#self.s.close()
#wait until the thread dies
if ( self.s != None ):
self.s.settimeout(0)
self.connection.close()
#self.s.close()
time.sleep(5)
self.Close(true) # Close the frame.
...
========================= snippet =======================

Now, the exit closes the socket which triggers an exception, as
expected. This also triggers a "clean" closing of the connection on the
server.

2) Albert said: "herefore, you cannot expect for the close() to have any
effect at the recv()."
So in order to close, i made sure that part of closing of the client is
to first send a "bye" command to the server. This makes the server close
the socket which then also triggers the exception.

========================= snippet =======================
client _connection class:
...
try:
while not done:
print "ready to receive data"
try:
data = self.client_socket.recv(BUF_SIZE)
except socket.error, msg:
print "Error receiving data"
break
...
def close(self):
print "from client_connection close() "
self.message("bye")
done = 1
self.client_socket.settimeout(0)
self.client_socket.close()
========================= snippet =======================

Now, there are 2 ways to solve my problem but i'm not sure which one is
the nicest when you would aim for the most "logical" sollution.
Any thoughts?

Thanks,
Benedict


Or i can combine the two. If the "bye" command doesn't trigger a close
(for whatever reason, for instance lag) immediately, then the select
could still handle the closing of the socket gracefully?

========================= snippet ==============================
client _connection class:
...
in_socket = [self.client_socket]
try:
while not done:
print "ready to receive data"
try:
i, o, e = select.select(in_socket,[],[])
for x_socket in i:
data = x_socket.recv(BUF_SIZE)
#data = self.client_socket.recv(BUF_SIZE)
except socket.error, msg:
print "Error receiving data"
break
...
def close(self):
print "from client_connection close() "
self.message("bye")
done = 1
self.client_socket.settimeout(0)
self.client_socket.close()
main class:
...
def OnFileExit(self,e):
#wait until the thread dies
if ( self.s != None ):
self.connection.close()
time.sleep(5)
self.Close(true) # Close the frame
...
========================= snippet ==============================

So there seems to be 3 options. 1, 2 or both?
What will it be?

Benedict
Jul 18 '05 #5

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

8 posts views Thread by simon place | last post: by
reply views Thread by Hameed Khan | last post: by
2 posts views Thread by Droopy | last post: by
2 posts views Thread by Silby | last post: by
1 post views Thread by Chris Morse | last post: by
reply views Thread by =?Utf-8?B?QWxwZXIgQUtDQVlPWg==?= | last post: by
11 posts views Thread by atlaste | last post: by
reply views Thread by NPC403 | last post: by
1 post views Thread by UniDue | last post: by
By using this site, you agree to our Privacy Policy and Terms of Use.