Python socket: Errno 9 Bad file descriptor when recv - python

My problem is like this. I would need to create a client program for quick trial that can send out some commands and listen to data(after which I would need to parse it) from the same socket. So I have created two threads(one to issue command (not shown here), the other to listen to data) to handle this after I created the sockets and connect out to the server. Server is written in other langauges.
As the same socket is to be used, I thought that the socket should be set to be unblocking
the socket after creation is send to the thread as an arguement.
I tried to run the python program. And there is a problem of OSError: [Errno 9] Bad file descriptor. I have narrowed down the problem. It got to do with the recv function.
Most of the solution down in the forum seem to point to socket closure as the main problem but i really could not see how since the socket closure was placed out of while loop.
So need somebody help to point to the problem. And here is my code (as below)
import socket
import errno
import sys
import threading
HOST = "192.168.50.35"
PORT = 2356
def listener(sock, q):
print("status thread created")
while q != True:
try:
data = sock.recv(1024)
except socket.error as socketerr:
if socketerr == errno.EAGAIN or socketerr == errno.EWOULDBLOCK:
sleep(1)
print('Data is unavailable')
continue
else:
print(socketerr)
sys.exit(1)
else:
print(f" new {data!r} recieved")
### processed data
### some processing set but not shown here
continue
sock.close()
def connect():
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
try:
s.connect((HOST, PORT))
s.setblocking(0)
s.settimeout(1)
except socket.error as socketerr:
print("Error: ", socketerr)
return s
if __name__ == '__main__':
print_machine_info()
q = False
s = connect()
print("socket created")
t1 = threading.Thread(target=status, args=(s,q))
t1.daemon = False
t1.start()

Related

Socket python doesn't send data if program is alive

I'm trying to run a client/server script, where the client sends a file to the server and waits for responses until the server sends a stop message.
The problem is: once the connection is established the client starts sending data but until I press CTRL-C the server cannot recreate the file. Only after CTRL-C print "file is fully created" and the file becomes visible, instead, before it's seems to be waiting for something. idk where the problem is. Also tried changing condition on send loop using len(), but doesn't work. Anyone know how to fix it ?
client.py :
import socket # Import socket module
# from threading import Thread
s = socket.socket() # Create a socket object
HOST = "101.xx.x.xxx" # public IP address
PORT = 4243 # Reserve a port for your service.
PDF_PATH = "exam.pdf"
s.connect((HOST, PORT))
def send():
f = open(PDF_PATH, "rb")
while data := f.read(4096):
s.send(data)
f.close()
return
def receive():
while 1:
exercise = s.recv(4096)
if exercise == "stop!":
s.close()
break
f = open(f"{exercise}.txt", "wb")
while data := f.read(4096):
f.write(data)
return
def main():
send()
receive()
if __name__ == "__main__":
main()
server.py :
import socket
from threading import Thread
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
HOST = socket.gethostname()
IP = socket.gethostbyname(HOST)
PORT = 4243
s.bind(('', PORT))
s.listen(5)
def receive_file(conn, i):
f = open(f"exam.pdf", "wb")
while received := conn.recv(4096):
f.write(received)
print("File is fully copied\n")
f.close()
def send_result(conn,i):
while 1:
nbr = str(input("which exercise? "))
if nbr == "stop!":
break
f = open(f"exercise{nbr}.txt", "rb")
conn.send(bytes(f"exercise{nbr}.txt", encoding="utf-8"))
while data := f.read(4096):
conn.send(data)
f.close()
def main():
try:
while 1:
i = 0
conn, addr = s.accept()
print("Got connection from", addr)
# c.send(b"Thank you for connecting")
t = Thread(target=receive_file, args=(conn, i))
t.start()
t.join()
t = Thread(target=send_result, args=(conn, i))
t.start()
t.join()
except KeyboardInterrupt:
print("interrupting \n")
conn.close()
s.close()
if _name_ == '_main_':
main()
conn.recv() in the server won't return '' (no more data) unless the client closes the connection or calls shutdown(SHUT_WR) to indicate sends are complete:
def send():
with open(PDF_PATH, "rb") as f:
while data := f.read(4096):
s.sendall(data)
s.shutdown(socket.SHUT_WR)
An alternative is to design a protocol that sends the length of data before the data so you know when you've received the complete transmission. This would be required if you need to send more than one thing without closing the socket or shutting down sends. You're going to need this to make the receive portion of the server work if you want to send more than one exercise file.
Refer to this answer for an example of sending multiple files over a socket.

