1

I am trying to build a simple server-client model to do the file transfer task. My server.py and client.py look like this:

<Server.py>
import socket

s = socket.socket()
host = socket.gethostname()
port = 1717
s.bind((host, port))
s.listen(1)
print(host)
print("Waiting for the client ...")

conn, addr = s.accept()
print(addr, "Connected!")

filename = "My file name"
file = open(filename, 'rb')
file_data = file.read(2048)
conn.send(file_data)
print("File has been sent to server.")
s.close()
<Client.py>
import socket
import time

time.sleep(3)

s = socket.socket()
host = "ubuntu"
port = 1717
s.connect((host, port))
print("Connected ....")

filename = "My file name"
file = open(filename, 'wb')
file_data = s.recv(2048)
file.write(file_data)
file.close()
print("File has been received.")

Also, I wrote a shell file to run the server and client, because I can only get no error if the server runs before the client, I wrote in my shell script something like this:

python3 ./some_path/server.py &
python3 ./some_path/client.py $n

Notice that I also added the time.sleep(3) at the beginning of my Client.py because I found the shell script command I wrote does not guarantee that server runs first. Now this problem is resolved, however, I am getting the 'Adress already in use' error because of s.bind() in the server.py every time I want to run the whole thing for the second time. That's saying, If I open my Ubuntu, and run the shell script, it worked and everything is fine as expected. But when it's done and I want to run again, I would get the 'Adress already in use'.

So my questions are:

  1. How to solve this, so that I test the functionalities without rebooting the whole computer.

  2. Are there any more sophisticated way to make client.py always run after the server.py than my time.sleep() way?

  3. Are there any more sophisticated ways to get the hostname instead of specifying in advance? As you can see from the client.py I basically set the host to "ubuntu" because that's what I get if I print the hostname from the server-side.

Thank you so much for reading these long questions...I just want to make things more clear... Much appreciated it if you can answer any one of my questions or even give some suggestions. By the way, I am testing all these on a ubuntu 14.04 machine.

Jim Simson
  • 2,774
  • 3
  • 22
  • 30
Haoran Bai
  • 21
  • 2

3 Answers3

1

Firstly you need to close the socket in the client as well. Secondly you should call shutdown before closing the socket.

Please see this https://stackoverflow.com/a/598759/6625498

ekhanad
  • 154
  • 2
  • 8
0
  1. Try to reboot entirely the system. It may means that the process still running.
0
  1. How to solve this, so that I test the functionalities without rebooting the whole computer.

    Please run this command on the shell script if you get the this message "Adress already in use"

    sudo killall -9 python3

    And then run your server and client.

  2. Are there any more sophisticated way to make client.py always run after the server.py than my time.sleep() way

Please use this codes.

server.py

import socket
import threading
import socketserver

socketserver.TCPServer.allow_reuse_address = True

__all__ = ['server']


class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler):
    def handle(self):
        cur_thread = threading.current_thread()
        requests = self.server.requests
        if self.request not in requests:
            requests[self.request] = {'client_id': cur_thread.ident,
                                      'client_address': self.client_address[0],
                                      'client_port': self.client_address[1]}

            if callable(self.server.onConnected):
                self.server.onConnected(self.request, self.server)
        while True:
            try:
                buffer = self.request.recv(my_constant.MSG_MAX_SIZE)
                if not buffer:
                    break
                buffer = str(binascii.hexlify(buffer))
                buffer = [buffer[i:i + 2] for i in range(2, len(buffer) - 1, 2)]

                self.server.onData(buffer, self.server, self.request) # process receive function
            except socket.error:
                print(str(socket.error))
                break
        if callable(self.server.onDisconnected) and (self.request in requests):
            self.server.onDisconnected(self.request, self.server)
        self.request.close()


