python制作websocket私人聊天室


装好python环境直接就用 运行pyhton3 ./client.py 访问地址xxxx:5001

python代码

提示:这里可以添加技术概要

# -*- coding: utf-8 -*-

import socket
import threading
import json
from flask import Flask, render_template, request, redirect, url_for, session
from flask_socketio import SocketIO, emit
from gevent import monkey

# 修复阻塞问题
monkey.patch_all()

# 初始化 Flask 和 SocketIO
app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret!'
socketio = SocketIO(app, async_mode="gevent", cors_allowed_origins="*")

# 用于存储客户端发送的消息
messages = []

# 用户登录信息(账号:密码)
user_credentials = {
    "xxx": "123456",
	"xxx1": "123456"
}

# 聊天页面路由
@app.route('/')
def login_page():
    """登录页面"""
    return render_template('login.html')

@app.route('/login', methods=['POST'])
def login():
    """处理用户登录"""
    username = request.form.get('username')
    password = request.form.get('password')

    # 校验用户名和密码
    if username in user_credentials and user_credentials[username] == password:
        session['username'] = username  # 将用户名存入会话
        return redirect(url_for('chat_page'))  # 跳转到聊天页面
    else:
        return "登录失败,用户名或密码错误!<a href='/'>返回</a>"

@app.route('/chat')
def chat_page():
    """聊天页面"""
    if 'username' in session:
        return render_template('chat.html', username=session['username'])
    else:
        return redirect(url_for('login_page'))

@app.route('/logout')
def logout():
    """登出用户"""
    session.pop('username', None)
    return redirect(url_for('login_page'))

# WebSocket 事件监听
@socketio.on('connect')
def on_connect():
    """处理用户连接事件"""
    username = session.get('username')
    if username:
        print(f"用户 {username} 已连接到 Web 页面")
        # 将历史消息发送给登录用户
        emit('chat_history', messages)
    else:
        print("未登录用户尝试连接")
        # 断开未登录用户的连接
        emit('unauthorized', {'message': '请先登录!'})
        return False  # 断开连接

@socketio.on('send_message')
def handle_send_message(data):
    """处理用户发送的消息"""
    username = session.get('username')
    if username:
        message = data.get('message', '')
        if message:
            print(f"收到消息: {message} 来自用户: {username}")
            # 保存消息
            msg_data = {'username': username, 'message': message}
            messages.append(msg_data)  # 将消息存储到历史记录
            # 广播消息到所有用户
            socketio.emit('new_message', msg_data)
    else:
        emit('unauthorized', {'message': '未登录用户不能发送消息!'})

# 广播消息到页面
def broadcast_message(msg, ip_port):
    """广播 TCP 服务端接收到的消息"""
    data = f"{ip_port}: {msg}"
    messages.append(data)
    socketio.emit('new_message', {'message': data})

# 处理客户端的请求操作
def handle_client_request(service_client_socket, ip_port):
    """处理 TCP 客户端的请求"""
    try:
        while True:
            recv_data = service_client_socket.recv(1024)
            if recv_data:
                # 检测是否为 HTTP CONNECT 请求
                if recv_data.startswith(b"CONNECT") or b"HTTP" in recv_data:
                    print(f"检测到 HTTP CONNECT 请求,来自 {ip_port}")
                    service_client_socket.send("不支持的请求类型".encode("utf-8"))
                    service_client_socket.close()
                    return

                # 尝试解码数据
                try:
                    message = recv_data.decode("utf-8")
                    print(f"收到消息: {message} 来自 {ip_port}")
                    # 如果数据是 JSON 格式,可以尝试加载
                    try:
                        data = json.loads(message)
                        broadcast_message(data.get('message', '未知消息'), ip_port)
                    except json.JSONDecodeError:
                        # 如果不是 JSON 格式,直接广播
                        broadcast_message(message, ip_port)

                    # 回复客户端
                    service_client_socket.send("消息已接收并显示在页面上".encode("utf-8"))
                except UnicodeDecodeError:
                    print(f"收到无法解码的数据,来自 {ip_port}: {recv_data}")
                    service_client_socket.send("无法解码的消息".encode("utf-8"))
            else:
                print("客户端下线:", ip_port)
                break
    except Exception as e:
        print(f"处理客户端请求时发生错误,来自 {ip_port}: {e}")
    finally:
        service_client_socket.close()