How to know if a non-blocking socket is closed?

I'm trying to write my own TCP Non-Blocking Server to handle multiple long lasting socket connections rather than opening many threads to handle them.
I've written my over-complicated, hard to use syntax but have the issue forms when I'm trying to detect a closed socket.
In a normal threaded TCP Socket Server I would use detected a b'' from the socket.read(size) function, However this is not possible with a nonblocking socket as it will always return a BlockingIOError
I have also tried catching theese following events
except BrokenPipeError:
conn.abort()
except ConnectionResetError:
conn.abort()
except ConnectionAbortedError:
conn.abort()
except socket.error:
conn.abort()
(conn is a class that houses the client socket and address from socket.accept())
I'm unsure what to do, but here is a deeply simplified extract from my code:
def loop_listen(self):
while self.running == True:
cr, addr = self.server.accept()
crs = SocketHandler(self, cr, addr)
self.client_handler(crs)
self.connections.append(crs)
crs.events["open"]()
crs.cr.setblocking(0)
def loop_recv(self):
while self.running == True:
time.sleep(self.poll_time)
for conn in self.connections:
try:
data = conn.cr.recv(self.poll_size)
print(data)
if (data == b''):
conn.abort()
except BlockingIOError:
data = None
except BrokenPipeError:
conn.abort()
except ConnectionResetError:
conn.abort()
except ConnectionAbortedError:
conn.abort()
except socket.error:
conn.abort()
if (data != None):
conn.events["msg"](data)
(Both loops are separate threads)
And incase you wanted it, here is the conn class
class SocketHandler:
def __init__(self, server, cr, addr):
self.server = server
self.cr = cr
self.addr = addr
self.events = {"msg": emptyCallback, "close": "emptyCallback","open":emptyCallback}
self.cache = b""
def message(self, func):
self.events["msg"] = func
def close(self, func):
self.events["close"] = func
def open(self, func):
self.events["open"] = func
def send(self, data):
self.cr.send(data)
def abort(self):
self.cr.close()
self.events["close"]()
self.server.connections.remove(conn)
This works fine on Windows but on Ubuntu it does not call the conn.abort().
Any help would be greatly appreciated.
Thanks, Sam.
The official way to detect a closed connection on a non-blocking socket is exactly the same as blocking sockets. They return empty data from recv().
Example:
# Server
import socket
import time
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('localhost', 12345))
s.listen(1)
while True:
conn, addr = s.accept()
conn.setblocking(0)
print("New connection from " + str(addr) + ".")
while True:
try:
data = conn.recv(1024)
if not data:
break
print("Received:", data)
except BlockingIOError:
time.sleep(0.001)
print("Closed.")
# Client
import socket
import time
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('localhost', 12345))
for i in range(5):
time.sleep(0.3)
s.send(str(i).encode('utf-8'))
s.close()
There is one special case where this won't work, as described in the official docs, section When Sockets Die. It happens, when sockets don't shut down gracefully. There basically is no way for recv() to detect when a socket is dead without a graceful shutdown. It might be that this is what you are seeing.
There are multiple ways to resolve that. For one, create some kind of timeout that closes and discards a socket if it didn't receive a message for a sensible amount of time. Secondly, you could actively send messages. Detecting a dead socket is much easier for send() than for recv().
Further, this works on Linux. I didn't test it on Windows. The internal implementation of the sockets class is very platform dependent, so it might be a Windows bug.

Python error: [Errno 111] Connection refused

