Perplexabot
Perplexabot

Reputation: 1989

list/array of (multi-threaded) sockets in python

I am kind of new to python. I am currently trying to make and use a list/array of sockets in a program. So I have declared an array as follows:

myCSocks = ['CSock1', 'CSock2', 'CSock3', 'CSock4', 'CSock5']

And I am trying to use my array elements as follows:

myCSocks[i], addr = serverSocket.accept()
message = myCSocks[i].recv(1024)

I am getting the following error:

Traceback (most recent call last):
  File "./htmlserv_multi.py", line 22, in <module>
    message = myCSocks[i].recv(1024)
AttributeError: 'str' object has no attribute 'recv'

This kind of makes sense to me, it is saying that my array elements are of type String and are not sockets. So I understand what my problem is but I do not know how to remedy it. I have googled "list of sockets python" but did not find anything. Any help will be greatly appreciated. Thank you.

PS: My final objective is to create a very simple multithreaded TCP web server (using python)

CODE:

#! /usr/bin/env python
from socket import *

#does this work?
myCSocks = []

serverSocket = socket(AF_INET, SOCK_STREAM)
serverSocket.bind(('192.168.1.4',12000))
serverSocket.listen(5)
while True:
  for i in range(0, len(myCSocks)+1):
    myCSocks[i], addr = serverSocket.accept()
  try:
    for i in range(0, len(myCSocks)):
      message = myCSocks[i].recv(1024)
      filename = message.split()[1]
      f = open(filename[1:])
      outputdata = f.read()
      myCSocks[i].send('HTTP/1.1 200 OK\r\n\r\n')
      for p in range(0, len(outputdata)):
        myCSocks[i].send(outputdata[p])
      myCSocks[i].close()
  except IOError:
    connectionSocket.send('HTTP/1.1 404 Bad Request\r\n\r\n')
    connectionSocket.send('<HTML><p>ERROR 404: BAD REQUEST!</p></HTML>')
    serverSocket.close()
    exit()

Upvotes: 1

Views: 3582

Answers (3)

Perplexabot
Perplexabot

Reputation: 1989

A very simple echo TCP (SOCK_STREAM) server demonstrating how to implement a multiprocessing server. Makes use of threadPoolExecutor to accept connections asynchronously.

Server:

import socket
import concurrent.futures


def server_instance(addr):
    HOST = addr[0]
    PORT = addr[1]
    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
        s.bind((HOST, PORT))
        s.listen()
        conn, addr = s.accept()
        with conn:
            print(f"Linked with: {addr}")
            while True:
                data = conn.recv(1024)
                if not data:
                    break
                conn.sendall(data)
    return f'DONE'


addresses = [
    ('127.0.0.1', 65432),
    ('127.0.0.1', 65431),
    ('127.0.0.1', 65433),
    ('127.0.0.1', 65435),
    ('127.0.0.1', 65434),
]


with concurrent.futures.ThreadPoolExecutor() as executor:
    for address, status in zip(addresses, executor.map(server_instance, addresses)):
        print(f"{address}: {status}")

A client to send data to server.

Client:

import socket
import sys

HOST = '127.0.0.1'


if len(sys.argv) != 3:
    print(f"[*] Usage: python {sys.argv[0]} <PORT> <MESSAGE>")
    sys.exit()

PORT = int(sys.argv[1])
print(f"PORT SET TO: {PORT}")

MSG = bytes(sys.argv[2], encoding='utf8')
print(f"MESSAGE SET TO: {MSG}")

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
    s.connect((HOST, PORT))
    s.sendall(MSG)
    data = s.recv(1024)

print(f'[r] {repr(data)}')

f-strings require python3.6 and up

concurrent futures require python 3.2 and up

Upvotes: 1

Peter Halliday
Peter Halliday

Reputation: 301

If CSock1 is a class already defined you can just refer to the class objects. However, if you are trying to do a multi-threaded, there's better ways to do that: Multithreaded web server in python. If you are just trying to use sockets, I'd look at Multi Threaded TCP server in Python (the second answer is best).

Upvotes: 1

Andy Rimmer
Andy Rimmer

Reputation: 2111

Have a look at the built-in socket module here (http://docs.python.org/2/library/socket.html). This allows you to create sockets, and send and receive data, and there are simple examples in the online documentation. Your code will probably work if you replace the strings with actual sockets. If you want to store several sockets by name, you could use a dictionary:

theDict = {}
theDict['socket1'] = socket.socket()

etc.

Upvotes: 2

Related Questions