list/array of (multi-threaded) sockets in python - 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()

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.

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).

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

Related

I'm encountering a Python error when I mix threading, input, and TCP sockets

I'm creating a program that uses threads to handle sockets and input at the same time. I've narrowed down the errors I'm getting to be replicable in these couple dozen lines of code. What happens to anyone else who runs the code below? I encounter a hang-up in waiting for the recv in the client. If I further try to send() more data in the server, I get a Broken Pipe error. And, even more weirdly, if I comment out the line that calls input(), the sockets work just fine.
What kind of weird interaction is going on between input(), sockets, and threading? And does anyone have a solution to this? Here's some code that generates the error.
Server:
import socket
import threading
def handle_connection(conn, addr):
data = conn.recv(1024)
message = data.decode('ascii').split()
s = "TEST"
conn.send(bytes(s, 'ascii')) #
conn.close()
def handle_input():
while True:
s = input()
print(s)
HOST = "127.0.0.1" # The server's hostname or IP address
PORT = 2000 # The port used by the server
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.bind((HOST, PORT)); #Empty first string = INADDR_ANY
s.listen();
w = threading.Thread(target=handle_input)
w.start()
while True:
conn, addr = s.accept()
x = threading.Thread(target=handle_connection, args=(conn, addr))
x.start()
s.close()
Client:
import socket
HOST = "127.0.0.1" # The server's hostname or IP address
PORT = 2000 # The port used by the server
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
message = "find_successor a"
s.connect((HOST, PORT))
s.sendall(bytes(message, 'ascii'))
data = s.recv(1024)
print(f"Received {data!r}")
I appreciate any help or insight!

Python sockets. OSError: [Errno 9] Bad file descriptor

It's my client:
#CLIENT
import socket
conne = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
conne.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
i=0
while True:
conne.connect ( ('127.0.0.1', 3001) )
if i==0:
conne.send(b"test")
i+=1
data = conne.recv(1024)
#print(data)
if data.decode("utf-8")=="0":
name = input("Write your name:\n")
conne.send(bytes(name, "utf-8"))
else:
text = input("Write text:\n")
conne.send(bytes(text, "utf-8"))
conne.close()
It's my server:
#SERVER
import socket
counter=0
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind(('', 3001))
sock.listen(10)
while True:
conn, addr = sock.accept()
data = conn.recv(1024)
if len(data.decode("utf-8"))>0:
if counter==0:
conn.send(b"0")
counter+=1
else:
conn.send(b"1")
counter+=1
else:
break
print("Zero")
conn.send("Slava")
conn.close()
))
After starting Client.py i get this error:
Traceback (most recent call last): File "client.py", line 10, in
conne.connect ( ('127.0.0.1', 3001) ) OSError: [Errno 9] Bad file descriptor
Problem will be created just after first input.
This program - chat. Server is waiting for messages. Client is sending.
There are a number of problems with the code, however, to address the one related to the traceback, a socket can not be reused once the connection is closed, i.e. you can not call socket.connect() on a closed socket. Instead you need to create a new socket each time, so move the socket creation code into the loop:
import socket
i=0
while True:
conne = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
conne.connect(('127.0.0.1', 3001))
...
Setting socket option SO_BROADCAST on a stream socket has no affect so, unless you actually intended to use datagrams (UDP connection), you should remove the call to setsockopt().
At least one other problem is that the server closes the connection before the client sends the user's name to it. Probably there are other problems that you will find while debugging your code.
Check if 3001 port is still open.
You have given 'while True:' in the client script. Are you trying to connect to the server many times in an infinite loop?

How to get python tcp server/client to allow multiple clients on ant the same time

I have started to make my own TCP server and client. I was able to get the server and the client to connect over my LAN network. But when I try to have another client connect to make a three way connection, it does not work. What will happen is only when the first connected client has terminated the connection between, the server and the client, can the other client connect and start the chat session. I do not understand why this happens. I have tried threading, loops, and everything else I can think of. I would appreciate any advice. I feel like there is just one small thing i am missing and I can not figure out what it is.
Here is my server:
import socket
from threading import Thread
def whatBeip():
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(('8.8.8.8', 0))
local_ip_address = s.getsockname()[0]
print('Current Local ip: ' + str(local_ip_address))
def clietConnect():
conn, addr = s.accept()
print 'Connection address:', addr
i = True
while i == True:
data = conn.recv(BUFFER_SIZE)
if not data:
break
print('IM Recieved: ' + data)
conn.sendall(data) # echo
whatBeip()
TCP_IP = ''
TCP_PORT = 5005
BUFFER_SIZE = 1024
peopleIn = 4
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((TCP_IP, TCP_PORT))
s.listen(peopleIn)
for client in range(peopleIn):
Thread(target=clietConnect()).start()
conn.close()
Here is my client
import socket
TCP_IP = '10.255.255.3'
TCP_PORT = 5005
BUFFER_SIZE = 1024
MESSAGE = "Hello, World!"
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((TCP_IP, TCP_PORT))
i = True
while i == True:
s.sendall(raw_input('Type IM: '))
data = s.recv(BUFFER_SIZE)
s.close()
This is your main problem: Thread(target=clietConnect()).start() executes the function clientConnect and uses it's return value as the Thread function (which is None, so the Thread does nothing)
Also have a look at:
1) You should wait for all connections to close instead of conn.close() in the end of the server:
threads = list()
for client in range(peopleIn):
t = Thread(target=clietConnect)
t.start()
threads.append(t)
for t in threads: t.join()
and to close the connection when no data is received:
if not data:
conn.close()
return
2) You probably want to use SO_REUSEADDR [ Socket options SO_REUSEADDR and SO_REUSEPORT, how do they differ? Do they mean the same across all major operating systems? , Python: Binding Socket: "Address already in use" ]
3) And have a look at asyncio for python

