【问题标题】:Not recieving data python socktes不接收数据python套接字
【发布时间】:2020-09-24 06:37:31
【问题描述】:

我正在使用 python 创建一个简单的聊天室服务器,当我使用它发送数据时,我没有收到它。该代码一直有效,直到我使用函数和类将其分开。我这样做是为了添加 UI 会更简单

这是我的服务器端代码:

import socket
import select
from tkinter import *
import threading

HEADER_LENGTH = 10
IP = socket.gethostbyname('0.0.0.0')
PORT = 1234

class ServerNoGui():

    def __init__(self):
        self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

        self.server_socket.bind((IP, PORT))
        self.server_socket.listen()

        self.sockets_list = [self.server_socket]

        self.clients = {}

        print("server started")
        print("Starting thread sub-proccesses...")
        acceptLoop = threading.Thread(target=self.acceptUsers)
        acceptLoop.start()
        recieveLoop = threading.Thread(target=self.manageDataSending)
        recieveLoop.start()
        print("sub-proccesses started!")


    def recieve_message(self, client_socket):
        message_header = client_socket.recv(HEADER_LENGTH)

        if not len(message_header):
            return False

        message_length = int(float(message_header.decode('utf-8').strip()))
        return {'header': message_header, 'data': client_socket.recv(message_length)}

    def acceptUsers(self):
        read_sockets, _x_, exception_sockets = select.select(self.sockets_list, [], self.sockets_list) 

        for notified_socket in read_sockets:
            if notified_socket == self.server_socket:
                client_socket, client_address = self.server_socket.accept()
                print("accepted")

                user = self.recieve_message(client_socket)

                #print(user)
                print("Recieved")

                if(not user):
                    continue

                self.sockets_list.append(client_socket)
                print("added to list")

                self.clients[client_socket] = user
                print("created user")

                print(f"Accepted connection from {client_address[0]}{client_address[1]} username: {user['data'].decode('utf-8')}")

    def manageDataSending(self):
        while True:
            read_sockets, _x_, exception_sockets = select.select(self.sockets_list, [], self.sockets_list)  
            print("point")
            for notified_socket in read_sockets:
                if notified_socket == self.server_socket:
                    print("point 0")
                    self.acceptUsers()
                else:
                    print("point 1")
                    message = self.recieve_message(notified_socket)

                    if(message is False):
                        print(f"Closed connection from {self.clients[notified_socket]['data'].decode('utf-8')}")
                        self.sockets_list.remove(notified_socket)
                        del self.clients[notified_socket]
                        continue

                    else:
                        user = self.clients[notified_socket]

                        type_, data = message['data'].decode("utf-8").split("$")


                        if(type_ == "message"):
                            print(f"Recieved Message from {user['data'].decode('utf-8')} : {message['data'].decode('utf-8')} of type {type_}")
                            for client_socket in self.clients:

                                if client_socket != notified_socket:
                                    client_socket.send(user['header'] + user['data'] + message['header'] + message['data'])

            for notified_socket in exception_sockets:
                sockets_list.remove(notified_socket)
                del clients[notified_socket]    
                print(f"Closed connection from {clients[notified_socket]['data'].decode('utf-8')}")

class serverGUI():
    def __init__():
        window = Tk()
        window.title(f"Chatt.py HOSTING SERVER (IP : {IP} \\\\ HOST : {HOST})")

    def createWidgets(self):
        return False

    def log(self, data):
        return False

    def loop(self):
        window.mainloop()



serverBackend = ServerNoGui()

这是客户

import socket
import select
import errno
import sys


HEADER_LENGTH = 10

IP = socket.gethostbyname("0.0.0.0")#'192.168.0.40' 
PORT = 1234

my_username = input("Username: ")
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.connect((IP, PORT))
client_socket.setblocking(False)

username = my_username.encode("utf-8");
username_header = f"{len(username):<{HEADER_LENGTH}}".encode("utf-8")

client_socket.send(username_header + username)

