【问题标题】:socket.sock().bind() Address already in usesocket.sock().bind() 地址已经在使用中
【发布时间】:2019-11-25 23:22:44
【问题描述】:

我正在尝试构建一个简单的服务器-客户端模型来执行文件传输任务。我的 server.py 和 client.py 看起来像这样:

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

另外,我写了一个shell文件来运行服务器和客户端,因为如果服务器在客户端之前运行,我只能得到没有错误,我在我的shell脚本中写了这样的内容:

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

请注意,我还在 Client.py 的开头添加了 time.sleep(3),因为我发现我编写的 shell 脚本命令不能保证服务器首先运行。现在这个问题已经解决了,但是,每次我想第二次运行整个过程时,我都会因为 server.py 中的 s.bind() 而收到“地址已在使用”错误。 也就是说,如果我打开我的 Ubuntu 并运行 shell 脚本,它就可以工作并且一切都按预期进行。但是当它完成并且我想再次运行时,我会得到“地址已在使用中”。

所以我的问题是:

  1. 如何解决这个问题,这样我就可以在不重新启动整个计算机的情况下测试功能。

  2. 有没有比我的 time.sleep() 方式更复杂的方法让 client.py 始终在 server.py 之后运行?

  3. 有没有更复杂的方法来获取主机名而不是提前指定?正如您从 client.py 中看到的,我基本上将主机设置为“ubuntu”,因为如果我从服务器端打印主机名,就会得到这样的结果。

非常感谢您阅读这些冗长的问题...我只是想让事情更清楚... 如果您能回答我的任何一个问题,甚至提出一些建议,我们将不胜感激。 顺便说一句,我正在 ubuntu 14.04 机器上测试所有这些。

【问题讨论】:

  • 绑定前需要在监听socket上设置SO_REUSEADDR。
  • 它确实有帮助!谢谢。

标签: python linux shell sockets ubuntu-14.04


【解决方案1】:

首先,您还需要关闭客户端中的套接字。 其次,您应该在关闭套接字之前调用shutdown。

请看这个https://stackoverflow.com/a/598759/6625498

【讨论】:

  • 您不需要在关闭套接字之前调用shutdown(),并且您的链接没有另外说明。
【解决方案2】:
  1. 尝试完全重新启动系统。 这可能意味着该进程仍在运行。

【讨论】:

    【解决方案3】:
    1. 如何解决这个问题,以便我在不重新启动整个计算机的情况下测试功能。

      如果您收到此消息“地址已在使用中”,请在 shell 脚本上运行此命令

      sudo killall -9 python3

      然后运行你的服务器和客户端。

    2. 有没有比我的 time.sleep() 方式更复杂的方法让 client.py 始终在 server.py 之后运行

    请使用此代码。

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

    【讨论】:

    • 没有必要杀掉整个操作系统中的每一个Python 3进程来解析'address already in use',事实上也可能不够。
    • 我的意思是在他的代码中是必需的,然后请检查我的服务器代码。在我的服务器代码中,你会发现allow_reuse_address标志。我不知道你为什么降低我的声誉。
    • 在任何代码中都不需要,尤其是如果你设置了allow_reuse_address。你不知道是谁“降低了你的声誉”。
    • 你不懂我。在他的情况下,为了在不重启主机的情况下尽快解决他的问题,我的建议对他来说是个好方法。
    猜你喜欢
    • 1970-01-01
    • 2017-04-21
    • 2017-11-01
    • 2016-03-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-12
    • 2021-10-21
    相关资源
    最近更新 更多