I am trying to send and receive data using TCP connection using Python. My server and client are in the same file, defined and used as follows.
In the constructor, I define the server as:
self.sock_in = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.sock_in.bind((self.host_ip, self.host_port))
self.sock_in.listen(1)
Do not worry about the host_ip and host_port variables, they are all fine.
In a function, I am trying to send data as follows:
sock_out = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # TCP Connection
sock_out.connect((self.remote_ip, self.remote_port))
sock_out.send(self.navigation_data.get_message())
sock_out.close()
And this is my main:
def main(self):
rospy.logwarn("Starting...")
while not rospy.is_shutdown():
conn = self.sock_in.accept()
try:
recv_buffer = conn.recv(BUFFERSIZE_IN)
if recv_buffer != "":
msg = recv_buffer.decode('utf-8')
msg_type = msg[:msg.find(',')]
if msg_type == self.pilot_control.MESSAGE_ID:
self.pilot_control_handler(msg, self.pilot_control_publisher)
else:
rospy.logwarn("Received an unimplemented message type '%s'", msg_type)
except socket.error as socket_error:
rospy.logerr("SocketError: %s", str(socket_error))
And the error I get is:
line 230, in send_83b_package
sock_out.connect((self.remote_ip, self.remote_port))
File "/usr/lib/python2.7/socket.py", line 224, in meth
return getattr(self._sock,name)(*args)
error: [Errno 111] Connection refused
I put some print commands to see where it collapses, and apparently it does not run the accept command. Until there I can see the print commands working, but after the accept method nothing is printed, which means it collapses there.
I suspect the problem is about synchronization. That is, the server does not start fast enough.
Any thoughts?
EDIT:
One of the suggestions was to run the server on a separate thread, which I tried as follows:
def my_tcp_server(self):
# Establish a TCP Connection
self.sock_in = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.sock_in.bind((self.host_ip, self.host_port))
self.sock_in.listen(1)
rospy.logwarn("ready")
while not rospy.is_shutdown():
rospy.logwarn("before accept")
conn, address = self.sock_in.accept()
rospy.logwarn("after accept")
try:
recv_buffer = conn.recv(BUFFERSIZE_IN)
rospy.logwarn("recv works!")
if recv_buffer != "":
msg = recv_buffer.decode('utf-8')
msg_type = msg[:msg.find(',')]
if msg_type == self.pilot_control.MESSAGE_ID:
self.pilot_control_handler(msg, self.pilot_control_publisher)
else:
rospy.logwarn("Received an unimplemented message type '%s'", msg_type)
except socket.error as socket_error:
rospy.logerr("SocketError: %s", str(socket_error))
conn.close()
def main(self):
rospy.logwarn("Starting..")
threading.Thread(target=self.my_tcp_server).start()
And in my constructor, the order of calls are as follows:
self.main()
self.sendDataFunction()
Which should be okay. However, the accept function is still not working, hence there is no connection.
As you didn't provide a complete executable code example I took your snippet and removed the class declaration aspects, added definitions for ip/port etc. Also added socket timeout. Anywayt this code works for me on Windows 7x64 with 32-bit Python 2.7.8:
import threading
import socket
is_shutdown = False
BUFFERSIZE_IN = 32768
def my_tcp_server():
# Establish a TCP Connection
sock_in = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock_in.bind((host_ip, host_port))
sock_in.settimeout(10000)
sock_in.listen(1)
print "ready"
while not is_shutdown:
print "before accept"
conn, address = sock_in.accept()
print "after accept"
try:
recv_buffer = conn.recv(BUFFERSIZE_IN)
print "recv works!"
if recv_buffer != "":
msg = recv_buffer.decode('utf-8')
print "Received",msg
except socket.error as socket_error:
print "SocketError: %s", str(socket_error)
conn.close()
print "Shutting down server"
sock_in.close()
def main():
print "Starting.."
threading.Thread(target=my_tcp_server).start()
def sendData():
sock_out = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # TCP Connection
sock_out.connect((remote_ip, remote_port))
sock_out.send("ASD")
sock_out.close()
host_ip="127.0.0.1"
remote_ip = host_ip
host_port = 8073
remote_port = host_port
main()
print "Sending"
sendData()
print "Completed"
is_shutdown = True
The output is:
Starting..
Sending
ready
before accept
Completedafter accept
recv works!
Received ASD
Shutting down server
I guess there is something in your class/constructor/something I can't see which is making your code not work.
HTH
barny

Exiting thread in a python multithreaded server

