TNT the lagger
TNT the lagger

Reputation: 35

How to make a TCP server handle multiple clients?

I'm trying to make a Python server where multiple clients can connect but I've run into a problem I tried everything that I found on the internet. I'm running a laptop whit windows 7 and an I3 processor.

This is the file called tcp:

import socket

def make_server (ip,port):
    try:
        server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        server.bind((ip, port))
        server.listen(1)
        return server
    except Exception as ex:
        print(ex)
        return None


def accept(server):
    conn, addr = server.accept()
    return conn

def make_client():
    client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    return client

def client_connect(client,ip,port):
    client.connect((ip,port))

def sendall(conn,mess):
    conn.send(str(mess).encode("utf-8"))

def rec(conn,rate):
    mess = conn.recv(rate).decode("utf-8")
    return mess

def close(client):
    client.close()

This is the server:

from multiprocessing import Process
from random import randint
import tcp
import sys


def start(sip, sport):
    print("Making sob server...")
    print("id= {}".format(sport))
    sserver = tcp.make_server(sip, sport)
    print("Sub Server Started!")
    sconn = tcp.accept(sserver)
    tcp.sendall(sconn, "connected!!")
    while True:
        try:
            tcp.sendall(sconn, randint(0, 100))
        except Exception as ex:
            print("")
            print("From server {} error:".format(port))
            print(ex)
            print("")
            break


ip = "192.168.0.102"
port = 8000
subport = 9000
server = tcp.make_server(ip, port)
if server is None:
    sys.exit(0)
print("Started!")
while True:
    print("Wating for new connection!")
    con = tcp.accept(server)
    print("Connected!")
    subport = subport + 1
    tcp.sendall(con, subport)
    print("New Port Sent!")
    print("New Port = {}".format(subport))
    subs = Process(target=start, args=(ip, subport))
    subs.start()
    subs.join()

This is the client:

import tcp
import time

nport = 0
ip = "192.168.0.102"
port = 8000
client = tcp.make_client()
tcp.client_connect(client,ip,port)
nport = tcp.rec(client,1024)
print(nport)
tcp.close(client)
nport = int(nport)
time.sleep(1)
print(nport)
client = tcp.make_client()
tcp.client_connect(client,ip,nport)
while True:
    mess = tcp.rec(client, 1024)
    if(mess):
        print(mess)

The error is:

[WinError 10048]Only one usage of each socket address (protocol/network address/port) is normally permitted Python

Feel free to change anything you want. If you need any info in plus just ask.

Upvotes: 0

Views: 6258

Answers (1)

Gil Hamilton
Gil Hamilton

Reputation: 12347

You are creating a socket in the client with tcp.make_client. You are then using that socket to connect to the server via tcp.client_connect. Presumably you successfully receive the new port number back from the server. But then you are trying to re-use the same socket to connect to those ports.

This is the proximate cause of your error: A socket can only be used for a single TCP connection. If you want to create a new connection, you must first create a new socket.

That being said, if you are simply trying to create a server that will accept multiple connections, you're making it way too complicated. The server can receive any number of connections on its single listening port, as long as a different address/port combination is used by each client.

One way to structure this in a server is something like this:

# Create and bind listening socket
lsock = socket.socket()
lsock.bind(('', port))
lsock.listen(1)
while True:    
    csock, addr = lsock.accept()
    print("Got connection from {}".format(addr))

    # Start sub-process passing it the newly accepted socket as argument
    subs = Process(target=start, args=(csock, ))
    subs.start()

    # Close our handle to the new socket (it will remain open in the 
    # sub-process which will use it to talk to the client)
    csock.close()

    # NOTE: do not call subs.join here unless you want the parent to *block* 
    # waiting for the sub-process to finish (and if so, what is the point in 
    # creating a sub-process?)

There are several others ways to do it as well: you can create multiple threads to handle multiple connections, or you can handle all connections in a single thread by using select or with asynchronous I/O.

The client is typically much simpler -- as it usually only cares about its own one connection -- and doesn't care which way the server is implemented:

sock = socket.socket()
sock.connect((ip, port))
while True:
    sock.send(...)
    sock.recv(...)

If the client does wish to connect to the same server again, it simply creates a second socket and call its connect method with the same server IP and port.

Usually, the client never needs to specify its own port, only the server's port. It simply calls connect and the client-side operating system chooses an unused port for it. So the first time, the client creates a socket and connects it (to the server's listening port), the client-side OS may choose port 50001. The next time it creates and connects a socket, it may get 50002 and so on. (The exact port numbers chosen depend on the operating system implementation and other factors, such as what other programs are running and creating connections.)

So, given client IP 192.168.0.101 and server IP 192.168.0.102, and assuming the server is listening on port 8000, this would result in these two connections:

  • (192.168.0.101/50001) ====> (192.168.0.102/8000)
  • (192.168.0.101/50002) ====> (192.168.0.102/8000)

Upvotes: 3

Related Questions