Hi This is my first post here. I am making a chatroom in Python using sockets and I have written the code for the server and client side. I am successful in establishing a connection between the server and the clients but I can't send any messages. The client provides a password and username through terminal and the server check if the password is correct and only then the client can send messages. I have not yet implemented the password check yet but the messages are still not being sent. I have made sure I am encoding and decoding correctly. I have also implemented threading to allow multiple users. Here is the server side code:
import socket
import threading
import sys
#TODO: Implement all code for your server here
#usernames = []
def broadcast(message):
for client in clients:
client.send(message)
def handle_client(client_socket, client_address):
try:
password = client_socket.recv(1024).decode()
username = client_socket.recv(1024).decode()
print("user: " + username)
clients.append(client_socket)
while True:
message = username + " joined the chatroom"
print(message)
broadcast(message.encode())
message = client_socket.recv(1024).decode()
if (message != ":Exit"):
print(f"{username}: {message}")
broadcast(message.encode())
else:
print(f"{username} left the chatroom")
clients.remove(client_socket)
client_socket.close()
message = username + " left the chatroom"
broadcast(message.encode())
break
except:
client_socket.close()
def receive():
while True:
client_socket, client_address = server.accept()
print(client_socket)
client_thread = threading.Thread(target=handle_client, args=(client_socket, client_address))
client_thread.start()
# Use sys.stdout.flush() after print statemtents
if __name__ == "__main__":
HOST = '127.0.0.1'
#PORT = int(sys.argv[1])
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind((HOST, 10001))
server.listen(5)
clients = []
print("server is listening")
receive()
Here is the client side:
import socket
import threading
import sys
#TODO: Implement a client that connects to your server to chat with other clients here
HOST = '127.0.0.1'
#PORT = int(sys.argv[1])
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.connect((HOST, 10001))
username = sys.argv[1]
password = sys.argv[2]
client_socket.send(password.encode())
client_socket.send(username.encode())
reply = client_socket.recv(1024).decode()
print(reply)
def receive():
while True:
try:
message = client_socket.recv(1024).decode()
if message:
print(message)
except:
continue
def write():
while True:
message = input()
if message == ":Exit":
client_socket.send(message.encode())
client_socket.close()
break
else:
client_socket.send(message.encode())
receive_thread = threading.Thread(target=receive)
receive_thread.start()
write_thread = threading.Thread(target=write)
write_thread.start()
# Use sys.stdout.flush() after print statemtents
if __name__ == "__main__":
pass
I have tried asking my TAs but they were of no help :(.
It looks like you are taking the second and third arguments instead of first and second. Thus if you do not pass 3 arguments with the third being the password then the client will not have a password to send.
After that I have connected to the server from input, how do I change my server in the chat?
I just updated the code with something that could work though it needs some more work, anyone?
def send(event=None): # event is passed by binders.
"""Handles sending of messages."""
global HOST
global PORT
global ADDR
msg = my_msg.get()
my_msg.set("") # Clears input field.
msg_list1 = msg.split()
try:
if msg_list1 [0] == "/connect":
try:
HOST = msg_list1[1]
PORT = int(msg_list1[2])
ADDR = (HOST,PORT)
client_socket.connect(ADDR)
receive_thread = Thread(target=receive)
receive_thread.start()
except TypeError:
msg_list_tk.insert(tt.END, "Error: please write '/connect ADDR PORT' to connect to server\n")
if msg_list1 [0] == "/connectnew":
HOST = msg_list1[1]
PORT = int(msg_list1[2])
ADDR = (HOST,PORT)
client_socket_2.connect(ADDR)
receive_thread = Thread(target=receive)
receive_thread.start()
except:
msg_list_tk.insert(tt.END, "Error: please write '/connect ADDR PORT' to connect to server\n")
elif msg == "/q":
root.quit()
client_socket.send(b"/q")
elif msg == "/disconnect":
client_socket.close()
else:
client_socket.send(bytes(msg, "utf8"))
except:
msg_list_tk.insert(tt.END, "Wrong input\n")
A TCP socket is only usable for a single TCP connection. If you want a second connection, you need to create a new socket and call connect() on that (i.e. you can't call connect() on your old socket a second time).
import paho.mqtt.publish as publish
import paho.mqtt.client as mqtt
USERNAME = "admin-user"
PASSWORD = "admin-user#12345"
AUTH = {"username":USERNAME, "password":PASSWORD}
HOSTNAME = "ssl://b-c7d1ea8g-f777-4c71-23a3-2d73088fdb64-1.mq.us-west-2.amazonaws.com"
PORT = 8883
TOPICNAME = "paho/test/single"
PAYLOAD = "Hope Stackoverflow Help Me Resolve This Issue!"
publish.single(TOPICNAME, payload=PAYLOAD, hostname=HOSTNAME, port=PORT, auth=AUTH, protocol=mqtt.MQTTv311, transport="tcp", client_id="", keepalive=60, will=None) # This won't work
# publish.single(TOPICNAME, payload=PAYLOAD, hostname="localhost") # This works!
print('published message payload = ', PAYLOAD)
I am able to connect to AmazonMQ with Java eclipse Paho client, but not able to do same the in Python. It gives me an error "gaierror: [Errno -2] Name or service not known".
The above python code works fine with a locally hosted ActiveMQ MQTT broker and also in stand alone server where I have hosted ActiveMQ MQTT broker. But the same is not working with AmazonMQ broker.
This issue is already mentioned in the issue tracker of Github Paho, but still there is no solution that will help.
You need to remove the "ssl://" from your host variable, and set a ssl context in order to connect to Amazon-MQ with paho.
context = ssl.create_default_context()
client.tls_set_context(context=context)
Here is a working version of the example posted on your github issue.
import paho.mqtt.client as mqttClient
import time
import ssl
context = ssl.create_default_context()
Connected = False
broker_address= "b-xxxxxx-acbf-xxxx-xxxx-xxxxx-1.mq.us-east-1.amazonaws.com" # No ssl://
port = 8883
user = "xxxxxx"
password = "xxxxx"
def on_connect(client, userdata, flags, rc):
if rc == 0:
print("Connected to broker")
global Connected #Use global variable
Connected = True #Signal connection
client.subscribe("test/data")
else:
print("Connection failed")
def on_message(client, userdata, msg):
print(msg.topic+" "+str(msg.payload))
client = mqttClient.Client("Test") #create new instance
client.username_pw_set(user, password=password) #set username and password
client.on_connect=on_connect
client.on_message=on_message
client.tls_set_context(context=context)
client.connect(broker_address, port=port)
client.loop_start()
while Connected != True:
time.sleep(0.1)
client.publish("test/data", "This is my test msg 123.")
time.sleep(10)
I am using the following code in attempt to connect to Azure IoT Hub. It uses SAS, therefore no security certificates are needed. I am successfully connecting to Azure IoT Hub using the same M2MQTT library in C# but this code fails with:
Failed to connect.Connection refused, not authorized. Error Code= 5
I tried any possible combos of security parameters but at no avail. The SAS token is generated by DeviceExplorer.
#! /usr/bin/python3.5
import serial
import time
import datetime
import os
import socket
import ssl
import logging
import paho.mqtt.client as mqtt
import sys
print(sys.executable)
def on_disconnect(client, userdata, rc):
if rc==0:
print("client disconnected OK")
client.connected_flag=False
def on_connect(client, userdata, flags, rc):
if rc==0:
print("Connected OK")
mqtt.Client.connected_flag=True
mqtt.Client.bad_connection_params=False
else:
mqtt.Client.bad_connection_params=True
if rc==1:
print("Failed to connect. Connection refused, unacceptable
protocol version. Error Code=", rc)
elif rc==2:
print("Failed to connect.Connection refused, identifier
rejected. Error Code=", rc)
elif rc==3:
print("Failed to connect.Connection refused, server unavailable. Error Code=", rc)
elif rc==4:
print("Failed to connect.Connection refused, bad user name or password. Error Code=", rc)
elif rc==5:
print("Failed to connect.Connection refused, not authorized. Error Code=", rc)
def on_publish(client, userdata, mid):
if rc==0:
print("Data published OK: ", userdata)
else:
print("Failed to publish data. MessageID=", mid)
pass
broker="myIoTHubName.azure-devices.net"
port=8883
DeviceID="MasterTag"
DeviceKey="myDeviceKey"
IoTHubName="myIoTHubName"
SasToken="SharedAccessSignature sr=myIoTHubName.azure-devices.net&sig=..."
# Create client object
# 4 stands for MQTTv311
rpiclient = mqtt.Client("PahoClient-on-RPi-Gateway2", clean_session=True, userdata=None, protocol=4, transport="tcp")
usernameFormat="{}{}{}"
username=usernameFormat.format(IoTHubName, ".azure-devices.net/", DeviceID)
password=SasToken
rpiclient.username_pw_set(username, password)
rpiclient.tls_set(tls_version=ssl.PROTOCOL_TLSv1_2)
rpiclient.tls_insecure_set(True)
# connection flag indicates that connection was made or not
mqtt.Client.connected_flag = False
# connection parameters are incorrect: ip address, port, authentication, etc
mqtt.Client.bad_connection_params=False
#assign function to callback
rpiclient.on_connect = on_connect
#assign function to callback
rpiclient.on_publish = on_publish
# bind the disconnect callback
rpiclient.on_disconnect = on_disconnect
rpiclient.loop_start()
rpiclient.will_set("dwm/position", "Client PahoClient-on-RPi2 had unexpectedly disconnected", 1, True)
try:
print("Connecting to MQTT broker ",broker)
# Connect to the MQTT Broker
rpiclient.connect(broker, port)
time.sleep(1)
# Wait in a loop until we are connected
print("mqtt.Client.connected_flag={},
mqtt.Client.bad_connection_params={}".format(mqtt.Client.connected_flag, mqtt.Client.bad_connection_params))
while mqtt.Client.connected_flag == False and mqtt.Client.bad_connection_params == False:
print("Waiting for connection...");
time.sleep(1)
if mqtt.Client.bad_connection_params == True:
rpiclient.loop_stop()
sys.exit()
except Exception as ex:
print("Connection to MQTT Broker failed: ", ex)
rpiclient.loop_stop()
# Disconnect MQTT Client
rpiclient.disconnect()
Any advice is appreciated.
the following is a working example of the simulated device1 connected to the Azure IoT Hub using a paho.Mqtt client library:
from paho.mqtt import client as mqtt
import time
import ssl
def on_subscribe(client, userdata, mid, granted_qos):
print('Subscribed for m' + str(mid))
def on_connect(client, userdata, flags, rc):
print("Connected with result code "+str(rc))
def on_message(client, userdata, message):
print("Received message '" + str(message.payload) + "' on topic '" + message.topic + "' with QoS " + str(message.qos))
def on_log(client, userdata, level, buf):
print("log: ",buf)
device_id = "device1"
iot_hub_name = "myIoTHub"
sas_token = "SharedAccessSignature sr=myIoTHub.azure-devices.net%2Fdevices%2Fdevice1&sig=****&se=1586926815"
client = mqtt.Client(client_id=device_id, protocol=mqtt.MQTTv311, clean_session=False)
client.on_log = on_log
client.tls_set_context(context=None)
# Set up client credentials
username = "{}.azure-devices.net/{}/api-version=2018-06-30".format(iot_hub_name, device_id)
client.username_pw_set(username=username, password=sas_token)
# Connect to the Azure IoT Hub
client.on_connect = on_connect
client.connect(iot_hub_name+".azure-devices.net", port=8883)
# Publish
client.publish("devices/{device_id}/messages/events/".format(device_id=device_id), payload="{}", qos=0, retain=False)
# Subscribing on the topic ,
client.on_message = on_message
client.on_subscribe = on_subscribe
client.subscribe("devices/{device_id}/messages/devicebound/#".format(device_id=device_id))
client.subscribe("$iothub/twin/PATCH/properties/desired/#")
client.subscribe("$iothub/methods/POST/#")
client.loop_forever()
Update:
The sas_token for the specific device can be generated using the Device Explorer tool, see the following screen snippet:
and the output log should be looked like the following screen snippet:
When you use MQTT to connect the Azure IoT Hub directly, you need to connect over TLS/SSL. In order to establish a TLS connection, you may need to download and reference the DigiCert Baltimore Root Certificate, and then set the certificate for the TLS/SSL connection. Please see the document Communicate with your IoT hub using the MQTT protocol.
client.tls_set(ca_certs=path_to_root_cert, certfile=None, keyfile=None,
cert_reqs=ssl.CERT_REQUIRED, tls_version=ssl.PROTOCOL_TLSv1, ciphers=None)
client.tls_insecure_set(False)
I am currently using the socket library in python to send basic text from one computer to another on the same local network.
My problem is that due to me using different computers on multiple occasions the iPv4 which the client connects to changes each time .
Line 4 of the client code : client.connect(("172.16.0.34",8888))
This introduces a difficulty as I cant change the ip in the client code very easily.
My Question:
Is there possibly a way that the client can "scan" the network to see what ip is hosting a socket and obtain that ip to connect to them, allowing me to use any computer and have it still functioning?
Here is my code:
Client:
import socket
client = socket.socket()
try:
client.connect(("172.16.0.34",8888))
except:
print("Server not connected")
else:
print("Connect to server: ","localhost")
while True:
print("[Waiting for response...]")
print(client.recv(1024))
valid = False
while not valid:
try:
msg = str(input("Enter your message to send: "))
except:
print("Invalid input format")
else:
valid = True
to_send = msg.encode("UTF-8")
client.send(to_send)
Server:
import socket
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print("Socket created")
host = "0.0.0.0"
port = 8888
print(host)
try:
server.bind((host,port))
except:
print("Bind failed")
else:
print("Bind successful")
server.listen(5)
clientsocket = None
while True:
if clientsocket == None:
print("[Waiting for connection..]")
(clientsocket, address) = server.accept()
print("Client accepted from", address)
else:
print("[Waiting for response...]")
print(clientsocket.recv(1024))
valid = False
while not valid:
try:
msg = str(input("Enter your message to send: "))
except:
print("Invalid input format")
else:
valid = True
clientsocket.send(msg.encode("UTF-8"))