I'm trying to make a multithreaded server in python right now that sends a header line and then the html file requested but I've run into a bit of a snag. I'm pretty sure my threads aren't exiting when the function is done. My server is printing "ready to serve..." more times than it should (and encountering random errors from time to time). I heard that if a thread hits a handled exception it might not exit, but it appears not to exit even when things run smoothly without exception.
I'm pretty new to python and am used to making these in C where I can simply exit threads from within the thread but my research has told me it's not quite that simple in python. Any help on how to fix or improve the server would be amazing!
#import socket module
from socket import *
import threading
def work(connectionSocket):
try:
message = connectionSocket.recv(1024)
filename = message.split()[1]
f = open(filename[1:])
outputdata = f.read()
#Send one HTTP header line into socket
connectionSocket.send("Header Line")
#Send the content of the requested file to the client
for i in range(0, len(outputdata)):
connectionSocket.send(outputdata[i])
connectionSocket.close()
except IOError:
#Send response message for file not found
connectionSocket.send("404 File Not Found.")
connectionSocket.close()
return
def server():
threads = []
serverPort = 14009
serverSocket = socket(AF_INET, SOCK_STREAM)
#Prepare a sever socket
serverSocket.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
serverSocket.bind(('', serverPort))
serverSocket.listen(1)
while True:
#Establish the connection
print 'Ready to serve...'
connectionSocket, addr = serverSocket.accept()
t = threading.Thread(target=work, args=(connectionSocket,))
threads.append(t)
t.start()
serverSocket.close()
if __name__ == '__main__':
server()
The reason it prints out 'Ready to server' more than once is that you put print 'Ready to serve...' in the loop. If you only want it to print once, just put it outside the loop.
And to make sure that every thread exits, it's a better practice to join all the threads when the program ends. Then the code would be like this:
print('Ready to serve...')
while True:
#Establish the connection
try:
connectionSocket, addr = serverSocket.accept()
except KeyboardInterrupt:
break
t = threading.Thread(target=work, args=(connectionSocket,))
threads.append(t)
t.start()
print("Exiting")
for t in threads:
t.join(5)
serverSocket.close()

Python Server send data not working

I am currently working on a server in Python, the problem I am facing is the client could not retrieve the sent data from server.
The code of the server is:
import sys
import socket
from threading import Thread
allClients=[]
class Client(Thread):
def __init__(self,clientSocket):
Thread.__init__(self)
self.sockfd = clientSocket #socket client
self.name = ""
self.nickName = ""
def newClientConnect(self):
allClients.append(self.sockfd)
while True:
while True:
try:
rm= self.sockfd.recv(1024)
print rm
try:
self.sockfd.sendall("\n Test text to check send.")
print "Data send successfull"
break
except socket.error, e:
print "Could not send data"
break
except ValueError:
self.sockfd.send("\n Could not connect properly")
def run(self):
self.newClientConnect()
self.sockfd.close()
while True:
buff = self.sockfd.recv(1024)
if buff.strip() == 'quit':
self.sockfd.close()
break # Exit when break
else:
self.sendAll(buff)
#Main
if __name__ == "__main__":
#Server Connection to socket:
IP = '127.0.0.1'
PORT = 80
serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
serversocket.setsockopt( socket.SOL_SOCKET, socket.SO_REUSEADDR,1)
print ("Server Started")
try:
serversocket.bind(('',5000))
except ValueError,e:
print e
serversocket.listen(5)
while True:
(clientSocket, address) = serversocket.accept()
print 'New connection from ', address
ct = Client(clientSocket)
ct.start()
__all__ = ['allClients','Client']
#--
And the client connecting is:
import socket
HOST = '192.168.1.4' # The remote host
PORT = 5000 # The same port as used by the server
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
data = s.recv(1024)
s.close()
print 'Received', data#repr(data)
In need of a quick solution....
Thanks,
I tested out your code, and when I commented out
rm= self.sockfd.recv(1024)
print rm
it worked fine. Basically the server stopped there to wait for a message that never came. If it still does not work for you, there might be two problems. Either you have a firewall that blocks the connection somehow, or you have old servers running in the background from previous tries that actually wasn't killed. Check your processes if pythonw.exe or equivalent is running when it shouldn't be, and kill it.
To wait for response:
with s.makefile('rb') as f:
data = f.read() # block until the whole response is read
s.close()
There are multiple issues in your code:
nested while True without break
finally: ..close() is executed before except ValueError: ..send
multiple self.sockfd.close()
etc
Also you should probably use .sendall() instead of .send().
your server code is excepting client send something first,
rm= self.sockfd.recv(1024)
but I don't see any in your code
please try send something in your client code
s.connect((HOST, PORT))
s.send("hello")
Short solution
Add a short sleep after connect.
import time
time.sleep(3)

Categories

Resources