欢迎访问宙启技术站
智能推送

使用Python的select函数实现简单的聊天室程序。

发布时间:2023-12-24 04:12:33

聊天室是一个多人在线聊天的平台,参与者可以发送消息、接收消息并与其他用户互动。我们可以使用Python的select函数来实现一个简单的聊天室程序。

首先,我们需要导入select模块和socket模块,用于创建网络套接字和处理连接。然后,我们创建一个Server类来管理聊天室服务器。

import select
import socket

class Server:
    def __init__(self, host, port):
        self.host = host
        self.port = port
        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((self.host, self.port))
        self.server_socket.listen(5)
        self.client_sockets = []
        self.inputs = [self.server_socket]

    def run(self):
        print(f"Server is running on {self.host}:{self.port}...")

        while True:
            readable, _, _ = select.select(self.inputs, [], [])
            for sock in readable:
                if sock == self.server_socket:
                    client_socket, client_address = self.server_socket.accept()
                    self.client_sockets.append(client_socket)
                    self.inputs.append(client_socket)
                    print(f"New connection from {client_address}")
                else:
                    try:
                        message = sock.recv(1024).decode()
                        if message:
                            self.broadcast(sock, message)
                    except:
                        self.remove_socket(sock)

    def broadcast(self, sender_sock, message):
        for client_socket in self.client_sockets:
            if client_socket != self.server_socket and client_socket != sender_sock:
                client_socket.send(message.encode())

    def remove_socket(self, sock):
        if sock in self.inputs:
            self.inputs.remove(sock)
        if sock in self.client_sockets:
            self.client_sockets.remove(sock)
        sock.close()

Server类的__init__方法中,我们创建了一个TCP服务器套接字并绑定到指定的主机和端口。然后,我们使用select函数监听套接字的可读事件。当有新的连接到来时,我们接受该连接并将客户端套接字添加到inputs列表中,以便可以监听其可读事件。当有数据通过套接字发送过来时,我们使用recv方法接收并将消息广播给所有客户端套接字(除了发送者)。

接下来,我们创建一个Client类来连接到聊天室服务器并发送/接收消息。

import select
import socket
import sys
import threading

class Client:
    def __init__(self, host, port):
        self.host = host
        self.port = port
        self.client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.client_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

    def connect(self):
        try:
            self.client_socket.connect((self.host, self.port))
            print("Connected to the server.")
            threading.Thread(target=self.receive).start()

            while True:
                message = input()
                if message:
                    self.client_socket.send(message.encode())
        except Exception as e:
            print(f"Connection failed: {e}")
            sys.exit()

    def receive(self):
        while True:
            try:
                readable, _, _ = select.select([self.client_socket], [], [])
                if self.client_socket in readable:
                    message = self.client_socket.recv(1024).decode()
                    if not message:
                        print("Disconnected from the server.")
                        sys.exit()
                    else:
                        print(message)
            except (KeyboardInterrupt, SystemExit):
                sys.exit()

if __name__ == '__main__':
    if len(sys.argv) != 3:
        print("Usage: python chatroom.py <host> <port>")
        sys.exit()

    client = Client(sys.argv[1], int(sys.argv[2]))
    client.connect()

Client类的__init__方法中,我们创建一个TCP客户端套接字。在connect方法中,我们尝试连接到指定的主机和端口,并在成功连接后创建一个新线程来接收服务器发送的消息。然后,我们使用input函数从终端获取用户输入的消息,并使用send方法发送到服务器。在receive方法中,我们使用recv方法接收服务器发送的消息,并将其打印到终端。

运行聊天室程序的例子:

1. 启动服务器:

server = Server('localhost', 5000)
server.run()

2. 运行客户端(至少两个客户端):

client1 = Client('localhost', 5000)
client1.connect()

client2 = Client('localhost', 5000)
client2.connect()

3. 在客户端终端输入消息进行聊天。消息将被广播到其他客户端。

这是一个简单的基于select函数的聊天室程序示例。但请注意,此示例基于单线程,可能无法处理大量客户端连接和高并发情况。在实际应用中,您可能需要使用多线程或异步框架来处理更复杂的场景。