JeremyVarghese
JeremyVarghese

Reputation: 41

Unable to send data to a specific websocket client in python

I'm writing a program with websockets in python. I've got an example server and client code running and they work well if only one client is connected. If there are multiple clients, data from the server will go randomly to one of the clients.

I would like for:

  1. Server to keep track of the various clients connected
  2. Server to be able to direct messages to a specific client out of multiple(For eg. 5) clients

websockets is the library I'm using. Python version 3.7.2

Server Code:

import asyncio
import websockets

uri='localhost'


async def response(websocket, path):

    msg = input("What do you want to send : ")
    print("message:",msg)
    await websocket.send(msg)

start_server = websockets.serve(response, uri, 5000)
asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()

Client Code:

import asyncio
import websockets

uri="ws://localhost:5000"     
async def message():

                async with websockets.connect(uri) as socket:
                        print(await socket.recv())

while True:
        asyncio.get_event_loop().run_until_complete(message())

If I create 2 files with the client code as client1.py and client2.py, and send message from the server side, I get the sent data going to either on of the clients.

I would like to:

  1. Server keeps track of the various clients connected
  2. Server is able to direct messages to a specific client out of multiple clients

As I am just starting out with websockets, all input is appreciated.

In this output given, I intended to send all my messages to client 1, yet they got split up between client 1 and 2

Upvotes: 4

Views: 5021

Answers (2)

Mane Motha
Mane Motha

Reputation: 11

"websocket" targets the current connection and if you say "websocket.send(msg)" you're sending a message to the client that has just connected and websocket is an object that is reusable while the client is connected. You can assign the websocket as a variable then send a message some other time as long as the connection is still opened.

NOT RECOMMENED

Requiring user's input from the server is not a good idea because now you're awaiting the server until it receives user inputs. Nothing really happens to the server while it's waiting for user's input and this may crush your server.

RECOMMENED

A client has to tell the server which connection / client to send the message to. I would recommend using a JSON format when sending messages within client's and the server and then convert the String to a python-dict since websocket requires only strings.

Click here to check out my GitHub repository. A websockets server made only Python.

SERVER EXAMPLE

Example on how you can send a packet to a specific client

Upvotes: 1

itsaMeMathi0x
itsaMeMathi0x

Reputation: 172

I'm not familiar with asyncio, so I will try to get to the point with functions/threads;

Usually, my server side listens to one connection and once it accepts it, I have a function 'handler' that is threaded to each connection that gets accepted.

part of my server and handler:

def handler(conn, addr):
    global data1

    while True:
        data = conn.recv(2048)
        data1 = json.loads(data.decode())
        # treat it as you need

while True:
    s.listen(1)
    conn, addr = s.accept()
    print('Conectado com', addr[0],':', str(addr[1]))
    thr = threading.Thread(target = handler, args = (conn, addr)).start()

Now, for the control of the clients and such, I always use a dictionary. The key should be the username or any other particular info. The value of the key is the 'conn' from that user. This way you can get the connection of user 'x' by its specific key.

Something like:

import socket
import time
import datetime as dt
import base64
import os
import json
import threading

HOST = ''
PORT = 12999

global s

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind((HOST,PORT))

whoto = {}

def autenticacao():

    global data1
    global conn
    global nomeuser

    user1 = data1[1]
    passwd = data1[2]


    auth = c.execute('SELECT usuario FROM fullinfo WHERE usuario= ? AND password = ?', (user1,passwd)).fetchone()
    if auth is not None:
        word = 'autenticado'
        conn.sendall(word.encode())
        nomeuser = auth[0]
        whoto[nomeuser] = conn

I'm sorry i'm leaving it unreproducible, but my point is to show the 'algorithm'. This dictionary is what I use to keep record of who is online, the 'adress' (conn) of each client to send messages to single clients and such. On the example above, I add the user (key) and conn (value) once it's authenticated inside my server.

Hope this helps. Good luck!

Upvotes: 0

Related Questions