class server(socketserver.ThreadingTCPServer):
    def __init__(self, host='', port=16838, *args, **kwargs):
        socketserver.ThreadingTCPServer.__init__(self, (host, port), ThreadedTCPRequestHandler)
        self.requests = {}
        self.server_thread = threading.Thread(target=self.serve_forever)
        self.server_thread.setDaemon(True)
        self.server_thread.start()
        self.onConnected = None
        self.onDisconnected = None
        self.onData = None

    def stop(self):
        self.quote_send_thread_stop = True

        for request in list(self.requests):
            self.shutdown_request(request)
            if self.onDisconnected:
                self.onDisconnected(request, self)
        self.shutdown()
        self.server_close()

    def broadcast(self, data):
        for request in list(self.requests):
            try:
                request.sendall(data)
            except socket.error:
                print(str(socket.error))
                del self.requests[request]

    def send(self, request, data):
        try:
            request.sendall(data)
        except socket.error:
            print(str(socket.error))
            del self.requests[request]

    def sendRaw(self, client_id, data):
        pass

    def disconnect(self, client_id):
        for request in list(self.requests):
            if client_id == self.requests[request]['client_id']:
                self.shutdown_request(request)
                if self.onDisconnected:
                    self.onDisconnected(request, self)
                else:
                    del self.requests[request]

def onConnected(request, server):
    try:
        print('[onConnected] client_address: ' + str(server.requests[request]))
    except Exception as e:
        print(str(e))

def onDisconnected(request, server):
    try:
        print('[onDisconnected] client_address: ' + str(server.requests[request]))
        del server.requests[request]
    except Exception as e:
        print(str(e))
def onData(request, server):
    #define your process message
    pass

main.py

his_server = server.server(sever_host, sever_port)
his_server.onConnected = server.onConnected
his_server.onDisconnected = server.onDisconnected
his_server.onData = server.onData

client.py

import socket
import time
from common.constant import *
from threading import Thread
import binascii
from .packet import *
import threading


def recv_msg(sock):
    while True:
        try:
            res = sock.recv(buf_size)
            if not res:
                continue
            buffer = str(binascii.hexlify(res))
            buffer = [buffer[i:i + 2] for i in range(2, len(buffer) - 1, 2)]

            #packet parsing, you maybe change this part.
            packet_parsing(buffer)
            time.sleep(0.100)
        except socket.error:
            print(str(socket.error))
            break

class history_thread(threading.Thread):
    def __init__(self, threadID, name, delay, server, port):
        threading.Thread.__init__(self)
        self.threadID = threadID
        self.name = name
        self.delay = delay
        self.server = server
        self.port = port
        self.sock = None
    def run(self):
        print("Starting " + self.name)

        while True:
            try:
                self.sock = socket.socket()
                self.sock.connect((self.server, self.port))

                tc = Thread(target=recv_msg, args=(self.sock,))
                tc.start()
                threads = []
                threads.append(tc)
                for pip in threads:
                    pip.join()
                self.sock.close()
                self.sock = None
            except socket.error:
                print(str(socket.error))
                if self.sock is not None:
                    self.sock.close()
                self.sock = None
            time.sleep(self.delay)

    def send(self, data):
        if self.sock is None:
            return -1
        try:
            self.sock.sendall(data)
        except:
            print(str(socket.error))
Xilin Zang
  • 94
  • 5
  • It is not necessary to kill every Python 3 process in the entire operating system to resolve 'address already in use', and in fact it may not be sufficient either. – user207421 Nov 26 '19 at 00:57
  • I mean that is necessary in his code, And then please check my server code.In my server code, you will find the allow_reuse_address flag.I am not sure why you reduce my reputation. – Xilin Zang Nov 26 '19 at 01:01
  • It is not necessary in any code, and *especially* if you've set `allow_reuse_address`. You don't know who 'reduced your reputation'. – user207421 Nov 26 '19 at 01:04
  • You don't understand me. in his case, in order to fix his issue as soon as possible wtihout restarting host, my suggest is good way for him. – Xilin Zang Nov 26 '19 at 01:07