Python - Simple socket use

I want to create a simple communication between a server and a client using sockets. The cliend is supposed to send a message and then the server sends a message to the client.
This is my Client code :
import socket
s = socket.socket()
HOST = '127.0.0.1'
s.connect((HOST, 1234))
s.send('Hi')
print ('Client send')
print s.recv(1024)
s.close
This is my Server's code :
import socket
s = socket.socket()
HOST = '127.0.0.1'
s.bind((HOST, 1234))
s.listen(5)
while True:
c, addr = s.accept()
c.send('Hi client')
c.close()
But it only prints "Client send " .
In your server, after having sent 'Hi client' you must wait for the client to have read the message.
You could do either of two things:
Use shutdown() on the socket in the server, see https://docs.python.org/2/library/socket.html#socket.socket.shutdown
Do a .recv(..) in the server, which will terminate after the client has close'ed
the socket after reading the reply the server sent.
Update: tried it on my system (MacOSX). Started two python interpreters. Pasted the server code verbatim in one; server is now up and running and accepting connections.
In the other python interpreter, the client shell, I did the following
>>> import socket
>>> HOST = '127.0.0.1'
>>> def test():
... s = socket.socket()
... s.connect((HOST, 1234))
... s.send('Hi')
... print s.recv(1024)
... s.close() # <== Note function call here!
...
>>> test()
Hi client
>>> test()
Hi client
>>> test()
Hi client
>>> test()
Hi client
This demonstrates that - at least on my system - the code works as anticipated.
I can't reprocude your problem and therefore vote to close your question.
Here's the code I used:
import socket
import threading
HOST = '127.0.0.1'
PORT = 12345
def client():
s = socket.socket()
s.connect((HOST, PORT))
s.send('Hi')
print ('Client send')
print s.recv(1024)
s.close()
def server():
s = socket.socket()
s.bind((HOST, PORT))
s.listen(5)
c, addr = s.accept()
c.send('Hi client')
c.close()
if __name__ == "__main__":
server = threading.Thread(target=server)
server.start()
client()
server.join()
Here's the output I got:
$ python test.py
Client send
Hi client
If the problem persists, please add additional details to your question about why and how your setup still not works. Maybe the problem is just about how you run the programs. Please add details about this as well.
The underlying problem is that you treat sockets as if they were message-busses (one message at a time, always received fully), where in fact they are streams of bytes.
Nobody guarantees you that sending X bytes of data will reach the opposite side as that. It could be X1, X2, X3, Y1 where X1+X2+X3=X, and Y1 being the beginning of the next message Y. And all other kinds of combinations and errors.
To remedy this, real-world client-server apps use protocols. Take HTPP for example: a request starts always with HTTP, and it ends with two newlines. Within this block, there is the Content-Length header telling the client how many bytes to read then - regardless of chunk sizes.
So to really solve your problem, you either have to write a full fledged protocol, or built upon libraries that do that for you - e.g. Twisted, Nanomsg or ZeroMQ

Python server-client

I need some help. I have a simple server:
host="localhost"
port=4447
from socket import *
import thread
def func():
while 1:
data = conn.recv(1024)
if not data:
continue
else:
print("%s said: %s")%(player, data)
conn.close()
s=socket(AF_INET, SOCK_STREAM)
s.bind((host,port))
s.listen(2)
print("Waiting for clients on localhost, port %s")%port
while 1:
conn, addr = s.accept()
player = addr[1]
print(conn)
thread.start_new_thread(func,())
And a simple client:
import socket
TCP_IP = '127.0.0.1'
TCP_PORT = 4447
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((TCP_IP, TCP_PORT))
while 1:
data = raw_input("Input: ")
s.send(data)
So when I connect to the server I can type anything and it is printed in the server's terminal. When I open another terminal and start second client I can also type anything and it is sent to the server, but when I go back to the first client's terminal and type several messages, it returns:
Traceback (most recent call last):
File "Client.py", line 18, in <module>
s.send(data)
socket.error: [Errno 32] Broken pipe
So I fixed that with adding conn as a parameter in func(), but I don't understand why this error happened? Could anyone please explain it to me?
Thanks!
Your func, apart from needing a better name, uses global state in your program to communicate with a client. No matter how many threads you start to handle client connections, there's still only one global conn variable. Each time a new client connects, your main thread loop rebinds conn to the new connection. The old socket is thrown away and automatically closed by the Python runtime.
You can fix this by removing the use of global variables to track per-connection state. A better route to explore, though, is Twisted.

Categories

Resources