How can I check if the client disconnects abruptly in Python 3.6. Here is my code,
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print('Socket created')
try:
s.bind((HOST, PORT))
print('Socket binding complete')
except socket.error as socketError:
print('socket binding failed, ', socketError)
s.listen(1)
print('Socket listening for connection...')
conn, addr = s.accept()
conn.setblocking(0)
print('connected to ', addr[0])
try:
while True:
temp = conn.recv(1024)
if not temp:
break
data = int.from_bytes(temp, byteorder='big', signed=True)
print('value received,', temp)
print('converted value = ', data)
except Exception as loopException:
print("Exception occurred in loop, exiting...", loopException)
finally:
conn.close()
s.close()
This is working if the client disconnects normally, It is properly closing the connection. How can I check if the client disconnects abruptly?
You can at the beginning try to send to the client a packet and with it you can see if you are connected to the client or not
while True:
try:
string = "Are you up?"
s.send(string.encode())
except:
print("Can't seem to be connected with the client")
# here you can process the expection
# rest of the code
And in your case, you are already using non blocking socket conn.setblocking(0), so even if the client end the session and you don't receive any data temp, variable will contains nothing, and you will break from the loop (That if the client is if the client send data at every loop)
Or you can also set a timeout for response from the client
s.settimeout(30) # wait for the response of the client 30 seconds max
and in the recv line you can do:
try:
temp = conn.recv(1024)
except socket.timeout:
print('Client is not sending anything')
Related
I was trying to send some data over sockets, but I noticed that the bytes I send sometimes just get concatenated together.
Sorry if the wording is not great, but here’s some example code to reproduce this problem:
# SERVER CODE
import socket, pickle
from _thread import start_new_thread
IP = "0.0.0.0" # Address to bind to
PORT = 5555 # Arbitrary non-privileged port
DEFAULT_BYTES = 2048
total_connections_so_far = 0
def send(data, conn, pickle_data=True):
try:
if pickle_data:
data = pickle.dumps(data)
conn.sendall(data)
except Exception as e:
print("ERROR TRYING TO SEND DATA: ", e)
def threaded_client(conn, addr, user_id):
send(b"Hello there!", conn, False)
send(b"2nd message", conn, False)
send(b"Last message", conn, False)
conn.close()
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
# bind the socket to the host address and port
s.bind((IP, PORT))
print("Server started at: ", s.getsockname())
# listen for connections
s.listen()
print("Server has started. waiting for connections...")
while True:
conn, addr = s.accept()
print("[CONNECTED]: ", addr)
total_connections_so_far += 1 # increment the totoal connections
# start a thread for the new client
start_new_thread(threaded_client, (conn, addr, total_connections_so_far))
☝🏻 server.py
# CLIENT CODE
import socket, pickle
class Network:
def __init__(self):
self.client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.server = ""
self.port = 5555
self.addr = (
self.server,
self.port,
)
# function to connect to the server
def connect(self):
try:
self.client.connect(self.addr)
print("Connected!")
except Exception as e:
print("error while trying to connect:", e)
return False
# send some data to the server
def send(self, data, pickle_data=True):
try:
if pickle_data:
data = pickle.dumps(data)
self.client.sendall(data)
except Exception as e:
print("error while trying to send data:", e)
return False
# recieve some data from the server
def recv(self, buffer_size=2048):
try:
data = self.client.recv(buffer_size)
return data
except Exception as e:
print("error while recieving:", e)
client = Network()
client.connect()
data = client.recv()
print(data)
☝🏻 client.py
Try running the client code a few times and you’ll notice that sometimes, the data received is a concatenation of all 3 messages sent from the server.
So to get around this problem, I have been using time.sleep(1) after every time I send something, but this is obviously not a great idea.
I understand that this happens cuz ( correct me if I’m wrong ) I’m only sending tiny bits of data from the server, and expecting to receive 2048 bits on the client side, so the client waits for a while to try and receive the full amount of data.
But this is a pretty common problem and there must be a neat solution to it right?
I know I’m a total noob, but please help me!
I am currently working on a problem where I need to have a server handle multiple clients at the same time. I have a server.py file and a client.py file. Here is a snippet from server.py:
connections = []
addresses = []
for c in connections:
c.close()
del connections[:]
del addresses[:] #clears anything pre-existing
while True:
try:
csock, address = s.accept() #takes in connection and stores info
s.setblocking(1) #prevents timeout
connections.append(csock)
addresses.append(address)
print(f"Connection from {address} has been established!")
except:
print("Error has occurred")
When I run my server in terminal and then connect to it with a client. It behaves as I would expect, with it printing out Connection from ('192.168.1.84', 50824) has been established!.
When I open up another terminal and run client.py to make an additional connection, nothing happens. That is, until I close out of my first client process and then the server prints out
Error occurred
Connection from ('192.168.1.84', 50826) has been established!
I can kind of see what is happening here, but I'm very new to networking and I'm not super great at multithreading, so could anyone give me some insight as to what's going on and what I can do to make these processes run simultaneously as I would expect?
After s.accept() you should use threading to run code in separated thread - and this thread should continue connection with client. At the same time main thread may go back to s.accept() to wait for next client.
Minimal working code with some extra settings.
Server:
import socket
import threading
import time
# --- functions ---
def handle_client(conn, addr):
print("[thread] starting")
# recv message
message = conn.recv(1024)
message = message.decode()
print("[thread] client:", addr, 'recv:', message)
# simulate longer work
time.sleep(5)
# send answer
message = "Bye!"
message = message.encode()
conn.send(message)
print("[thread] client:", addr, 'send:', message)
conn.close()
print("[thread] ending")
# --- main ---
host = '0.0.0.0'
port = 8080
s = socket.socket()
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # solution for "[Error 89] Address already in use". Use before bind()
s.bind((host, port))
s.listen(1)
all_threads = []
try:
while True:
print("Waiting for client")
conn, addr = s.accept()
print("Client:", addr)
t = threading.Thread(target=handle_client, args=(conn, addr))
t.start()
all_threads.append(t)
except KeyboardInterrupt:
print("Stopped by Ctrl+C")
finally:
if s:
s.close()
for t in all_threads:
t.join()
Client (for test)
import socket
# --- main ---
host = '0.0.0.0'
port = 8080
s = socket.socket()
s.connect((host, port))
print("Connected to the server")
message = "Hello"
print('send:', message)
message = message.encode()
s.send(message)
message = s.recv(1024)
message = message.decode()
print('recv:', message)
I'm quite new to socket programming, and I was wondering why the client stops responding after I send 3 messages to the server. Basically I send a message twice and the server responds to the client. The third time, the client just runs infinitely and the server doesn't receive anything.
Does it have something to do with overload? How does that work, especially with socket.listen()
Here is the code for reference:
client.py
# Import socket module
import socket
# Create a socket object
s = socket.socket()
# Define the port on which you want to connect
port = 12345
# connect to the server on local computer
s.connect(('127.0.0.1', port))
while True:
msg = input("Enter your message: ")
if msg != "quit":
s.send((msg).encode())
else:
# close the connection
s.close()
# receive data from the server
new_msg = (s.recv(1024).decode())
print ("[CLIENT]: ", new_msg)
server.py
# first of all import the socket library
import socket
# next create a socket object
s = socket.socket()
print ("Socket successfully created")
# reserve a port on your computer in our
# case it is 12345 but it can be anything
port = 12345
# Next bind to the port
# we have not typed any ip in the ip field
# instead we have inputted an empty string
# this makes the server listen to requests
# coming from other computers on the network
s.bind(('', port))
print ("socket binded to %s" %(port))
# a forever loop until we interrupt it or
# an error occurs
while True:
# put the socket into listening mode
s.listen(20)
print ("socket is listening")
# Establish connection with client.
c, addr = s.accept()
print('Got connection from', addr)
msg = c.recv(1024).decode()
if msg == "quit":
# Close the connection with the client
c.close()
else:
print ("[SERVER]: Recieved data: ", msg)
print ("[SERVER]: sending", msg)
c.send((msg).encode())
You still need a better understanding on how a listening socket works:
it listens only once
it accepts only once per connection
it can read and send as many packets as required until either side closes the connection
at that point (and for a single threaded server) it is ready to accept a new connection
You server.py should become:
...
s.bind(('', port))
print ("socket binded to %s" %(port))
# put the socket into listening mode
s.listen(20)
print ("socket is listening")
# a forever loop until we interrupt it or
# an error occurs
while True:
# Establish connection with client.
c, addr = s.accept()
print('Got connection from', addr)
while True:
msg = c.recv(1024).decode()
if len(msg) == 0: # the client does not send anything but just closes its side
# Close the connection with the client
c.close()
print('Client disconnected')
break
else:
print ("[SERVER]: Recieved data: ", msg)
print ("[SERVER]: sending", msg)
c.send((msg).encode())
A small fix for the client side:
...
if msg != "quit":
s.send((msg).encode())
else:
# close the connection
s.close()
break # break out of the loop after closing connection
But that is not all: TCP is a stream protocol. You should be prepared for packets send from one side to be splitted or re-assembled before reaching other side. The only guarantee is that bytes arrive in same order that they were send, but not necessarily in same packets.
This is my Python script to receive data from client:
import time
import socket
HOST = ''
PORT = 8888
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print('Socket created')
try:
s.bind((HOST, PORT))
except socket.error as socketError:
print('socket binding failed, ', socketError)
print('Exiting...')
sys.exit(0)
print('Socket binding complete')
s.listen(1)
print('Socket listening for connection...')
conn, addr = s.accept()
print('connected to ', addr[0])
bfr = b''
try:
while True:
while True:
temp = conn.recv(1024)
print('temp is ',temp.decode('utf-8'))
print('buffer value ', bfr.decode('utf8'))
if not temp:
break
bfr += temp;
data = bfr.decode('utf-8')
bfr = b''
print('value received,', data)
if data == 'Connection-Ready to receive commands':
print('')
#other conditions
except Exception as loopException:
print("Exception occurred in loop, exiting...")
finally:
s.close()
The script hangs up after printing
connected to 192.168.4.197
and is not accepting any commands from client. if the client disconnects, all the send commands are printed.
Why is it behaving like this?
Update 1
Tried removing the inner while and added a time.sleep(.10) and the script is not hanging up but only the first command is printing as is and the rest is printing with a linebreak after the first character like, if I send 10, it will print 1 first and 0 in another line. All I want is to get the commands as it is sent from the client, every command is single word.
Perhaps try sendall to make sure the data is sent in its entirety from the client?
I'm new to python, and I'm trying to write a simple chat application, featuring a server which runs a thread that accepts from and transmits messages to connected clients, and a client which runs two threads that send messages to and accept messages from the server respectively. Here's the code
Server:
import socket
import sys
import thread
def receiveAndDeliverMessage(conn):
while True:
data = conn.recv(1040)
if not data: break
print(data)
conn.send(data)
conn.close
HOST = '' # Localhost
PORT = 8888 # Arbitrary non-privileged port
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) #Create a TCP/IP socket
print 'Socket created'
#Bind socket to local host and port
try:
sock.bind((HOST, PORT))
except socket.error as msg:
print 'Bind failed. Error Code : ' + str(msg[0]) + ' Message ' + msg[1]
sys.exit()
print 'Socket bind complete'
#Start listening on socket
sock.listen(10)
print 'Socket now listening'
# Create threads for receiving a connection from client and receiving data from client
while True:
connection, address = sock.accept() #Accept method returns a tupule containing a new connection and the address of the connected client
print 'Connected with ' + address[0] + ':' + str(address[1])
try:
thread.start_new_thread(receiveAndDeliverMessage, (connection))
except:
print ("Error: unable to start thread")
sock.close()
Client:
#Socket client example in python
import socket #for sockets
import sys #for exit
import thread
def sendMessage():
count = 0
while (count < 3):
message = raw_input('Write message to send to server: ');
count = count + 1
print 'message '+str(count)+': '+(message)
try :
#Send the whole string
sock.sendall(message)
except socket.error:
#Send failed
print 'Send failed'
sys.exit()
print 'Message sent successfully to server'
def receiveMessage():
reply = sock.recv(1024)
print reply#Print the message received from server
#create an INET, STREAMing socket
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
except socket.error:
print 'Failed to create socket'
sys.exit()
print 'Socket Created'
serverHost = 'localhost'
serverPort = 8888
try:
remote_ip = socket.gethostbyname(serverHost)
except socket.gaierror:
#could not resolve
print 'Hostname could not be resolved. Exiting'
sys.exit()
#Connect to remote server
sock.connect((remote_ip , serverPort))
print 'Socket Connected to ' + serverHost + ' on ip ' + remote_ip
try:
thread.start_new_thread(receiveMessage, ())
except:
print ("Error: unable to start receive message thread")
try:
thread.start_new_thread(sendMessage, ())
except:
print ("Error: unable to start send message thread")
sock.close()#Close socket to send eof to server
Now every time a client is opened, instead of the thread which runs receiveAndDelivermessage function running on the server, the exception gets thrown. So I get the "Error: unable to start thread". I don't understand why the exception gets thrown. Maybe I haven't yet quite grasped how threads work. Any help greatly appreciated. Also each time a client is opened, it gets terminated immediately, after the connection to server is established.
You swallow the original exception and print out a custom message so it's hard to determine what's causing the issue. So I am going to provide some tips around debugging the issue.
try:
thread.start_new_thread(receiveAndDeliverMessage, (connection))
except:
print ("Error: unable to start thread")
You are catching all types of exception in one except block which is quite bad. Even if you do so, try to find the message -
except Exception as ex:
print(ex)
Or you can also get the full traceback instead of just printing the exception:
import traceback
tb = traceback.format_ex(ex)