# 启动 TCP 服务端线程
def start_tcp_server():
    """启动 TCP 服务端线程"""
    tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
    tcp_server_socket.bind(("", 8081))
    tcp_server_socket.listen(128)
    print("TCP 服务端已启动,等待客户端连接...")
    while True:
        service_client_socket, ip_port = tcp_server_socket.accept()
        print("客户端连接成功:", ip_port)
        sub_thread = threading.Thread(target=handle_client_request, args=(service_client_socket, ip_port))
        sub_thread.setDaemon(True)
        sub_thread.start()

# 启动服务
if __name__ == '__main__':
    # 启动 TCP 服务端线程
    threading.Thread(target=start_tcp_server, daemon=True).start()
    # 启动 Flask Web 服务
    socketio.run(app, host='0.0.0.0', port=5001)

页面代码

chat.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>聊天页面</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.6.0/socket.io.js"></script>
    <style>
        body {
            font-family: Arial, sans-serif;
            background-color: #f3f4f6;
            margin: 0;
            padding: 0;
            display: flex;
            flex-direction: column;
            align-items: center;
            height: 100vh;
        }

        h1 {
            margin-top: 20px;
            color: #333;
        }

        #chat-box {
            background-color: #ffffff;
            border: 1px solid #ccc;
            border-radius: 8px;
            width: 80%;
            max-width: 600px;
            height: 400px;
            overflow-y: auto;
            padding: 15px;
            box-sizing: border-box;
            margin-top: 20px;
        }

        #chat-box p {
            margin: 5px 0;
            padding: 8px;
            background-color: #f3f3f3;
            border-radius: 4px;
            box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
        }

        #chat-form {
            margin-top: 20px;
            display: flex;
            justify-content: center;
            width: 80%;
            max-width: 600px;
        }

        #message {
            flex: 1;
            padding: 10px;
            font-size: 16px;
            border: 1px solid #ccc;
            border-radius: 4px;
            box-sizing: border-box;
        }

        button {
            padding: 10px 20px;
            font-size: 16px;
            border: none;
            border-radius: 4px;
            background-color: #4CAF50;
            color: white;
            margin-left: 10px;
            cursor: pointer;
            transition: background-color 0.3s;
        }

        button:hover {
            background-color: #45a049;
        }
    </style>
</head>
<body>
    <h1>欢迎,{{ username }}</h1>
    <div id="chat-box">
        <!-- 消息内容将动态加载到这里 -->
    </div>
    <form id="chat-form">
        <input type="text" id="message" placeholder="输入消息" required>
        <button type="submit">发送</button>
    </form>
    <script>
        const socket = io.connect();

        // 加载历史消息
        socket.on('chat_history', function(messages) {
            const chatBox = document.getElementById('chat-box');
            messages.forEach(msg => {
                chatBox.innerHTML += `<p><strong>${msg.username}:</strong> ${msg.message}</p>`;
            });
        });

        // 显示新消息
        socket.on('new_message', function(data) {
            const chatBox = document.getElementById('chat-box');
            chatBox.innerHTML += `<p><strong>${data.username}:</strong> ${data.message}</p>`;
            chatBox.scrollTop = chatBox.scrollHeight; // 滚动到底部
        });

        // 发送消息
        document.getElementById('chat-form').addEventListener('submit', function(e) {
            e.preventDefault();
            const message = document.getElementById('message').value.trim();
            if (message) {
                socket.emit('send_message', { message });
                document.getElementById('message').value = ''; // 清空输入框
            }
        });
    </script>
</body>
</html>

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>聊天页面</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.5.4/socket.io.min.js"></script>
    <style>
        body {
            font-family: Arial, sans-serif;
            background-color: #f4f4f9;
            margin: 0;
            padding: 0;
        }
        #messages {
            margin: 20px;
            padding: 10px;
            background: #fff;
            border-radius: 5px;
            box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
            max-height: 60vh;
            overflow-y: auto;
        }
        .message {
            margin: 5px 0;
            padding: 10px;
            background: #f1f1f1;
            border-radius: 5px;
        }
        .message .sender {
            font-weight: bold;
        }
        .login, .send-message {
            margin: 20px;
            padding: 10px;
            background: #fff;
            border-radius: 5px;
            box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
        }
        .login input, .send-message input {
            margin: 5px 0;
            padding: 5px;
            width: calc(100% - 12px);
        }
        .login button, .send-message button {
            margin-top: 10px;
            padding: 5px 10px;
        }
        .current-user {
            text-align: center;
            font-size: 18px;
            margin-top: 10px;
            font-weight: bold;
        }
    </style>
