I am working on socket programming in python and I want to detect client socket disconnection on server side.
Client:
socket.connect(host, port)
try:
""" send something to server and get response from the server"""
except KeyboardInterrupt:
socket.shutdown(socket.SHUT_RDWR)
socket.close()
Server:
conn, address = socket.accept()
try:
conn.send(message)
except:
print "-1"
But when I first run this code, I close the client by keyboard interrupt and the server won't print -1 in the screen. When I try it again, the server will catch the exception and print -1.
I wonder if there is something wrong with my code. Why the server won't detect the disconnection at the first time?
Thanks.
Related
hi i make model server client which works fine and i also create separate GUI which need to two input server IP and port it only check whether server is up or not. But when i run server and then run my GUI and enter server IP and port it display connected on GUI but on server side it throw this error. The Server Client working fine but integration of GUI with server throw below error on server side.
conn.send('Hi'.encode()) # send only takes string BrokenPipeError: [Errno 32] Broken pip
This is server Code:
from socket import *
# Importing all from thread
import threading
# Defining server address and port
host = 'localhost'
port = 52000
data = " "
# Creating socket object
sock = socket()
# Binding socket to a address. bind() takes tuple of host and port.
sock.bind((host, port))
# Listening at the address
sock.listen(5) # 5 denotes the number of clients can queue
def clientthread(conn):
# infinite loop so that function do not terminate and thread do not end.
while True:
# Sending message to connected client
conn.send('Hi'.encode('utf-8')) # send only takes string
data =conn.recv(1024)
print (data.decode())
while True:
# Accepting incoming connections
conn, addr = sock.accept()
# Creating new thread. Calling clientthread function for this function and passing conn as argument.
thread = threading.Thread(target=clientthread, args=(conn,))
thread.start()
conn.close()
sock.close()
This is part of Gui Code which cause problem:
def isOpen(self, ip, port):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
s.connect((ip, int(port)))
data=s.recv(1024)
if data== b'Hi':
print("connected")
return True
except:
print("not connected")
return False
def check_password(self):
self.isOpen('localhost', 52000)
Your problem is simple.
Your client connects to the server
The server is creating a new thread with an infinite loop
The server sends a simple message
The client receives the message
The client closes the connection by default (!!!), since you returned from its method (no more references)
The server tries to receive a message, then proceeds (Error lies here)
Since the connection has been closed by the client, the server cannot send nor receive the next message inside the loop, since it is infinite. That is the cause of the error! Also there is no error handling in case of closing the connection, nor a protocol for closing on each side.
If you need a function that checks whether the server is online or not, you should create a function, (but I'm sure a simple connect is enough), that works like a ping. Example:
Client function:
def isOpen(self, ip, port):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
s.connect((str(ip), int(port)))
s.send("ping".encode('utf-8'))
return s.recv(1024).decode('utf-8') == "pong" # return whether the response match or not
except:
return False # cant connect
Server function:
def clientthread(conn):
while True:
msg = conn.recv(1024).decode('utf-8') #receiving a message
if msg == "ping":
conn.send("pong".encode('utf-8')) # sending the response
conn.close() # closing the connection on both sides
break # since we only need to check whether the server is online, we break
From your previous questions I can tell you have some problems understanding how TCP socket communication works. Please take a moment and read a few articles about how to communicate through sockets. If you don't need live communications (continous data stream, like a video, game server, etc), only login forms for example, please stick with well-known protocols, like HTTP. Creating your own reliable protocol might be a little complicated if you just got into socket programming.
You could use flask for an HTTP back-end.
I'm a beginner in Python. So I wanted to make if a server shuts down, disconnects, the client just keeps connecting until the server is opened again. I get this error:
File "C:\Users\Laurynas\Desktop\project\client.py", line 24, in reconnect server1.connect((HOST, PORT)) OSError: [WinError 10056] A connect request was made on an already connected socket
Current client.py code:
import socket
import time
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
HOST = socket.gethostbyname(socket.gethostname())
PORT = 8888
# Check at the first try
def connect():
try:
server.connect((HOST, PORT))
messages()
except ConnectionRefusedError:
print("reconnecting, please wait...")
time.sleep(0.1)
connect()
# Check at the second, third, etc.
def reconnect():
try:
server1.connect((HOST, PORT))
messages()
except ConnectionRefusedError:
print("reconnecting, please wait...")
time.sleep(0.1)
reconnect()
def messages():
while True:
try:
command = server.recv(1024).decode()
print(command)
except:
reconnect()
pass
connect()
With the exception of listening sockets that are used for many accepts, data sockets cannot be reconnected and reused. On the client side a new socket needs to be created for the new connection and on the server side a new accept needs to be made. The old sockets should also be closed to get them out of the kernel.
This poses a difficulty because a server won't automatically know which client is reconnecting and which higher level activity should be restarted. This has to be baked into the protocol you implement on top of the connection. In HTTP for instance, each GET/PUT/POST reidentifies itself so that the web server knows how to do that, perhaps using a cookie based session id.
Bottom line, you can't keep on calling server.connect to start it up again.
In trying to familiarize myself with the socket library, I have a simple server and client setup. Basically I've stumbled through and am able to set up connection and get the server and client to talk to each other. To make it more interactive, I have client.py able to send text through the command line. Everything appears to be working properly (with the exception of the server side tearing down connection properly if client input is blank), if I type a message from the client side, it spits it right back out to me. In this example, I have it set up for the server side to print the text as well. What I noticed was, that the server side doesn't alway 'register' what it being sent from the client. I am trying to figure out why this is the case. For being a test, it doesn't really affect anything, I just can't figure out what is taking place behind the scenes.
EDIT:
Actually, after playing around with it for a bit, it appears every other message is being printed out to the server console. I've still yet to figure out why this is the case
Server side:
#server.py
import socket
ss = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
ss.bind(('127.0.0.1',5000))
ss.listen(5)
while True:
conn, addr = ss.accept()
with conn:
print ('Connected by', addr)
while True:
data = conn.recv(4096)
print (data)
if not data:
print ("nothing received from client")
ss.close()
break
Client side:
#client.py
import socket
server = 'localhost'
port = 5000
s = socket. socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('127.0.0.1', 5000))
s.send(bytes(b'Client has connected'))
while True:
msg = input()
s.send(bytes(input(msg),'utf-8'))
if not msg:
print ("Server should tear down connection...")
# s.close()
break
In sockets you there are no methods __exit__ implemented, so you can't use the with conn:
you need to remove this part of code.
I am writing a simple client/server socket program where clients connect with server and communicate and then they send exit msg to server and then server closes the connection. The code looks like below.
server.py
import socket
import sys
from threading import Thread
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# This is to prevent the socket going into TIME_WAIT status and OSError
# "Address already in use"
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
except socket.error as e:
print('Error occured while creating the socket {}'.format(e))
server_address = ('localhost', 50000)
sock.bind(server_address)
print('**** Server started on {}:{} ****'.format(*server_address))
sock.listen(5)
def client_thread(conn_sock, client_add):
while True:
client_msg = conn_sock.recv(1024).decode()
if client_msg.lower() != 'exit':
print('[{0}:{1}] {2}'.format(*client_add, client_msg))
serv_reply = 'Okay ' + client_msg.upper()
conn_sock.send(bytes(serv_reply, 'utf-8'))
else:
conn_sock.close()
print('{} exitted !!'.format(client_add[0]))
sys.exit()
try:
# Keep the server until there are incominmg connections
while True:
# Wait for the connctions to accept
conn_sock, client_add = sock.accept()
print('Recieved connection from {}:{}'.format(*client_add))
conn_sock.send(
bytes('***** Welcome to {} *****'.format(server_address[0]), 'utf-8'))
Thread(target=client_thread, args=(
conn_sock, client_add), daemon=True).start()
except Exception as e:
print('Some error occured \n {}'.format(e))
except KeyboardInterrupt as e:
print('Program execution cancelled by user')
conn_sock.send(b'exit')
sys.exit(0)
finally:
sock.close()
client.py
import socket
import sys
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_address = ('localhost', 50000)
print('Connecting to {} on {}'.format(*server_address))
sock.connect(server_address)
def exiting(host=''):
print('{} exitted !!'.format(host))
sys.exit()
while True:
serv_msg = sock.recv(1024).decode()
if serv_msg.lower() != 'exit':
print('{1}: {0}'.format(serv_msg, server_address[0]))
client_reply = input('You: ')
sock.send(bytes(client_reply, 'utf-8'))
if client_reply.lower() == 'exit':
exiting()
else:
exiting('Server')
What I want is in case server exits either through ctrl-c or any other way I want all client sockets to be closed and send msg to clients upon which they should close their socket as well.
I am doing below in except section but for some reason the msg sent by server is not being received by the client.
except KeyboardInterrupt as e:
print('Program execution cancelled by user')
conn_sock.send(b'exit')
sys.exit(0)
Surprisingly if I send the 'exit' msg from client_thread as srvr_reply, the client accepts the msg and exit the client socket at its end just fine. So I am not sure as to why the server is not able to send the same message in except section of the code as mentioned above.
I'm sorry to say that abnormal termination of TCP/IP connections is undetectable unless you try to send data through the connection.
This is known as a "Half Open" socket and it's also mention in the Python documentation.
Usually, when a server process crashes, the OS will close TCP/IP sockets, signaling the client about the closure.
When a client receives the signal, the server's termination can be detected while polling. The polling mechanism (i.e. poll / epoll / kqueue) will test for the HUP (hung up) event.
This is why "Half Open" sockets don't happen in development unless the issue is forced. When both the client and the server run on the same machine, the OS will send the signal about the closure.
But if the server computer crashes, or connectivity is lost (i.e. mobile devices), no such signal is sent and the client never knows.
The only way to detect an abnormal termination is a failed write attempt read will not detect the issue (it will act as if no data was received).
This is why they invented the ping concept and this is why HTTP/1.1 servers and clients (that don't support pings) use timeouts to assume termination.
There's a good blog post about Half Open sockets here.
EDIT (clarifications due to comments)
How to handle the situation:
I would recommend the following:
Add an explicit Ping message (or an Empty/NULL message) to your protocol (the messages understood by both the clients and the server).
Monitor the socket for inactivity by recording each send or recv operation.
Add timeout monitoring to your code. This means that you will need to implement polling, such as select (or poll or the OS specific epoll/kqueue), instead of blocking on recv.
When connection timeout is reached, send the Ping / empty message.
For an easy solution, reset the timeout after sending the Ping.
The next time you poll the socket, the polling mechanism should alert you about the failed connection. Alternatively, the second time you try to ping the server/client you will get an error message.
Note that the first send operation might succeed even though the connection was lost.
This is because the TCP/IP layer sends the message but the send function doesn't wait for the TCP/IP's ACK confirmation.
However, by the second time you get to the ping, the TCP/IP layer would have probably realized that no ACK is coming and registered the error in the socket (this takes time).
Why the send failed before exiting the server
The comment I left about this issue is wrong (in part).
The main reason the conn_sock.send(b'exit') failed is because conn_sock is a local variable in the client thread and isn't accessible from the global state where the SIGINT (CTRL+C) is raised.
This makes sense, as what would happen if the server has more than a single client?
However, it is true that socket.send only schedules the data to be sent, so the assumption that the data was actually sent is incorrect.
Also note that socket.send might not send the whole message if there isn't enough room in the kernel's buffer.
When I try to execute Python server socket program and client socket program (both running in same linux machine) in Linux terminal I don't get any error, server accepts connection and sends data to client successfully.
But when I execute the same programs in python IDLE I get "[Errno 111] Connection refused" error.
What is the difference in both execution?
I'm using serversock.bind(('',port#)) in server
and in client i'm using clientsock.connect(('localhost',port#))
Server.py
import socket
serversock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
host = ''
print host
port = 5800
serversock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
serversock.bind((host,port))
serversock.listen(2)
try:
while True:
csock,addr = serversock.accept()
print 'Recieved address from %s '% str(addr)
csock.send('hello')
csock.close()
except Exception,e:
print e
client.py
import socket
try:
c = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
host = 'localhost'
port = 5800
c.connect((host,port))
data = c.recv(1024)
print data
except Exception,e:
print e
finally:
c.close()
Server side you must use:
serversock.bind(('',port#)) # binds to port
serversock.listen(5) # actually listen to port and allow 5 incoming calls
conv = serversock.accept() # accept first incoming call
The connection will only be accepted after the listen call, before it, you have only bound a socket, but have not declared that you were ready to accept incoming calls, so they are refused.
With added code, another possible error cause is that you close connection (server side) immediately after sending data. That is bad: the close condition can destroy the socket before the data has actually been sent.
You should use a graceful shutdown:
server side:
csock.send('hello')
csock.shutdown(socket.SHUT_WR) # shutdown the socket
csock.read() # wait the close from peer
csock.close()
client side: you can leave the code as is in your use case you do not send anything to server, so when the client has finished reading it can safely close the socket
Anyway you should close serversock when everything is finished
try:
...
except ...:
...
finally:
serversock.close()