while True:
    messageInput = input(f"Me({my_username}) > ")
    message = f"message${messageInput}"

    if(message):
        message = message.encode("utf-8")
        message_header = f"{len(message):<{HEADER_LENGTH}}".encode("utf-8")
        client_socket.send(message_header + message)
        print(f"sent {message_header} : {message}")

    try:
        while True:
            username_header = client_socket.recv(HEADER_LENGTH)
            if(not len(username_header)):
                print("connection closed by server")
                sys.exit()
            username_lenght = int(username_header.decode("utf-8").strip())

            username = client_socket.recv(username_lenght).decode("utf-8")

            message_header = client_socket.recv(HEADER_LENGTH)
            message_length = int(message_header.decode("utf-8").strip())
            messageRaw = client_socket.recv(message_length).decode("utf-8")
            type_, message = messageRaw.split("$")
            if(type_ == message):
                print(f"{username} >> {message}")

    except IOError as e:
        if(e.errno != errno.EAGAIN and e.errno != errno.EWOULDBLOCK):
            print("READ ERR",str(e))
            sys.exit()
        continue

    except Exception as e:
        print("Error".str(e))
        sys.exit()

我决定尝试两个客户端我得到以下输出 服务器:

server started
Starting thread sub-proccesses...
sub-proccesses started!
point
point 0
accepted
Recieved
added to list
created user
Accepted connection from 127.0.0.160338 username: test1
point
point 0
accepted
Recieved
added to list
created user
Accepted connection from 127.0.0.160340 username: test2
point
point 1
Recieved Message from test2 : message$hello of type message
point
point 1
Recieved Message from test1 : message$ of type message
point
point 1
Recieved Message from test1 : message$hello of type message

客户端1:

Username: test1
Me(test1) > 
sent b'8         ' : b'message$'
Me(test1) > hello
sent b'13        ' : b'message$hello'

客户端2:

Username: test2
Me(test2) > hello
sent b'13        ' : b'message$hello'

如您所见,消息由服务器发送和接收,但未显示(我不傻,我按了几次回车键)。

【问题讨论】:

    标签: python python-3.x sockets server


    【解决方案1】:

    您的服务器代码令人困惑,可能没有按照您的想法进行。首先,您创建一个线程来接受将acceptUsers 作为其线程函数的连接(将此线程称为A)。然而,该函数只会在该线程中运行一次,然后它会在访问完所有read_sockets 后退出(因为没有while True 循环)。

    其次,您的另一个线程 (B) 正在 manageDataSending 中运行——也正在执行 select,但是当客户端连接时,它调用 acceptUsers .这意味着在第一次连接到您的服务器时,两个线程之间存在“竞争”。接下来会发生什么值得怀疑,因为现在两者都注定要或多或少同时执行acceptUsers 代码,因此两个线程中的确切操作顺序现在是不确定的。

    线程 A 可能先运行,处理 server_socket(接受连接 进行接收)并在线程 B 在acceptUsers 中输入select 调用。这将使线程Bselect(在acceptUsers)中等待,直到下次客户端连接或发送数据。

    另一方面,线程 A 和线程 B 都可能通过 acceptUsers 中的 select 并都执行 accept 调用。然后accept 将在一个中成功,并在另一个中阻塞,等待后续传入连接。在任何一种情况下,您的线程 B 最终都会在代码中您没想到的地方被阻塞。

    底线:没有明显的理由让您拥有两个单独的线程,都执行select 调用。如果只创建一个线程,并让它在一个地方执行你的套接字select,让那个地方处理传入连接和传入客户端数据的套接字通知,将会更简单、更容易理解发生了什么。

    还有一点需要注意:您实际上并不需要单独处理exception_sockets。如果您的一个客户离开了,它在read_sockets 列表中的条目将被标记为“ready-to-read”,当您尝试读取它时,您将得到一个文件结束指示(即零长度缓冲区返回)。

    【讨论】:

    • 非常感谢,我显然对线程很陌生,我想通了,但我很困惑为什么它会起作用,所以这非常有用,并且该注释有助于提高代码效率。我整晚都在努力修复这个错误,所以谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-04-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-07
    • 1970-01-01
    相关资源
    最近更新 更多