I am following the Bidirectional pair socket example from the pyzmq documentation. I created two files,
socket1.py with this code
import zmq
import random
import sys
import time
port = "5556"
context = zmq.Context()
socket = context.socket(zmq.PAIR)
socket.connect("tcp://localhost:{}".format(port))
print("Socket created")
i = 0
while True:
msg = socket.recv()
print("socket: msg recved")
print(msg)
socket.send_string("hello from 1")
time.sleep(1)
print(i)
and socket2.py with this code:
import zmq
import random
import sys
import time
port = "5556"
context = zmq.Context()
socket = context.socket(zmq.PAIR)
socket.connect("tcp://localhost:{}".format(port))
print("Socket created")
i = 0
while True:
socket.send_string("hello from 2")
print("socket2: msg sent")
msg = socket.recv()
print(msg)
time.sleep(1)
print(i)
I run both the files in 2 separate terminals but it prints the following messages in terminal1 and terminal2 respectively:
Socket created
Socket created
socket2: msg sent
I am not able to understand why socket1 is not receiving the msg sent by socket2 and is stuck at socket.recv(). I would really appreciate any help. TIA.
You are close. The first example, socket1.py needs to bind to the port. zeromq will turn that into a listen for the client to connect.
import zmq
import random
import sys
import time
port = "5556"
context = zmq.Context()
socket = context.socket(zmq.PAIR)
socket.bind("tcp://localhost:{}".format(port))
print("Socket created")
i = 0
while True:
msg = socket.recv()
print("socket: msg recved")
print(msg)
socket.send_string("hello from 1")
time.sleep(1)
print(i)
Related
I have written a simple server and client py using UDP. The base is working, however I want that every time a user (client) joins, he would receive a chatlog of everything that has been said.
This is my code until now:
Server:
import socket
import threading
import queue
import pickle
messages = queue.Queue()
clients = []
# AF_INET used for IPv4
# SOCK_DGRAM used for UDP protocol
ip = "localhost"
port = 5555
chatlog=[]
UDPServerSocket = socket.socket(family=socket.AF_INET, type=socket.SOCK_DGRAM)
# binding IP and port
UDPServerSocket.bind((ip, port))
def receive():
while True:
try:
message, addr = UDPServerSocket.recvfrom(1024)
messages.put((message, addr))
chatlog.append((message,addr))
except:
pass
def broadcast():
while True:
while not messages.empty():
message, addr = messages.get()
print(message.decode())
if addr not in clients:
clients.append(addr)
for client in clients:
try:
if message.decode().startswith("SIGNUP_TAG:"):
name = message.decode()[message.decode().index(":") + 1:]
UDPServerSocket.sendto(f"{name} joined!".encode(), client)
if len(chatlog)>0:
sending= pickle.dumps(chatlog)
UDPServerSocket.sendto(sending, client)
else:
pass
else:
UDPServerSocket.sendto(message, client)
except:
clients.remove(client)
t1 = threading.Thread(target=receive)
t2 = threading.Thread(target=broadcast)
t1.start()
t2.start()
And the client
import socket
import threading
import random
client= socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
client.bind(("localhost", random.randint(7000, 8000))) # random port for every client
name = "Henk" #test name
def receive():
while True:
try:
message, _ = client.recvfrom(1024)
print(message.decode())
except:
pass
t= threading.Thread(target= receive)
t.start()
#this gives the server the name of the people who have entered the server
client.sendto(f"SIGNUP_TAG: {name}".encode(), ("localhost", 5555))
while True:
message= input("")
if message=="!q":
exit()
else:
client.sendto(f'[{name}]: {message}'.encode(), ("localhost",5555))
So I am actually a bit stuck on how I will approach this. Shall create a text file where every time that a message is written it gets written on the file as well? Or shall I create some kind of string list/database where every message is stored :/
I have been able to successfully create a chat application that works within a local network. I am wanting to deploy the server script to Heroku to enable connections from outside of the local network. Obviously I cannot use sockets on Heroku and will need to convert my code to utilize Websockets instead. I could re-write the entire script but wanting to see if there is a "path of least resistance" using the code I already have.
So the question: Is there a simple way to convert the Code I have to utilize websockets instead of sockets?
Server Side Code
import socket
from threading import Thread
# server's IP address
SERVER_HOST = "54.243.238.66"
SERVER_PORT = 5002 #port we want to use
separator_token = "<SEP>" # use this to separate the client name and message
#initialize list/set of all connected client's sockets
client_sockets = set()
#create a TCP socket
s = socket.socket()
#make the port reuseable
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
#bind the socket to the address we spedified
s.bind((SERVER_HOST, SERVER_PORT))
#listen for upcoming connections
s.listen(5)
print(f"[*] Listening as {SERVER_HOST}:{SERVER_PORT}")
def listen_for_client(cs):
"""
This function keeps listening for a message from 'cs' socket
Whenever a message is received, broadcast it to all other connected clients
"""
while True:
try:
#keep listening for a message from 'cs' socket
msg = cs.recv(1024).decode()
except Exception as e:
#Client no longer connected
#remove client from the set
print(f"[!] Error: {e}")
client_sockets.remove(cs)
else:
#if we received a message, replace the <SEP> token with ": " for nice printing
msg = msg.replace(separator_token, ": ")
for client_socket in client_sockets:
client_socket.send(msg.encode())
while True:
client_socket, client_address = s.accept()
print(f"[+] {client_address} connected.")
client_sockets.add(client_socket)
t = Thread(target=listen_for_client, args=(client_socket,))
t.daemon = True
t.start()
for cs in client_sockets:
cs.close()
s.close()
Client Side Code
import sys
import subprocess
subprocess.check_call([sys.executable, '-m', 'pip', 'install', 'colorama'])
import socket
import random
from threading import Thread
from datetime import datetime
from colorama import Fore, init, Back
init()
colors = [Fore.BLUE, Fore.CYAN, Fore.GREEN, Fore.LIGHTBLACK_EX,
Fore.LIGHTBLUE_EX, Fore.LIGHTCYAN_EX, Fore.LIGHTGREEN_EX,
Fore.LIGHTMAGENTA_EX, Fore.LIGHTRED_EX, Fore.LIGHTWHITE_EX,
Fore.LIGHTYELLOW_EX, Fore.MAGENTA, Fore.RED, Fore.WHITE, Fore.YELLOW
]
client_color = random.choice(colors)
SERVER_HOST = "54.243.238.66"
SERVER_PORT = 5002
separator_token = "<SEP>"
s = socket.socket()
print(f"[*] Connecting to {SERVER_HOST}:{SERVER_PORT}...")
s.connect((SERVER_HOST, SERVER_PORT))
print("[+] Connected.")
name = input("Enter your name: ")
print("To exit, type 'q' at any time and press enter.")
def listen_for_messages():
while True:
message = s.recv(1024).decode()
print("\n" + message)
# make a thread that listens for messages to this client & print them
t = Thread(target=listen_for_messages)
# make the thread daemon so it ends whenever the main thread ends
t.daemon = True
# start the thread
t.start()
while True:
# input message we want to send to the server
to_send = input()
# a way to exit the program
if to_send.lower() == 'q':
break
# add the datetime, name & the color of the sender
date_now = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
to_send = f"{client_color}[{date_now}] {name}{separator_token}{to_send}{Fore.RESET}"
# finally, send the message
s.send(to_send.encode())
# close the socket
s.close()
I've been trying to create a simple chat, my idea was to have 2 functions running in a loop on different threads, one is for sending messages and one is for receiving messages, I am prompted to enter messages which means that at least my sending messages thread works, and I also get connection success message but for some reason the messages are not reaching the other end.
this is my code:
server.py:
from socket import *
import threading
server = socket(AF_INET, SOCK_STREAM)
server.bind(("", 4444))
server.listen(5)
def acceptmessages():
while True:
data = client.recv(2048).decode()
print(data)
def sendmessages():
while True:
msg = input("Enter message > ").encode()
client.sendall(msg)
client, addr = server.accept()
print("New connection from Address: {0}".format(addr))
threading.Thread(target=sendmessages(), args=()).start()
threading.Thread(target=acceptmessages(),args=()).start()
client.py:
from socket import *
import threading
client = socket(AF_INET, SOCK_STREAM)
client.connect(("10.0.0.7", 4444))
def acceptmessages():
while True:
data = client.recv(2048).decode()
print(data)
def sendmessages():
while True:
msg = input("Enter message > ").encode()
client.sendall(msg)
threading.Thread(target=sendmessages(), args=()).start()
threading.Thread(target=acceptmessages(),args=()).start()
The problem was I called the function in the target field instead of passing the function, so instead of
threading.Thread(target=sendmessages(), args=()).start()
threading.Thread(target=acceptmessages(),args=()).start()
it needs to be
threading.Thread(target=sendmessages).start()
threading.Thread(target=acceptmessages).start()
I would like to use XSUB/XPUB to enable multiple ZMQ publishers and subscribers. Everything works when I use zmq.proxy(xpub_socket, xsub_socket), but I need something custom because I need to write code between XSUB and XPUB that examines the messages.
Here's where I'm at:
import time
import zmq
context = zmq.Context()
address = '127.0.0.1'
pub_port = '3000'
sub_port = '3001'
# XSUB socket
xsub_socket = context.socket(zmq.XSUB)
xsub_socket.bind(f'tcp://{address}:{pub_port}')
# XPUB socket
xpub_socket = context.socket(zmq.XPUB)
xpub_socket.bind(f'tcp://{address}:{sub_port}')
time.sleep(1)
# PUB socket
pub_socket = context.socket(zmq.PUB)
pub_socket.connect(f'tcp://{address}:{pub_port}')
# SUB socket
sub_socket = context.socket(zmq.SUB)
sub_socket.subscribe('')
sub_socket.connect(f'tcp://{address}:{sub_port}')
time.sleep(1)
pub_socket.send_string('test')
time.sleep(1)
print(poller.poll(0))
The values sent from the PUB socket do not reach the XSUB socket.
I read here that the first byte needs to be 1. Both of these also don't work:
pub_socket.send(b'\x01')
pub_socket.send_multipart([b'\x01', 'test'.encode('utf-8')])
What am I doing wrong here?
A PUB socket won't send any messages to an XSUB socket unless it has received a subscription request, which you get by calling subscribe on a SUB socket.
The only way those subscription messages get passed through is if you set up your XSUB/XPUB proxy.
Here's a simple proxy that connects an XPUB and XSUB socket, printing out messages it receives in either direction:
import zmq
ctx = zmq.Context()
xpub_sock = ctx.socket(zmq.XPUB)
xpub_sock.bind("tcp://127.0.0.1:3000")
xsub_sock = ctx.socket(zmq.XSUB)
xsub_sock.bind("tcp://127.0.0.1:3001")
poller = zmq.Poller()
poller.register(xpub_sock, zmq.POLLIN)
poller.register(xsub_sock, zmq.POLLIN)
while True:
socks = dict(poller.poll())
if xpub_sock in socks and socks[xpub_sock] == zmq.POLLIN:
msg = xpub_sock.recv_multipart()
print("(sub)", msg)
xsub_sock.send_multipart(msg)
elif xsub_sock in socks and socks[xsub_sock] == zmq.POLLIN:
msg = xsub_sock.recv_multipart()
print("(pub)", msg)
xpub_sock.send_multipart(msg)
If I connect to this with an PUB socket, like this...
import zmq
import time
ctx = zmq.Context()
pub_sock = ctx.socket(zmq.PUB)
pub_sock.connect("tcp://localhost:3001")
while True:
pub_sock.send_string("test")
time.sleep(1)
...I won't see any messages arriving at the XSUB socket, because
there are no active subscriptions. However, if I connect a SUB
socket to the XPUB socket and set a subscription...
import zmq
ctx = zmq.Context()
sub_sock = ctx.socket(zmq.SUB)
sub_sock.connect("tcp://localhost:3000")
sub_sock.subscribe("")
while True:
msg = sub_sock.recv()
print(msg)
...then I will start to see messages passing from the PUB socket to
the XSUB socket, and then from the XPUB socket to the SUB
socket.
I am writing a program to send the data continuously to the Client from the Server. In here, i am using a timestamp for sample to send it to the multiple Clients who are connected. I have used multi-threading to support multiple Clients. I want the time to be sent every 10 seconds to the client. but in my code, the client stops after receiving the first data. How to make client continuously receive the data. I tried adding while loop in Client Side but it doesn't make it possible. Any suggestions please
Here's the sample Code:
Server Side:
import socket
import os
from threading import Thread
import thread
import threading
import time
import datetime
def listener(client, address):
print "Accepted connection from: ", address
with clients_lock:
clients.add(client)
try:
while True:
data = client.recv(1024)
if not data:
break
else:
print repr(data)
with clients_lock:
for c in clients:
c.sendall(data)
finally:
with clients_lock:
clients.remove(client)
client.close()
clients = set()
clients_lock = threading.Lock()
host = socket.gethostname()
port = 10016
s = socket.socket()
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind((host,port))
s.listen(3)
th = []
while True:
print "Server is listening for connections..."
client, address = s.accept()
timestamp = datetime.datetime.now().strftime("%I:%M:%S %p")
client.send(timestamp)
time.sleep(10)
th.append(Thread(target=listener, args = (client,address)).start())
s.close()
Client Side:
import socket
import os
from threading import Thread
import socket
import time
s = socket.socket()
host = socket.gethostname()
port = 10016
s.connect((host, port))
print (s.recv(1024))
s.close()
# close the connection
My output:
01:15:10
Required Output on clients:
01:15:10
01:15:20
01:15:30
#and should go on
Server side
while True:
client, address = s.accept()
th.append(Thread(target=listener, args = (client,address)).start())
s.close()
In def listener() change while loop to continuously send data for each thread like this
while True:
data = client.recv(1024)
if data == '0':
timestamp = datetime.datetime.now().strftime("%I:%M:%S %p")
client.send(timestamp)
time.sleep(2)
at client side add this line in while loop to send some data to satisfy the if condition
s.connect((host, port))
while True:
s.send('0')
print(s.recv(1024))
#s.close()