I'm trying to achieve interprocess communication with socket. I have this code which acts as a socket server. When a message is received, the server broadcasts all the message to the other conntected clients.
from socket import AF_INET, gethostname, socket, SOCK_STREAM
import _thread as thread
clients = []
HOST = gethostname()
PORT = 33000
BUFFER_SIZE = 1024
ADDR = (HOST, PORT)
s = socket(AF_INET, SOCK_STREAM)
s.bind(ADDR)
def accept_client():
while True:
client, _ = s.accept()
clients.append(client)
print("Client accepted.")
thread.start_new_thread(handle_client, (client, ))
def handle_client(client):
while True:
message = client.recv(BUFFER_SIZE)
print("Incoming message: {}".format(message.decode('utf-8')))
broadcast(message)
def broadcast(message):
print("Broadcasting...")
for c in clients:
print("Broadcasting to {}".format(c))
c.send(message)
if __name__ == '__main__':
s.listen()
print("Listening...")
thread.start_new_thread(accept_client, ())
try:
while True:
pass
except KeyboardInterrupt:
print("Exited.")
exit(0)
And here is a class for my client.
from socket import AF_INET, gethostname, socket, SOCK_STREAM
import _thread as thread
class SocketClient:
buffer_size = 1024
def __init__(self, host=gethostname(), port=33000):
self.host = host
self.port = port
self.buffer_size = 1024
self.s = socket(AF_INET, SOCK_STREAM)
self.s.connect((self.host, self.port))
def bind_callback(self, callback, args=()):
thread.start_new_thread(self.receive, (callback, args))
def receive(self, callback, args):
while True:
try:
msg = self.s.recv(self.buffer_size).decode('utf-8')
callback(msg, *args)
except OSError as err:
self.close()
raise err
except NameError:
raise err
def send(self, msg):
try:
self.s.send(msg.encode('utf-8'))
except:
self.close()
def close(self):
self.send('{clientClose}')
self.s.close()
In other script which I've create the object ofSocketClient, there is an infinite amount of incoming socket after the script terminates (by Ctrl+D in Python). The server script (which prints an attempt when an incoming socket is received) shows this repeatedly:
Incoming message:
Broadcasting...
Broadcasting to <socket.socket fd=4, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.1.1', 33000), raddr=('127.0.0.1', 44126)>
Broadcasting to <socket.socket fd=5, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.1.1', 33000), raddr=('127.0.0.1', 44276)>
Observe that there appears to be no incoming messages.
My assumption is that I've failed to close the socket connection properly (before exiting). How can this be achieved? Thank you in advance.
Calling client.recv(1024) will block and return 1 to 1024 bytes unless the client disconnects, in which case it will return an empty bytestring:
def handle_client(client):
while True:
message = client.recv(BUFFER_SIZE)
if not message:
# client disconnected
break
...
Related
My Python socket chat with multithreading only accepts one connection. If I try to connect a second client it doesn't work. On the client side it seems like everything is okay but if i try to send a second message from client 2 the message doesn't arrive.
import socket
import threading
class TxtSocket:
def __init__(self, host="127.0.0.1" , port=5555):
self.host = host
self.port = port
self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.s.bind((self.host, self.port))
print("Socket was created")
def server(self):
self.s.listen()
print("Server is listening")
conn, addr = self.s.accept()
print(f"{addr} is now connected.")
while True:
data = conn.recv(1024).decode("utf8")
print(data)
if not data:
break
if __name__ == "__main__":
txtsocket = TxtSocket()
for i in range(0, 26):
t = threading.Thread(target=txtsocket.server())
t.start()
# Client
import socket
def Text():
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("127.0.0.1", 5555))
print("Connected")
while True:
message = input("Deine Nachricht: ")
message = message.encode("utf8")
s.send(message)
Text()
Need couple mods to the server to handle multiple clients.
Need main loop to keep accepting new connections and forking off the processing to a thread
Create a new thread to handle client connection when socket gets a new connection.
The following server code works with multiple running clients as specified above.
# server
import socket
import threading
class TxtSocket:
def __init__(self, host="127.0.0.1", port=5555):
self.host = host
self.port = port
self.thread = 0
self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.s.bind((self.host, self.port))
print("Socket was created")
def handle(self, conn, addr):
self.thread += 1
print(f"Thread-{self.thread} {addr} is now connected")
while True:
data = conn.recv(1024)
if not data:
break
print(data.decode("utf8"))
conn.close()
def server(self):
# specify the number of unaccepted connections that the server
# will allow before refusing new connections.
self.s.listen(5)
print(f'Server listening on tcp:{self.host}:{self.port}')
while True:
conn, addr = self.s.accept()
# create new thread to handle the client connection
t = threading.Thread(target=self.handle, args=(conn, addr))
t.start()
if __name__ == "__main__":
txtsocket = TxtSocket()
txtsocket.server()
Note that Python has a SocketServer module that can make some of this easier with a TCPServer that does much of the work. See server example.
you can use thread for close other connections
import socket
from _thread import start_new_thread
server = socket...
first_connection = None
def check_con_isalive():
try:
while True:
first_connection.send(b"\0")
except Exception:
print("connnection was closed")
first_connection.close()
def thread_con(con):
global first_connection
if not first_connection:
first_connection = con
start_new_thread(check_con_isalive, ())
...
else:
print("blocking new connections")
con.close()
if __name__ == '__main__':
while True:
con, adr = server.accept()
start_new_thread(thread_con, (con, ))
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 am setting up a client/server in Python with the ability to handle multiple clients.
Server code:
import socket
import threading
class Server:
def __init__(self):
self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.server.bind(('127.0.0.1',1234 ))
print("Waiting for connection")
self.server.listen()
self.loop()
def thread_client(self, conn, addr):
print(addr, ' has connected')
while True:
data = conn.recv(1024)
conn.sendall(data)
def loop(self):
while True:
conn, addr = self.server.accept()
x = threading.Thread(target = self.thread_client, args=(conn, addr,))
x.start()
self.server.close()
s = Server()
Client code:
import socket
class Client:
def __init__(self):
self.client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.connect()
def connect(self):
try:
self.client.connect(('127.0.0.1', 1234))
except:
print("Something went wrong...")
def send(self, data):
self.client.sendall(data)
return self.client.recv(1024)
c = Client()
print(c.send(b'Hello World'))
print(c.send(b'Hello World'))
When I run py server.py in one terminal this is all I get:
And from the client terminal this is how it looks:
My question is, why am I not recieving a simple print message from the initialization of the server? What does CLOSE_WAIT and FIN_WAIT_2 mean when I run netstat?
The server thread will loop forever until the socket times out resulting in WAIT states on the created sockets as shown in netstat command. Add a check in the server thread to check when data from the client is complete.
Socket Programming HOWTO states:
When a socket.recv returns 0 bytes, it means the other side has closed
(or is in the process of closing) the connection. You will not receive any
more data on this connection.
Server update:
import socket
import threading
class Server:
def __init__(self):
self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.server.bind(('127.0.0.1', 1234))
print("Waiting for connection")
self.server.listen()
self.loop()
def loop(self):
while True:
conn, addr = self.server.accept()
x = threading.Thread(target=Server.thread_client, args=(conn, addr,))
x.start()
self.server.close()
#staticmethod
def thread_client(conn, addr):
print(addr, ' has connected')
while True:
data = conn.recv(1024)
if len(data) == 0:
break
print("recv:", data)
conn.sendall(data)
conn.close()
s = Server()
For the client, close the socket connect when done.
Client update:
c = Client()
print(c.send(b'Hello World'))
print(c.send(b'Hello World'))
c.client.close() # added
I am new at python and I want to make a server-client application but every time I am attempting a connection I see this error.
I have tried changing sequency of send() and receive() functions but that didn't worked out
msg = client_socket.recv (BUFSIZ) .decode ("utf8")
OSError: [WinError 10038] An attempt was made to perform an operation on an object that is not a socket
Here is the code
Client.py
"""Handles receiving of messages."""
#client_socket.bind((HOST, PORT))
#client_socket.connect((HOST, PORT))
msg = client_socket.recv(BUFSIZ).decode("utf8")
print(msg)
client_socket.close()
def send(event=None): # event is passed by binders.
"""Handles sending of messages."""
client_socket.connect((HOST, PORT))
msg = input("MSG: ")
client_socket.send(bytes(msg, "utf8"))
client_socket.close()
#----Now comes the sockets part----
HOST = '127.0.0.1'
PORT = 7557
if not PORT:
PORT = 33000
else:
PORT = int(PORT)
BUFSIZ = 1024
ADDR = (HOST, PORT)
client_socket = socket(AF_INET, SOCK_STREAM)
client_socket.connect(ADDR)
receive_thread = Thread(target=receive)
receive_thread.start()
if __name__ == '__main__':
client_socket.close()
receive()
send()
receive()
Ps: 99% of code is from internet
Don't close your socket after receiving and sending information.
from socket import AF_INET, socket, SOCK_STREAM
from threading import Thread
def receive() :
"""Handles receiving of messages."""
while True :
msg = client_socket.recv(BUFSIZ).decode("utf8")
print(msg)
def send():
"""Handles sending of messages."""
while True:
msg = input("MSG: ")
client_socket.send(bytes(msg, "utf8"))
#----Now comes the sockets part----
HOST = '127.0.0.1'
PORT = 7557
BUFSIZ = 1024
ADDR = (HOST, PORT)
client_socket = socket(AF_INET, SOCK_STREAM)
client_socket.connect(ADDR)
receive_thread = Thread(target=receive, args=() )
send_thread = Thread(target=send, args=())
if __name__ == '__main__':
receive_thread.start()
send_thread.start()
This is a modified version of your code.
I made a similar application by myself using the same logic, take a look:
https://github.com/moe-assal/Chatting_Server
How do I make a simple Python echo server that remembers clients and doesn't create a new socket for each request? Must be able to support concurrent access. I want to be able to connect once and continually send and receive data using this client or similar:
import socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
host = raw_input("Server hostname or ip? ")
port = input("Server port? ")
sock.connect((host,port))
while True:
data = raw_input("message: ")
sock.send(data)
print "response: ", sock.recv(1024)
I.e. with the server running on port 50000, using the above client I want to be able to do this:
me#mine:~$ client.py
Server hostname or ip? localhost
Server Port? 50000
message: testa
response: testa
message: testb
response: testb
message: testc
response: testc
You can use a thread per client to avoid the blocking client.recv() then use the main thread just for listening for new clients. When one connects, the main thread creates a new thread that just listens to the new client and ends when it doesn't talk for 60 seconds.
import socket
import threading
class ThreadedServer(object):
def __init__(self, host, port):
self.host = host
self.port = port
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.sock.bind((self.host, self.port))
def listen(self):
self.sock.listen(5)
while True:
client, address = self.sock.accept()
client.settimeout(60)
threading.Thread(target = self.listenToClient,args = (client,address)).start()
def listenToClient(self, client, address):
size = 1024
while True:
try:
data = client.recv(size)
if data:
# Set the response to echo back the recieved data
response = data
client.send(response)
else:
raise error('Client disconnected')
except:
client.close()
return False
if __name__ == "__main__":
while True:
port_num = input("Port? ")
try:
port_num = int(port_num)
break
except ValueError:
pass
ThreadedServer('',port_num).listen()
Clients timeout after 60 seconds of inactivity and must reconnect. See the line client.settimeout(60) in the function ThreadedServer.listen()