I have to write a code that allows non-blocking recv (along with non-blocking accept)
The following is what I got so far:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_address = ('', int(PortEntry_Page2_Text))
sock.bind(server_address)
sock.setblocking(0)
sock.settimeout(1)
sock.listen(1)
EnterToTerminal2("Listening to port "+str(PortEntry_Page2_Text)+"..")
EnterToTerminal2("Waiting for a connection. Press STOP to cancel.")
connected = 0
while (StopButtonStatePage2 == 0 and connected == 0):
try:
connection, client_address = sock.accept()
EnterToTerminal2("Connection from "+ str(client_address)+"..")
connected = 1
except Exception as inst:
template = "An exception of type {0} occured. Arguments:\n{1!r}"
message = template.format(type(inst).__name__,inst.args)
print message
finally:
if (connected == 0):
EnterToTerminal2("No client connected..")
StopButtonStatePage2 = GetStopButtonStatePage2()
###########################################
StopButtonStatePage2 = 0
sock.setblocking(0) ##?
print "xx0 "+str(connected)+" "+str(StopButtonStatePage2)
while (connected == 1 and StopButtonStatePage2 == 0):
a = select.select([sock], [], [], 1) # steelkiwi.com/blog/working-tcp-sockets
if a[0]:##?
data = sock.recv(64) # or connection.recv ??
EnterToTerminal2("Data recv: "+str(data))
StopButtonStatePage2 = GetStopButtonStatePage2()
Until sock.recv part, it works as expected. Now, the problem is that with the select approach, it does not enter the a[0] condition at all, even though I send stuff from client. Basically what I'm trying to achieve is to make recv part non-blocking/or with timeout so that I can stop its operation with a button, whenever I want.
Any help is appreaciated. Thanks in advance.
Related
I have an industrial robot connected over TCP which recieves a string in bytes. I have successfully done some simple comms between them but I now need to add another client, where the server can send out messages to either client. I'm using selectors and as its a little abstract I'm getting confused.
This is the server code - the client is written in SPEL+ so i won't show it, but is very very simple - Print [port number] [message]
import socket
import selectors
import types
import time
import queue
sel = selectors.DefaultSelector()
# # Any data received by this queue will be sent
# send_queue = queue.Queue()
def accept_wrapper(sock):
conn, addr = sock.accept() # Should be ready to read
fd = sock.fileno()
print(f"Accepted connection from {addr}, FD# {fd}")
conn.setblocking(False)
data = types.SimpleNamespace(addr=addr, inb=b"", outb=b"")
events = selectors.EVENT_READ | selectors.EVENT_WRITE
sel.register(conn, events, data=data)
def service_connection(key, mask, pending_messages):
sock = key.fileobj
data = key.data
print("Key.fd~~~~~~")
print(key.fd)
print("Key.fileobj.fileno()~~~~~~")
print(key.fileobj.fileno())
if mask & selectors.EVENT_READ:
recv_data = sock.recv(1024) # Should be ready to read
if recv_data:
data.outb += recv_data
else:
print(f"Closing connection to {data.addr}")
sel.unregister(sock)
sock.close()
if mask & selectors.EVENT_WRITE:
if len(pending_messages) > 0 and pending_messages[0][0] == key.fd:
print(pending_messages[0][0])
data.outb = pending_messages[0][1]
pending_messages.pop(0)
print(pending_messages)
if data.outb:
print(f"Echoing {data.outb!r} to {data.addr}")
sent = sock.send(data.outb) # Should be ready to write
data.outb = data.outb[sent:]
time.sleep(1)
def main(host, port):
#host, port = sys.argv[1], int(sys.argv[2])
lsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
lsock.bind((host, port))
lsock.listen()
print(f"Listening on {(host, port)}")
lsock.setblocking(False)
sel.register(lsock, selectors.EVENT_READ, data=None)
pending_messages = []
try:
while True:
events = sel.select(timeout=None)
for key, mask in events:
if key.data is None:
fd, addr = accept_wrapper(key.fileobj)
else:
pending_messages = [(fd, b"helloWorld\r")]
service_connection(key, mask, pending_messages)
except KeyboardInterrupt:
print("Caught keyboard interrupt, exiting")
finally:
sel.close()
if __name__ == '__main__':
main("",2000)
I thought fd was the interger assigned to the connection within the selector, Also (using many print statements) im not sure how the selector knows that there is data to write.
The code might be familiar as its from RealPython, but like most tutorials im finding they all stop at the server being able to accept a message from other code to then send to a client.
At the moment, I cannot get multi socket server to accept a message to then send it to the client. The client and server do communicate but this is just a basic echo.
this is for server authentication for my application.
(im working on login function so dont mind about it)
what i wanna do is to make server receive heartbeat from client
and close client socket if its doesnt respond in a few min
also i want to detect number of connections per user.
for receiving heartbeat, i can make the client send heartbeat constantly but
how do you make the server decect it? i know time measurement is needed but
if i put time.perf_counter() right before 'client_socket.recv(1024)' the counter function wont be executed because its waiting on receiving. so how would i solve this?
and im also trying to make it detect number of connections per user. (5 maximum connections per user) for detection, i give username + 1 when a user is connected and give -1 when the user disconnects but im not sure if the method im doing is correct or a good way to do so.
i'd be appreciated if you could help me out
------------------------server----------------------------
import socket
from _thread import *
import sys
import time
username = ['test123', 'hongengi']
userconnect= 0
def threaded(client_socket, addr):
print('Connected by :', addr[0], ':', addr[1])
while True:
try:
data = client_socket.recv(1024)
print (data.decode())
print('Received from ' + addr[0],':',addr[1] , data.decode())
if data.decode() == ".": # heartbeat
heartbeat = time.perf_counter()
print ("heartbeat")
if data.decode() == "test123":
print ("login success")
userconnect == userconnect + 1
if not data:
print ("no data / disconnect ")
print('Disconnected by ' + addr[0],':',addr[1])
userconnect == userconnect - 1
break
client_socket.send(data)
except (ConnectionResetError, socket.error) as e:
print ("error occurs")
print('Disconnected by ' + addr[0],':',addr[1])
userconnect == userconnect - 1
break
client_socket.close()
HOST = '127.0.0.1'
PORT = 5000
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server_socket.bind((HOST, PORT))
server_socket.listen()
print('server start')
while True:
print('wait')
client_socket, addr = server_socket.accept()
start_new_thread(threaded, (client_socket, addr))
server_socket.close()
------------------------client----------------------------
import socket
SERVER_IP = 'localhost'
SERVER_PORT = 5000
SIZE = 100
SERVER_ADDR = (SERVER_IP, SERVER_PORT)
heartbeat = "."
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.connect(SERVER_ADDR)
#username = "test123"
#userpass = "123123"
while True:
client_socket.send(heartbeat.encode())
msg = client_socket.recv(SIZE)
print (msg.decode())
One end of a socket is never "notified" when the other socket closes. There is no direct connection, so the only way to tell this is to time out. You can use socket.timeout to establish a timeout time. Your recv will then return with 0 bytes, and that's an indication that your timeout expired.
How to set timeout on python's socket recv method?
I am developing a python socket server. The client send each message to start with a STX (\x02) and end with ETX (\x03). My code can receive message successfully but I can't implement receiving full string using STX and ETX condition. Need help in resolving this issue. Below I have sharing my code for better understanding.
import socket
import time
# Start New RnD
# Global Veriable
enq = chr(5)
ack = chr(6)
stx = chr(2)
etx = chr(3)
# Connect to the server with `telnet $HOSTNAME 5000`.
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.setblocking(False)
server.bind(('0.0.0.0', 5000))
server.listen(1)
connections = []
while True:
try:
connection, address = server.accept()
connection.setblocking(False)
connections.append(connection)
except BlockingIOError:
pass
# Incoming Data Processing
for connection in connections:
try:
full_message = ''
data = ""
while True:
try:
received = connection.recv(1)
if received == enq.encode('utf-8'):
print("Received <ENQ>, Sending <ACK>")
connection.sendall(ack.encode('utf-8'))
if not received:
raise RuntimeError("unexpected end-of-message", data)
data += received.decode('utf-8')
#print("Received: {!r}".format(data))
if "\x03" in received.decode("utf-8") :
break
except BlockingIOError:
pass
print("Full Received: {!r}".format(data))
print("Data Received, Sending <ACK>")
connection.sendall(ack.encode('utf-8'))
except BlockingIOError:
continue
I have a server and I need it to receive multiple connections and messages.
The server receives new connections without problems but it doesn't get multiple messages from one connection.
import socket
import select
HEADER_LENGTH = 1024
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
try:
server_socket.bind((HOST, PORT))
except socket.error as e:
print(str(e))
print("Server is connected")
server_socket.listen(5)
sockets_list = [server_socket]
clients = {}
print("Server is listening")
def receive_message(conn):
try:
data = conn.recv(HEADER_LENGTH)
if not len(data):
return False
strdata = data.decode('utf-8')
print(strdata)
return strdata
except Exception as e:
print(e)
return False
def handle_client():
conn, addr = server_socket.accept()
print(f"Accepted new connection from {addr[0]}:{addr[1]}")
sockets_list.append(conn)
while True:
read_sockets, _, exception_sockets = select.select(sockets_list, [], [], 0)
for i in read_sockets:
if i == server_socket:
handle_client()
else:
print("received message")
message = receive_message(i)
if message is False:
sockets_list.remove(i)
try:
del clients[i]
except KeyError:
pass
continue
if message is not None:
clients[i] = message
if message is not None:
for client_socket in clients:
if client_socket != i:
client_socket.send(str.encode(message))
print("sent to all players")
What happens it that after receiving the first message, the server stops receiving messages from that connection.
And of course there is a lot more code but I showed you the relevant code.
I'll be very happy if someone helps me with that, I've surfed the web so much but haven't seen a solution for my problem.
updates:
I've tried to put socket.close() on my client side(written in Java) and then server gets maximum 2 messages and the problems with it are:
1. The server gets maximum 2 messages.
2. the connection changes(I need that the connection will stay static if possible)
try this code block
#-*- coding:utf-8 -*-
import socket
import sys
#get machine ip address
server_ip = socket.gethostbyname(socket.gethostname())
#create socket object
s = socket.socket()
#define port number
port = 6666
#bind ip and port to server
s.bind((server_ip,port))
#now waiting for clinet to connect
s.listen(5)
print("Enter this ip to connect your clinet")
print(server_ip)
clients = []
flag = True
recv_data = ""
if not clients:
c, addr = s.accept()
print("this is c ",c," this is Addr ",addr)
clients.append(c)
recv_data = c.recv(1024)
print(recv_data.decode("utf-8"))
if flag == True:
while recv_data.decode("utf-8") != "EX":
recv_data = c.recv(1024)
recv_data.decode("utf-8")
if recv_data.decode("utf-8") == "EX":
s.close()
print("check false")
break
s.close()
I am writing a script for handling HTTP request through socket programming. My Python Script just reads each HTTP response, search for few keywords and increment the counters.
Only starting the script takes CPU upto 90-99% when there is no incoming messages. How should i handle this?
HOST = ''
SOCKET_LIST = []
RECV_BUFFER = 40966
PORT=int(sys.argv[1])
serviceInitiatedEvent=0
deliveredEvent=0
EstablishedEvent=0
ConnectionClearedEvent=0
def chat_server():
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server_socket.bind((HOST, PORT))
server_socket.listen(10)
SOCKET_LIST.append(server_socket)
print "Chat server started on port " + str(PORT)
try:
while 1:
ready_to_read,ready_to_write,in_error = select.select(SOCKET_LIST,[],[],0)
for sock in ready_to_read:
if sock == server_socket:
sockfd, addr = server_socket.accept()
SOCKET_LIST.append(sockfd)
else:
try:
data = sock.recv(RECV_BUFFER)
if data:
if re.search('serviceInitiatedEvent></SOAP-ENV',data):
global serviceInitiatedEvent
serviceInitiatedEvent+=1
if re.search('deliveredEvent></SOAP-ENV',data):
global deliveredEvent
deliveredEvent+=1
else:
if sock in SOCKET_LIST:
SOCKET_LIST.remove(sock)
except:
broadcast(server_socket, sock, "Client (%s, %s) is offline\n" % addr)
continue
except KeyboardInterrupt:
print "service Initiated Event:%s" % (serviceInitiatedEvent)
print "delivered Event: %s" % (deliveredEvent)
server_socket.close()
if __name__ == "__main__":
sys.exit(chat_server())
If you have code with while 1 loop utilizing 100%, that's probably the culprit. It's called busy waiting.
select function has timeout parameter that specifies how long it should wait for events. In your code, you set it to 0, so that when there is no data available in sockets, control returns immediately, causing busy waiting loop.
Specify some larger timeout, based on your needs, so that your code won't spin when there's nothing to do:
ready_to_read,ready_to_write,in_error = select.select(SOCKET_LIST,[],[], 1)
# ^^^ here