'Unable to get TCP client working in Flask APP

I have 2 programs running on a server with TCP service to communicate with the outside world. Now I would like to implement a FLASK App as an intermedium service to pass information between the outside users and the TCP sevices. How should I implement it?

workflow I have implemented the TCP server & client scripts (https://www.geeksforgeeks.org/simple-chat-room-using-python/), both work fine independently.

chat_server.py

#!/usr/bin/env python3
# chat_server.py localhost 6673

import socket, threading, sys

# Global variable that mantain client's connections
connections = []

def handle_user_connection(connection: socket.socket, address: str) -> None:
    '''
        Get user connection in order to keep receiving their messages and
        sent to others users/connections.
    '''
    while True:
        try:
            # Get client message
            msg = connection.recv(1024)

            # If no message is received, there is a chance that connection has ended
            # so in this case, we need to close connection and remove it from connections list.
            if msg:
                # Log message sent by user
                print(f'{address[0]}:{address[1]} - {msg.decode()}')
                
                # Build message format and broadcast to users connected on server
                msg_to_send = f'From {address[0]}:{address[1]} - {msg.decode()}'
                broadcast(msg_to_send, connection)

            # Close connection if no message was sent
            else:
                remove_connection(connection)
                break

        except Exception as e:
            print(f'Error to handle user connection: {e}')
            remove_connection(connection)
            break


def broadcast(message: str, connection: socket.socket) -> None:
    '''
        Broadcast message to all users connected to the server
    '''

    # Iterate on connections in order to send message to all client's connected
    for client_conn in connections:
        # Check if isn't the connection of who's send
        if client_conn != connection:
            try:
                # Sending message to client connection
                client_conn.send(message.encode())

            # if it fails, there is a chance of socket has died
            except Exception as e:
                print('Error broadcasting message: {e}')
                remove_connection(client_conn)


def remove_connection(conn: socket.socket) -> None:
    '''
        Remove specified connection from connections list
    '''

    # Check if connection exists on connections list
    if conn in connections:
        # Close socket connection and remove connection from connections list
        conn.close()
        connections.remove(conn)


def server() -> None:
    '''
        Main process that receive client's connections and start a new thread
        to handle their messages
    '''

    try:
        # Create server and specifying that it can only handle 4 connections by time!
        socket_instance = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        socket_instance.bind((SERVER, PORT))
        socket_instance.listen(4)

        print('Server running!')
        
        while True:

            # Accept client connection
            socket_connection, address = socket_instance.accept()
            # Add client connection to connections list
            connections.append(socket_connection)
            # Start a new thread to handle client connection and receive it's messages
            # in order to send to others connections
            threading.Thread(target=handle_user_connection, args=[socket_connection, address]).start()

    except Exception as e:
        print(f'An error has occurred when instancing socket: {e}')
    finally:
        # In case of any problem we clean all connections and close the server connection
        if len(connections) > 0:
            for conn in connections:
                remove_connection(conn)

        socket_instance.close()


if __name__ == "__main__":
    SERVER = sys.argv[1]
    PORT = int(sys.argv[2])
    
    server()

chat_client.py

#!/usr/bin/env python3

# chat_client.py localhost 6673

# Python program to implement client side of chat room.
import socket
import select
import sys
 
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
if len(sys.argv) != 3:
    print ("Correct usage: script, IP address, port number")
    exit()
IP_address = str(sys.argv[1])
Port = int(sys.argv[2])
server.connect((IP_address, Port))
 
while True:
 
    # maintains a list of possible input streams
    sockets_list = [sys.stdin, server]
 
    """ There are two possible input situations. Either the
    user wants to give manual input to send to other people,
    or the server is sending a message to be printed on the
    screen. Select returns from sockets_list, the stream that
    is reader for input. So for example, if the server wants
    to send a message, then the if condition will hold true
    below.If the user wants to send a message, the else
    condition will evaluate as true"""
    read_sockets,write_socket, error_socket = select.select(sockets_list,[],[])
 
    for socks in read_sockets:
        if socks == server:
            message = socks.recv(2048)
            print (f'Received from server: {message.decode()}\n')
        else:
            message = sys.stdin.readline()
            server.send(message.encode())
            sys.stdout.write("<You>")
            sys.stdout.write(message)
            sys.stdout.flush()
server.close()

FLASK app.py:

#!/usr/bin/env python3

# app.py localhost 6673

import flask
from flask import request, jsonify
import re
import socket
import time
import sys
import os
from signal import SIGKILL
from subprocess import Popen, PIPE


app = flask.Flask(__name__)
app.config["DEBUG"] = True

# =================================================================
# I need to send the data_array to TCP_CONN and wait the reply, then 
# return the reply back to user through HTTP
# =================================================================
def send_to_tcp(server, port, data_array):
    reply = {'fakeData': 123}
    return reply

def close_port(port):
    process = Popen(["lsof", "-i", ":{0}".format(port)], stdout=PIPE, stderr=PIPE)
    stdout, stderr = process.communicate()
    for process in str(stdout.decode("utf-8")).split("\n")[1:]:
        data = [x for x in process.split(" ") if x != '']
        if (len(data) <= 1):
            continue
        os.kill(int(data[1]), SIGKILL)



@app.route('/', methods=['GET'])
def home():
    return '''<h1>Testing</h1>
<p>Testing.</p>'''


@app.route('/all', methods=['GET'])
def api_all():
    return jsonify({'a':1, 'b':2})


@app.route('/item', methods=['GET'])
def api_id():
    if 'params' in request.args:
        #print(request.args)
        #id = int(request.args['id'])
        params = re.findall(r'<([^<>]+)>', request.args['params'])
        returns = send_to_tcp(HOST, PORT, params)
        for p in params:
            print(p)
        return jsonify(params)
    else:
        return "Error: No params field provided."


if __name__ == '__main__':
    HOST = sys.argv[1]
    PORT = int(sys.argv[2])
    TCP_CONN = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    TCP_CONN.connect((HOST, PORT))

    try:
        app.run(host=HOST, port=5000, debug=True)
        #from waitress import serve
        #serve(app, host=HOST, port=PORT)
        #threading.Thread(target=lambda: serve(app, host=HOST, port=5000)).start()
        #threading.Thread(target=lambda: app.run(host=HOST, port=5000, debug=True, use_reloader=False)).start()

    finally:
        close_port(PORT)

The FLASK app works fine as well with the fake send_to_tcp() function:

http://localhost:5000/item?params=%3Caaa:111%3E%3Cbbb:222%3E
FLASK's return

But it failed to talk to the TCP services. I tried something below but it didn't work:

def send_to_tcp(server, port, data_array):
    s = TCP_CONN
    r = ''
    while True:
        for d in data_array:
            ds = d
            s.send(ds.encode())
            print(ds)

        data = s.recv(4096)
        if len(data) == 0:
            break
        print(f"Received {data!r}")
        r = f'{r}{data.decode()}'
    return r

Could someone please help? Thanks in advance!



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source