</head>
<body>
    <h1 style="text-align: center;">聊天页面</h1>

    <!-- 显示当前用户 -->
    <div class="current-user" id="currentUser"></div>

    <!-- 登录模块 -->
    <div class="login">
        <h3>登录</h3>
        <input type="text" id="username" placeholder="请输入用户名" />
        <button onclick="login()">登录</button>
    </div>

    <!-- 消息区域 -->
    <div id="messages"></div>

    <!-- 发送消息模块 -->
    <div class="send-message" style="display: none;">
        <h3>发送消息</h3>
        <input type="text" id="messageInput" placeholder="请输入消息" />
        <button onclick="sendMessage()">发送</button>
    </div>

    <script>
        let username = '';
        const socket = io('http://172.18.1.26:5001/');

        // 显示当前用户
        function updateCurrentUser() {
            const currentUserDiv = document.getElementById('currentUser');
            currentUserDiv.textContent = `当前用户:${username}`;
        }

        // 登录逻辑
        function login() {
            const usernameInput = document.getElementById('username');
            username = usernameInput.value.trim();
            if (username) {
                alert(`欢迎 ${username} 登录`);
                updateCurrentUser();
                document.querySelector('.login').style.display = 'none';
                document.querySelector('.send-message').style.display = 'block';
            } else {
                alert('请输入有效用户名');
            }
        }

        // 发送消息逻辑
        function sendMessage() {
            const messageInput = document.getElementById('messageInput');
            const message = messageInput.value.trim();
            if (message && username) {
                socket.emit('send_message', { username, message });
                messageInput.value = '';
            } else {
                alert('请先输入消息或登录');
            }
        }

        // 加载历史消息
        socket.on('chat_history', function (messages) {
            const messagesDiv = document.getElementById('messages');
            messages.forEach((data) => {
                const messageElement = document.createElement('div');
                messageElement.className = 'message';
                messageElement.innerHTML = `<span class="sender">${data.username}:</span> ${data.message}`;
                messagesDiv.appendChild(messageElement);
            });
            messagesDiv.scrollTop = messagesDiv.scrollHeight;
        });

        // 接收新消息
        socket.on('new_message1', function (data) {
            const messagesDiv = document.getElementById('messages');
            const messageElement = document.createElement('div');
            messageElement.className = 'message';
            messageElement.innerHTML = `<span class="sender">${data.username}:</span> ${data.message}`;
            messagesDiv.appendChild(messageElement);
            messagesDiv.scrollTop = messagesDiv.scrollHeight;
        });
    </script>
</body>
</html>

login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>登录</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            background-color: #f3f4f6;
            margin: 0;
            padding: 0;
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100vh;
        }

        .login-container {
            background-color: #ffffff;
            border-radius: 8px;
            box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
            padding: 30px;
            max-width: 400px;
            width: 100%;
            box-sizing: border-box;
            text-align: center;
        }

        .login-container h1 {
            margin-bottom: 20px;
            color: #333;
        }

        .login-container input[type="text"],
        .login-container input[type="password"] {
            width: 100%;
            padding: 10px;
            margin-bottom: 15px;
            border: 1px solid #ccc;
            border-radius: 4px;
            font-size: 16px;
            box-sizing: border-box;
        }

        .login-container button {
            width: 100%;
            padding: 10px;
            background-color: #4CAF50;
            color: white;
            font-size: 16px;
            border: none;
            border-radius: 4px;
            cursor: pointer;
            transition: background-color 0.3s;
        }

        .login-container button:hover {
            background-color: #45a049;
        }

        .login-container a {
            display: inline-block;
            margin-top: 15px;
            color: #007BFF;
            text-decoration: none;
        }

        .login-container a:hover {
            text-decoration: underline;
        }
    </style>
</head>
<body>
    <div class="login-container">
        <h1>登录</h1>
        <form action="/login" method="post">
            <input type="text" name="username" placeholder="用户名" required>
            <input type="password" name="password" placeholder="密码" required>
            <button type="submit">登录</button>
        </form>
        <a href="#">忘记密码?</a>
    </div>
</body>
</html>

小结

提示:这里可以添加总结
公司电脑不让登录微信或QQ,又不好拿着手机发消息的,自己买个云服务器带有公网ip的,把程序部署上去打开网页聊天去吧

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值