You can use thread pools. Look at the multiprocessing.pool.ThreadPool package. You can create a pool of size N and then use a the imap_unordered() in a for loop to connect, send, and receive for each thread.
You can also use multiprocessing.pool.Pool for a pool of processes (versus thread), but it sounds like this will be I/O bound, so the ThreadPool would be better, IMHO.
For example:
from multiprocessing.pool import ThreadPool as Pool
import random
import time
def do_something(x):
delay = random.randint(1,3)
time.sleep(delay)
return x,delay
for i, result in pool.imap_unordered(do_something, range(10)):
print i, result