前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >TCP聊天服务器套接字|PyQt5+socket(TCP端口映射+端口放行)+logging+Thread(含日志,html)+anaconda打包32位exe(3.4万字)|python高阶

TCP聊天服务器套接字|PyQt5+socket(TCP端口映射+端口放行)+logging+Thread(含日志,html)+anaconda打包32位exe(3.4万字)|python高阶

作者头像
zmh-program
发布2023-02-06 09:51:22
8870
发布2023-02-06 09:51:22
举报

`TCP聊天服务器套接字v1.0`

目录

|模块

|测试

|端口映射

|端口放行

|云服务器

|代码讲解

[客户端]

·导入,定义

·socket

·logging

·Thread.threading

·datetime

·PyQt5

[服务端]

·socket

·PyQt5

 pyinstaller打包32位 anaconda 虚拟python系统

|全部代码(复制)


|模块

1.PyQt5 2.Thread(内置) 3.logging(内置) 4.socket(内置) 5.datetime + time(内置)

|测试

windows 11 64位

Python 3.8.6  [MSC v.1927 64 bit (AMD64)] on win32

PyQt5                     5.15.4 pyqt5-plugins             5.15.4.2.2 PyQt5-Qt5                 5.15.2 PyQt5-sip                 12.9.0 pyqt5-tools               5.15.4.3.2

|端口映射

选`TCP`(不选`UDP`)

我用的是花生k(主要的还是端口免费,其他的什么应该也行)看看官方文档就行了,没啥难的.

|端口放行

win10端口放行

选`TCP`

windows 11 和它差不多相同, 很长一段时间主机一直连不上花生指向地址,我还以为是他就不行,后来才知道是windows防火墙不让放行的,最终能在外网开了.

|云服务器

要想24小时能登服务器,连接这个套接字,一种是电脑一直开着,那样很吵,很耗电,风扇万一给干报废了,那不值得。所以有一种办法就是云上服务器,可几乎都是收费的.

|代码讲解

[客户端]

·导入,定义

`dicts` 为可以选择连接的IP地址字典, 使用时可以替换掉原先我用得三个地址

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

# Form implementation generated from reading ui files 'USER.ui', 'Connect.ui'
#
# Created by: PyQt5 UI code generator 5.15.4
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again.  Do not edit this file unless you know what you are doing.


from PyQt5 import QtCore, QtGui, QtWidgets
import socket, sys, logging
from traceback import format_exc
from datetime import datetime
from time import sleep
from threading import Thread

import logging  # 引入logging模块
logging.basicConfig(level=logging.DEBUG,format='%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s')
Username = 'zmh'
TIMEOUT = 3
IP = "114.67.206.19" 
bytecount = 1024
dicts = {f"{IP} (公网)" : {"ip":IP, "port":16223},
         "192.168.1.8 (私网)" : {"ip":"192.168.1.8","port":429},
         "EXAM-41 (微机室)" : {"ip":"EXAM-41","port":429}}

·socket

class Socket:
    def __init__(self,Function=lambda i:None,code='utf-8'):
        self.socket = socket.socket()
        self.code = code
        self._logger = Function
        self.socket.settimeout(TIMEOUT)
        self._connect = False
    def set_func(self, f):
        self._logger = f

    @to_logging
    def socket_connect(self):
        self.socket.connect(self.addr)
    def connect(self, ip = None,port:int=0000, show=None):
        self.addr = (ip, port)   
        if not self.socket_connect():
                show("[{}]: 连接服务器[{}]失败".format(get_time(),self.addr[0]))
                return False
        else:
                show("[{}]: 连接成功".format(get_time()))
                return True
        print(self.addr)
    def _handler(self):
            self.socket.send(Username.encode(self.code))
            while True:
                try:
                    byte = self.socket.recv(bytecount **2)
                    if len(byte) == 0:
                            break
                    kb = len(byte) / bytecount
                    self._logger(f'[{datetime.now().strftime("%H:%M:%S")}]{byte.decode(encoding=self.code)}                  {"<font size=1>%0.2f kb</font>" % kb}')
                except Exception as e:
                    if not type(e) == socket.timeout:
                        for n in ["","ERROR".center(20,"-")]+format_exc().split('\n')+["".center(20,"-"),""]:
                            self._logger(f"<font color='red'>{n}</font>")
                        self.socket.close()
                        return
    def run(self): #线程
        self._connect = True
        self.thread = threading(False, target=self._handler)

·logging

import logging  # 引入logging模块
logging.basicConfig(level=logging.DEBUG,format='%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s')
def to_logging(command):
    def logs(*args, **kwargs):
        try:
            command(*args, **kwargs)
        except Exception as e:
            if "main" in dir(): #main : Ui_MainWindow类
                main.Show_Message(format_exc())
            else:
                logging.exception(str())
            return False
        else:
            return True
    return logs

·Thread.threading

def threading(Daemon, **kwargs): 
        thread = Thread(**kwargs)
        thread.setDaemon(Daemon) #是否守护线程
        thread.start()
        return thread

·datetime

get_time = lambda: datetime.now().strftime('%Y %m %d %H:%M:%S')

·PyQt5

登录界面ui,可以选择连接的IP地址

class Ui_Dialog(object):
    def __init__(self):
        Dialog = QtWidgets.QDialog()
        self.Dialog = Dialog
        Dialog.setObjectName("Dialog")
        Dialog.resize(495, 81)
        self.gridLayout = QtWidgets.QGridLayout(Dialog)
        self.gridLayout.setObjectName("gridLayout")
        self.comboBox = QtWidgets.QComboBox(Dialog)
        self.comboBox.setObjectName("comboBox")
        self.comboBox.addItems(list(dicts.keys()))
        self.gridLayout.addWidget(self.comboBox, 0, 1, 1, 1)
        self.pushButton = QtWidgets.QPushButton(Dialog)
        self.pushButton.setObjectName("pushButton")
        self.gridLayout.addWidget(self.pushButton, 0, 2, 1, 1)
        self.label = QtWidgets.QLabel(Dialog)
        font = QtGui.QFont()
        font.setFamily("Consolas")
        self.label.setFont(font)
        self.label.setObjectName("label")
        self.gridLayout.addWidget(self.label, 0, 0, 1, 1)
        self.lineEdit = QtWidgets.QLineEdit(Dialog)
        self.lineEdit.setReadOnly(True)
        self.lineEdit.setObjectName("lineEdit")
        self.gridLayout.addWidget(self.lineEdit, 1, 0, 2, 3)

        self.retranslateUi(Dialog)
        self.pushButton.clicked.connect(self._connect)
        QtCore.QMetaObject.connectSlotsByName(Dialog)
        self.num = 0
    def retranslateUi(self, Dialog):
        _translate = QtCore.QCoreApplication.translate
        Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
        self.comboBox.setItemText(0, _translate("Dialog", list(dicts.keys())[0]))
        self.pushButton.setText(_translate("Dialog", "Connecting"))
        self.label.setText(_translate("Dialog", "Select Socket Connect Address:"))
        self.set_text("No return value.")
        Dialog.show()
    def set_text(self, m):
        self.lineEdit.setText(QtCore.QCoreApplication.translate("Dialog", str(m)))
        self.lineEdit.update()
    @to_logging
    def _connect(self, i):
        addr = dicts[self.comboBox.currentText()]
        self.set_text("[{}]: 尝试连接服务器[{}],最大超时报错 {}s".format(datetime.now().strftime('%Y %m %d %H:%M:%S'),addr["ip"],TIMEOUT))
        if s.connect(**addr, show=self.set_text):
            global main
            main = Ui_MainWindow()
            main.show()
            def close(widget):
                sleep(1)
                widget.close()
            threading(False, target=close, args=(self.Dialog, ))

主页ui

class Ui_MainWindow(object):
    def __init__(self):
        MainWindow = QtWidgets.QMainWindow()
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(800, 619)
        font = QtGui.QFont()
        font.setFamily("Consolas")
        MainWindow.setFont(font)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.gridLayout = QtWidgets.QGridLayout(self.centralwidget)
        self.gridLayout.setObjectName("gridLayout")
        self.lineEdit_3 = QtWidgets.QLineEdit(self.centralwidget)
        self.lineEdit_3.setReadOnly(True)
        self.lineEdit_3.setObjectName("lineEdit_3")
        self.gridLayout.addWidget(self.lineEdit_3, 7, 3, 1, 1)
        self.pushButton = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton.setStyleSheet("background-color:rgb(44, 176, 13);\n"
"color:rgb(255, 255, 255);\n"
"font: 200 10pt \"Consolas\";")
        self.pushButton.setObjectName("pushButton")
        self.gridLayout.addWidget(self.pushButton, 8, 6, 1, 1)
        spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
        self.gridLayout.addItem(spacerItem, 8, 5, 1, 1)
        self.label_2 = QtWidgets.QLabel(self.centralwidget)
        self.label_2.setObjectName("label_2")
        self.gridLayout.addWidget(self.label_2, 6, 1, 1, 1)
        spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
        self.gridLayout.addItem(spacerItem1, 8, 3, 1, 1)
        self.lineEdit_2 = QtWidgets.QLineEdit(self.centralwidget)
        self.lineEdit_2.setReadOnly(True)
        self.lineEdit_2.setObjectName("lineEdit_2")
        self.gridLayout.addWidget(self.lineEdit_2, 6, 3, 1, 1)
        self.label = QtWidgets.QLabel(self.centralwidget)
        self.label.setObjectName("label")
        self.gridLayout.addWidget(self.label, 5, 1, 1, 1)
        self.lineEdit = QtWidgets.QLineEdit(self.centralwidget)
        self.lineEdit.setCursor(QtGui.QCursor(QtCore.Qt.IBeamCursor))
        self.lineEdit.setDragEnabled(False)
        self.lineEdit.setReadOnly(True)
        self.lineEdit.setObjectName("lineEdit")
        self.gridLayout.addWidget(self.lineEdit, 5, 3, 1, 1)
        self.label_3 = QtWidgets.QLabel(self.centralwidget)
        self.label_3.setObjectName("label_3")
        self.gridLayout.addWidget(self.label_3, 7, 1, 1, 1)
        self.line = QtWidgets.QFrame(self.centralwidget)
        self.line.setFrameShape(QtWidgets.QFrame.VLine)
        self.line.setFrameShadow(QtWidgets.QFrame.Sunken)
        self.line.setObjectName("line")
        self.gridLayout.addWidget(self.line, 5, 4, 3, 1)
        self.textEdit = QtWidgets.QTextEdit(self.centralwidget)
        self.textEdit.setObjectName("textEdit")
        self.gridLayout.addWidget(self.textEdit, 5, 5, 3, 2)
        spacerItem2 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
        self.gridLayout.addItem(spacerItem2, 1, 1, 1, 1)
        self.textEdit_2 = QtWidgets.QTextEdit(self.centralwidget)
        self.textEdit_2.setObjectName("textEdit_2")
        self.textEdit_2.setReadOnly(True)
        self.gridLayout.addWidget(self.textEdit_2, 0, 3, 2, 4)
        self.pushButton_2 = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton_2.setObjectName("pushButton_2")
        self.gridLayout.addWidget(self.pushButton_2, 8, 1, 1, 1)
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 24))
        self.menubar.setObjectName("menubar")
        self.menu = QtWidgets.QMenu(self.menubar)
        self.menu.setObjectName("menu")
        self.menulanguage = QtWidgets.QMenu(self.menu)
        self.menulanguage.setObjectName("menulanguage")
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)
        self.actionsocket_connet = QtWidgets.QAction(MainWindow)
        self.actionsocket_connet.setObjectName("actionsocket_connet")
        self.actionChinese = QtWidgets.QAction(MainWindow)
        self.actionChinese.setObjectName("actionChinese")
        self.actionip_socket_gethostbyname_socket_gethostname = QtWidgets.QAction(MainWindow)
        self.actionip_socket_gethostbyname_socket_gethostname.setObjectName("actionip_socket_gethostbyname_socket_gethostname")
        self.menulanguage.addSeparator()
        self.menulanguage.addAction(self.actionChinese)
        self.menu.addSeparator()
        self.menu.addAction(self.menulanguage.menuAction())
        self.menu.addAction(self.actionip_socket_gethostbyname_socket_gethostname)
        self.menubar.addAction(self.menu.menuAction())
        self.socket_peername = s.addr[0]
        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)
        self.MainWindow = MainWindow
        self.pushButton.clicked.connect(self.send)
    @to_logging
    def sendmsg(self):
        data = self.textEdit.toPlainText().strip()
        if data:
            s.socket.send(data.encode('utf8'));self.textEdit.clear()
    @to_logging
    def send(self, i):
        if hasattr(s,"_connect") and s._connect:
            if not self.sendmsg():
                QtWidgets.QMessageBox.information(self.MainWindow, 'TraceBack',f'Socket Server<{self.socket_peername}> 断开连接')
                s._connect = False
        else:
            self.Show_Message("<font color='red'>发送异常. 未连接至服务器.</font>")
    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "Socket"))
        self.lineEdit_2.setText(socket.gethostname())
        self.lineEdit.setText(socket.gethostbyname(socket.gethostname()))
        self.lineEdit_3.setText(self.socket_peername)
        self.pushButton.setText(_translate("MainWindow", "send"))
        self.label_2.setText(_translate("MainWindow", "主机名:"))
        self.label.setText(_translate("MainWindow", "本地端口:"))
        self.label_3.setText(_translate("MainWindow", "连接端口:"))
        self.pushButton_2.setText(_translate("MainWindow", "搭建Socket"))
        self.menu.setTitle(_translate("MainWindow", "设置"))
        self.menulanguage.setTitle(_translate("MainWindow", "language"))
        self.actionsocket_connet.setText(_translate("MainWindow", "socket connect"))
        self.actionChinese.setText(_translate("MainWindow", "Chinese"))
        self.actionip_socket_gethostbyname_socket_gethostname.setText(_translate("MainWindow", "ip: "+socket.gethostbyname(socket.gethostname()) ))

        s.set_func(self.Show_Message)
        s.run()
    def show(self):
        self.MainWindow.show()
    def Show_Message(self, data):
        if data:
            for i in data.split('\n'):
                self.textEdit_2.append(i)
                print(i)

·主程序运行(PyQt5.QtWidgets.QApplication)

if __name__ == "__main__":
        app = QtWidgets.QApplication(sys.argv)
        s = Socket()
        conn = Ui_Dialog()
        sys.exit(app.exec_())

[服务端]

·socket

import socket # 导入 socket 模块
from threading import Thread
import logging
import serv #serv.py

def threading(Daemon, **kwargs):
        thread = Thread(**kwargs)
        thread.setDaemon(Daemon)
        thread.start()
        return thread

def debug(command):
    def logs(*args, **kwargs):
        try:
            command(*args, **kwargs)
        except Exception as e:
            print(e)

    return logs



logger = logging.getLogger(__name__)
logger.setLevel(level = logging.INFO)
handler = logging.FileHandler("log.txt")
handler.setLevel(logging.INFO)
handler.setFormatter(logging.Formatter("%(asctime)s - %(levelname)s - %(message)s"))
logger.addHandler(handler)
console = logging.StreamHandler()
console.setLevel(logging.INFO)
logger.addHandler(handler)
logger.addHandler(console)
bytecount = 1024
class Server(object):
    join_message = "<font color='red'>Server></font> <font color='blue'>%s</font> 连接服务器. 当前在线人数: <font color='red'>%s</font>"
    user_message = "<font color='%s'>%s(%s端)%s></font> %s"
    quit_message = "%s 下线"
    def __init__(self, addr, port, backlog = 10, encode = 'utf8'):
        self.address = addr, port
        self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.socket.bind(self.address)
        self.socket.listen(backlog)
        self.connect = {}
        self.encode = encode
        self.errs = []
    def run(self):
        logger.info("服务器[%s]开启,端口[%s]" % (socket.gethostbyname(socket.gethostname()), self.address[1]))
        self.accept_client()
    def _get_sockets(self): #return int
        return len(self.connect.items())
    def send(self, sock, user, mes):
        self.QUIT(user, lambda: sock.sendall(mes.encode(self.encode)))()
    def QUIT(self, user, command):
        sock = list(self.connect.keys())[list(self.connect.values()).index(user)]
        def logs(*args, **kargs):
            try:
                command(*args, **kargs)
            except:
                self.errs.append(sock)
        return logs
    def ServerMessage(self, mes):
        for sock, user in self.connect.items():
            if not sock in self.errs:
                self.send(sock, user, mes)
    def UserMessage(self, address, _user, mes):
        if not mes:
            return
        mes = mes.decode(encoding="utf8")
        for sock, user in self.connect.items():
            if not sock in self.errs:
                send_message = Server.user_message % ("brown" if _user == user else "red",
                                                      _user,
                                                      address,
                                                      "(我自己)" if _user == user else "",
                                                      mes)
                self.send(sock, user, send_message)
        logger.info(f"{address}[{_user}] : {mes}")
        self.error_handle()
    def error_handle(self):
        for sock in self.errs:
            sock.close()
            logger.exception(msg = str())
            Q = Server.quit_message % user
            logger.info(Q)
            self.connect.pop(sock)
            self.ServerMessage(Q)
    def accept_client(self):
      while True:
        client, address = self.socket.accept() # 阻塞,等待客户端连接
        thread = threading(Daemon=True, target=self.message_handle, args=(client,address[0]))

    def message_handle(self,client,address):
        username = client.recv(1024).decode(encoding='utf8')
        self.connect[client] = username
        logger.info(f"{address}[{username}] 加入服务器 , 当前人数 {self._get_sockets()}")
        self.ServerMessage(Server.join_message % (address, self._get_sockets()) )
        while True:
            try:
                self.UserMessage(address,username,client.recv(bytecount **2))
            except:
                pass
server = Server(socket.gethostname(),429)
server.run()
sys.exit(app.exec_())

因为socket.accept()为阻塞行为,所以使用多线程处理所用client用户

·PyQt5

serv.py

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

# Form implementation generated from reading ui file 'server.ui'
#
# Created by: PyQt5 UI code generator 5.15.4
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again.  Do not edit this file unless you know what you are doing.


from PyQt5 import QtCore, QtGui, QtWidgets
import sys

class Ui_MainWindow(object):
    def __init__(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(800, 685)
        font = QtGui.QFont()
        font.setFamily("Consolas")
        MainWindow.setFont(font)
        MainWindow.setStyleSheet("")
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.gridLayout_2 = QtWidgets.QGridLayout(self.centralwidget)
        self.gridLayout_2.setObjectName("gridLayout_2")
        self.formLayout = QtWidgets.QFormLayout()
        self.formLayout.setObjectName("formLayout")
        self.listView = QtWidgets.QListView(self.centralwidget)
        self.listView.setObjectName("listView")
        self.formLayout.setWidget(0, QtWidgets.QFormLayout.SpanningRole, self.listView)
        self.label_2 = QtWidgets.QLabel(self.centralwidget)
        self.label_2.setObjectName("label_2")
        self.formLayout.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.label_2)
        self.lineEdit = QtWidgets.QLineEdit(self.centralwidget)
        self.lineEdit.setObjectName("lineEdit")
        self.formLayout.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.lineEdit)
        self.lcdNumber = QtWidgets.QLCDNumber(self.centralwidget)
        self.lcdNumber.setObjectName("lcdNumber")
        self.formLayout.setWidget(2, QtWidgets.QFormLayout.FieldRole, self.lcdNumber)
        self.label_3 = QtWidgets.QLabel(self.centralwidget)
        self.label_3.setObjectName("label_3")
        self.formLayout.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.label_3)
        self.gridLayout_2.addLayout(self.formLayout, 2, 0, 1, 1)
        self.groupBox = QtWidgets.QGroupBox(self.centralwidget)
        self.groupBox.setObjectName("groupBox")
        self.gridLayout = QtWidgets.QGridLayout(self.groupBox)
        self.gridLayout.setObjectName("gridLayout")
        spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
        self.gridLayout.addItem(spacerItem, 1, 0, 1, 1)
        self.textEdit_2 = QtWidgets.QTextEdit(self.groupBox)
        self.textEdit_2.setObjectName("textEdit_2")
        self.gridLayout.addWidget(self.textEdit_2, 0, 0, 1, 2)
        self.pushButton = QtWidgets.QPushButton(self.groupBox)
        self.pushButton.setObjectName("pushButton")
        self.gridLayout.addWidget(self.pushButton, 1, 1, 1, 1)
        self.gridLayout_2.addWidget(self.groupBox, 3, 0, 1, 1)
        self.label = QtWidgets.QLabel(self.centralwidget)
        self.label.setObjectName("label")
        self.gridLayout_2.addWidget(self.label, 0, 0, 1, 1)
        self.label_4 = QtWidgets.QLabel(self.centralwidget)
        self.label_4.setObjectName("label_4")
        self.gridLayout_2.addWidget(self.label_4, 1, 2, 1, 1)
        self.label_5 = QtWidgets.QLabel(self.centralwidget)
        font = QtGui.QFont()
        font.setFamily("Comic Sans MS")
        font.setPointSize(14)
        font.setBold(False)
        font.setWeight(50)
        self.label_5.setFont(font)
        self.label_5.setStyleSheet("background-color:qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1, stop:0 rgba(0, 255, 241, 255), stop:0.930348 rgba(0, 158, 255, 255));\n"
"color:rgb(85, 0, 255)")
        self.label_5.setObjectName("label_5")
        self.gridLayout_2.addWidget(self.label_5, 4, 0, 1, 1)
        self.line = QtWidgets.QFrame(self.centralwidget)
        self.line.setFrameShape(QtWidgets.QFrame.VLine)
        self.line.setFrameShadow(QtWidgets.QFrame.Sunken)
        self.line.setObjectName("line")
        self.gridLayout_2.addWidget(self.line, 1, 1, 4, 1)
        self.textEdit = QtWidgets.QTextEdit(self.centralwidget)
        self.textEdit.setObjectName("textEdit")
        self.gridLayout_2.addWidget(self.textEdit, 2, 2, 3, 1)
        MainWindow.setCentralWidget(self.centralwidget)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        self.label_2.setText(_translate("MainWindow", "Maximum load(kb):"))
        self.lineEdit.setText(_translate("MainWindow", "1024"))
        self.label_3.setText(_translate("MainWindow", "Online user(s):"))
        self.groupBox.setTitle(_translate("MainWindow", "Administrator send"))
        self.pushButton.setText(_translate("MainWindow", "send"))
        self.label.setText(_translate("MainWindow", "Socket Server [%s:%s]"))
        self.label_4.setText(_translate("MainWindow", "Output:"))
        self.label_5.setText(_translate("MainWindow", "Socket Server v1.3"))

        MainWindow.show()
app = QtWidgets.QApplication(sys.argv)
GUI = Ui_MainWindow(QtWidgets.QMainWindow())
sys.exit(app.exec_())

server.ui

(xml)

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>MainWindow</class>
 <widget class="QMainWindow" name="MainWindow">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>800</width>
    <height>685</height>
   </rect>
  </property>
  <property name="font">
   <font>
    <family>Consolas</family>
   </font>
  </property>
  <property name="windowTitle">
   <string>MainWindow</string>
  </property>
  <property name="styleSheet">
   <string notr="true"/>
  </property>
  <widget class="QWidget" name="centralwidget">
   <layout class="QGridLayout" name="gridLayout_2">
    <item row="2" column="0">
     <layout class="QFormLayout" name="formLayout">
      <item row="0" column="0" colspan="2">
       <widget class="QListView" name="listView"/>
      </item>
      <item row="1" column="0">
       <widget class="QLabel" name="label_2">
        <property name="text">
         <string>Maximum load(kb):</string>
        </property>
       </widget>
      </item>
      <item row="1" column="1">
       <widget class="QLineEdit" name="lineEdit">
        <property name="text">
         <string>1024</string>
        </property>
       </widget>
      </item>
      <item row="2" column="1">
       <widget class="QLCDNumber" name="lcdNumber"/>
      </item>
      <item row="2" column="0">
       <widget class="QLabel" name="label_3">
        <property name="text">
         <string>Online user(s):</string>
        </property>
       </widget>
      </item>
     </layout>
    </item>
    <item row="3" column="0">
     <widget class="QGroupBox" name="groupBox">
      <property name="title">
       <string>Administrator send</string>
      </property>
      <layout class="QGridLayout" name="gridLayout">
       <item row="1" column="0">
        <spacer name="horizontalSpacer">
         <property name="orientation">
          <enum>Qt::Horizontal</enum>
         </property>
         <property name="sizeHint" stdset="0">
          <size>
           <width>40</width>
           <height>20</height>
          </size>
         </property>
        </spacer>
       </item>
       <item row="0" column="0" colspan="2">
        <widget class="QTextEdit" name="textEdit_2"/>
       </item>
       <item row="1" column="1">
        <widget class="QPushButton" name="pushButton">
         <property name="text">
          <string>send</string>
         </property>
        </widget>
       </item>
      </layout>
     </widget>
    </item>
    <item row="0" column="0">
     <widget class="QLabel" name="label">
      <property name="text">
       <string>Socket Server [%s:%s]</string>
      </property>
     </widget>
    </item>
    <item row="1" column="2">
     <widget class="QLabel" name="label_4">
      <property name="text">
       <string>Output:</string>
      </property>
     </widget>
    </item>
    <item row="4" column="0">
     <widget class="QLabel" name="label_5">
      <property name="font">
       <font>
        <family>Comic Sans MS</family>
        <pointsize>14</pointsize>
        <weight>50</weight>
        <bold>false</bold>
       </font>
      </property>
      <property name="styleSheet">
       <string notr="true">background-color:qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1, stop:0 rgba(0, 255, 241, 255), stop:0.930348 rgba(0, 158, 255, 255));
color:rgb(85, 0, 255)</string>
      </property>
      <property name="text">
       <string>Socket Server v1.3</string>
      </property>
     </widget>
    </item>
    <item row="1" column="1" rowspan="4">
     <widget class="Line" name="line">
      <property name="orientation">
       <enum>Qt::Vertical</enum>
      </property>
     </widget>
    </item>
    <item row="2" column="2" rowspan="3">
     <widget class="QTextEdit" name="textEdit">
      <property name="html">
       <string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'SimSun'; font-size:9pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
      </property>
     </widget>
    </item>
   </layout>
  </widget>
  <widget class="QStatusBar" name="statusbar"/>
 </widget>
 <resources/>
 <connections/>
</ui>

(ui)

 pyinstaller打包32位 anaconda 虚拟python系统

anaconda 打包32位exe

由于我们学校的机房可以带U盘, 所以我带了U盘想看看运行行不行(本人初中生)

我们家电脑是64x的, 而机房是win 7旗舰版32x的, 所以就提示不行

第二次去的时候,我就想这直接带.py, 所以去之前我在电脑上下了个PyQt5的.whl文件(我们电脑上有python3.4),然后呢他说pip没在环境变量里,我就试了py -m pip,结果就压根没有pip或pip3

第三次去的时候, 我之前下了个get-pip.py(那里没开网),结果说最低版本3.6, 我把那个(3, 6)数组改了也不行

第四周, 下了个老一点的, 结果闪退了, 直接 ====Restart Shell====,我崩溃了

终于,第五周的时候, 终于用anaconda下环境的pyinstaller打包的exe可以运行了!

提示: 

anaconda 4.3个GB, 如果C盘一直装东西没空间了, 就换个盘,何况anaconda app下载的时候也会提示.

|全部代码(复制)

服务端

#服务端
import socket # 导入 socket 模块
from threading import Thread
import logging

def threading(Daemon, **kwargs):
        thread = Thread(**kwargs)
        thread.setDaemon(Daemon)
        thread.start()
        return thread

def debug(command):
    def logs(*args, **kwargs):
        try:
            command(*args, **kwargs)
        except Exception as e:
            print(e)

    return logs



logger = logging.getLogger(__name__)
logger.setLevel(level = logging.INFO)
handler = logging.FileHandler("log.txt")
handler.setLevel(logging.INFO)
handler.setFormatter(logging.Formatter("%(asctime)s - %(levelname)s - %(message)s"))
logger.addHandler(handler)
console = logging.StreamHandler()
console.setLevel(logging.INFO)
logger.addHandler(handler)
logger.addHandler(console)
bytecount = 1024
class Server(object):
    join_message = "<font color='red'>Server></font> <font color='blue'>%s</font> 连接服务器. 当前在线人数: <font color='red'>%s</font>"
    user_message = "<font color='%s'>%s(%s端)%s></font> %s"
    quit_message = "%s 下线"
    def __init__(self, addr, port, backlog = 10, encode = 'utf8'):
        self.address = addr, port
        self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.socket.bind(self.address)
        self.socket.listen(backlog)
        self.connect = {}
        self.encode = encode
        self.errs = []
    def run(self):
        logger.info("服务器[%s]开启,端口[%s]" % (socket.gethostbyname(socket.gethostname()), self.address[1]))
        self.accept_client()
    def _get_sockets(self): #return int
        return len(self.connect.items())
    def send(self, sock, user, mes):
        self.QUIT(user, lambda: sock.sendall(mes.encode(self.encode)))()
    def QUIT(self, user, command):
        sock = list(self.connect.keys())[list(self.connect.values()).index(user)]
        def logs(*args, **kargs):
            try:
                command(*args, **kargs)
            except:
                self.errs.append(sock)
        return logs
    def ServerMessage(self, mes):
        for sock, user in self.connect.items():
            if not sock in self.errs:
                self.send(sock, user, mes)
    def UserMessage(self, address, _user, mes):
        if not mes:
            return
        mes = mes.decode(encoding="utf8")
        for sock, user in self.connect.items():
            if not sock in self.errs:
                send_message = Server.user_message % ("brown" if _user == user else "red",
                                                      _user,
                                                      address,
                                                      "(我自己)" if _user == user else "",
                                                      mes)
                self.send(sock, user, send_message)
        logger.info(f"{address}[{_user}] : {mes}")
        self.error_handle()
    def error_handle(self):
        for sock in self.errs:
            sock.close()
            logger.exception(msg = str())
            Q = Server.quit_message % user
            logger.info(Q)
            self.connect.pop(sock)
            self.ServerMessage(Q)
    def accept_client(self):
      while True:
        client, address = self.socket.accept() # 阻塞,等待客户端连接
        thread = threading(Daemon=True, target=self.message_handle, args=(client,address[0]))

    def message_handle(self,client,address):
        username = client.recv(1024).decode(encoding='utf8')
        self.connect[client] = username
        logger.info(f"{address}[{username}] 加入服务器 , 当前人数 {self._get_sockets()}")
        self.ServerMessage(Server.join_message % (address, self._get_sockets()) )
        while True:
            try:
                self.UserMessage(address,username,client.recv(bytecount **2))
            except:
                pass
server = Server(socket.gethostname(),429)
server.run()
sys.exit(app.exec_())

用户端

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

# Form implementation generated from reading ui files 'USER.ui', 'Connect.ui'
#
# Created by: PyQt5 UI code generator 5.15.4
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again.  Do not edit this file unless you know what you are doing.


from PyQt5 import QtCore, QtGui, QtWidgets
import socket, sys, logging
from traceback import format_exc
from datetime import datetime
from time import sleep
from threading import Thread

import logging  # 引入logging模块
logging.basicConfig(level=logging.DEBUG,format='%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s')
Username = 'zmh'
TIMEOUT = 3
IP = "114.67.206.19" 
bytecount = 1024
dicts = {f"{IP} (公网)" : {"ip":IP, "port":16223},
         "192.168.1.8 (私网)" : {"ip":"192.168.56.1","port":429},
         "EXAM-41 (微机室)" : {"ip":"EXAM-41","port":429}}
get_time = lambda: datetime.now().strftime('%Y %m %d %H:%M:%S')
def threading(Daemon, **kwargs):
        thread = Thread(**kwargs)
        thread.setDaemon(Daemon)
        thread.start()
        return thread

def to_logging(command):
    def logs(*args, **kwargs):
        try:
            command(*args, **kwargs)
        except Exception as e:
            if "main" in dir():
                main.Show_Message(format_exc())
            else:
                logging.exception(str())
            return False
        else:
            return True
    return logs

class Socket:
    def __init__(self,Function=lambda i:None,code='utf-8'):
        self.socket = socket.socket()
        self.code = code
        self._logger = Function
        self.socket.settimeout(TIMEOUT)
        self._connect = False
    def set_func(self, f):
        self._logger = f

    @to_logging
    def socket_connect(self):
        self.socket.connect(self.addr)
    def connect(self, ip = None,port:int=0000, show=None):
        self.addr = (ip, port)   
        if not self.socket_connect():
                show("[{}]: 连接服务器[{}]失败".format(get_time(),self.addr[0]))
                return False
        else:
                show("[{}]: 连接成功".format(get_time()))
                return True
        print(self.addr)
    def _handler(self):
            self.socket.send(Username.encode(self.code))
            while True:
                try:
                    byte = self.socket.recv(bytecount **2)
                    if len(byte) == 0:
                            break
                    kb = len(byte) / bytecount
                    self._logger(f'[{datetime.now().strftime("%H:%M:%S")}]{byte.decode(encoding=self.code)}                  {"<font size=1>%0.2f kb</font>" % kb}')
                except Exception as e:
                    if not type(e) == socket.timeout:
                        for n in ["","ERROR".center(20,"-")]+format_exc().split('\n')+["".center(20,"-"),""]:
                            self._logger(f"<font color='red'>{n}</font>")
                        self.socket.close()
                        return
    def run(self): #线程
        self._connect = True
        self.thread = threading(False, target=self._handler)

class Ui_Dialog(object):
    def __init__(self):
        Dialog = QtWidgets.QDialog()
        self.Dialog = Dialog
        Dialog.setObjectName("Dialog")
        Dialog.resize(495, 81)
        self.gridLayout = QtWidgets.QGridLayout(Dialog)
        self.gridLayout.setObjectName("gridLayout")
        self.comboBox = QtWidgets.QComboBox(Dialog)
        self.comboBox.setObjectName("comboBox")
        self.comboBox.addItems(list(dicts.keys()))
        self.gridLayout.addWidget(self.comboBox, 0, 1, 1, 1)
        self.pushButton = QtWidgets.QPushButton(Dialog)
        self.pushButton.setObjectName("pushButton")
        self.gridLayout.addWidget(self.pushButton, 0, 2, 1, 1)
        self.label = QtWidgets.QLabel(Dialog)
        font = QtGui.QFont()
        font.setFamily("Consolas")
        self.label.setFont(font)
        self.label.setObjectName("label")
        self.gridLayout.addWidget(self.label, 0, 0, 1, 1)
        self.lineEdit = QtWidgets.QLineEdit(Dialog)
        self.lineEdit.setReadOnly(True)
        self.lineEdit.setObjectName("lineEdit")
        self.gridLayout.addWidget(self.lineEdit, 1, 0, 2, 3)

        self.retranslateUi(Dialog)
        self.pushButton.clicked.connect(self._connect)
        QtCore.QMetaObject.connectSlotsByName(Dialog)
        self.num = 0
    def retranslateUi(self, Dialog):
        _translate = QtCore.QCoreApplication.translate
        Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
        self.comboBox.setItemText(0, _translate("Dialog", list(dicts.keys())[0]))
        self.pushButton.setText(_translate("Dialog", "Connecting"))
        self.label.setText(_translate("Dialog", "Select Socket Connect Address:"))
        self.set_text("No return value.")
        Dialog.show()
    def set_text(self, m):
        self.lineEdit.setText(QtCore.QCoreApplication.translate("Dialog", str(m)))
        self.lineEdit.update()
    @to_logging
    def _connect(self, i):
        addr = dicts[self.comboBox.currentText()]
        self.set_text("[{}]: 尝试连接服务器[{}],最大超时报错 {}s".format(datetime.now().strftime('%Y %m %d %H:%M:%S'),addr["ip"],TIMEOUT))
        if s.connect(**addr, show=self.set_text):
            global main
            main = Ui_MainWindow()
            main.show()
            def close(widget):
                sleep(1)
                widget.close()
            threading(False, target=close, args=(self.Dialog, ))
class Ui_MainWindow(object):
    def __init__(self):
        MainWindow = QtWidgets.QMainWindow()
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(800, 619)
        font = QtGui.QFont()
        font.setFamily("Consolas")
        MainWindow.setFont(font)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.gridLayout = QtWidgets.QGridLayout(self.centralwidget)
        self.gridLayout.setObjectName("gridLayout")
        self.lineEdit_3 = QtWidgets.QLineEdit(self.centralwidget)
        self.lineEdit_3.setReadOnly(True)
        self.lineEdit_3.setObjectName("lineEdit_3")
        self.gridLayout.addWidget(self.lineEdit_3, 7, 3, 1, 1)
        self.pushButton = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton.setStyleSheet("background-color:rgb(44, 176, 13);\n"
"color:rgb(255, 255, 255);\n"
"font: 200 10pt \"Consolas\";")
        self.pushButton.setObjectName("pushButton")
        self.gridLayout.addWidget(self.pushButton, 8, 6, 1, 1)
        spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
        self.gridLayout.addItem(spacerItem, 8, 5, 1, 1)
        self.label_2 = QtWidgets.QLabel(self.centralwidget)
        self.label_2.setObjectName("label_2")
        self.gridLayout.addWidget(self.label_2, 6, 1, 1, 1)
        spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
        self.gridLayout.addItem(spacerItem1, 8, 3, 1, 1)
        self.lineEdit_2 = QtWidgets.QLineEdit(self.centralwidget)
        self.lineEdit_2.setReadOnly(True)
        self.lineEdit_2.setObjectName("lineEdit_2")
        self.gridLayout.addWidget(self.lineEdit_2, 6, 3, 1, 1)
        self.label = QtWidgets.QLabel(self.centralwidget)
        self.label.setObjectName("label")
        self.gridLayout.addWidget(self.label, 5, 1, 1, 1)
        self.lineEdit = QtWidgets.QLineEdit(self.centralwidget)
        self.lineEdit.setCursor(QtGui.QCursor(QtCore.Qt.IBeamCursor))
        self.lineEdit.setDragEnabled(False)
        self.lineEdit.setReadOnly(True)
        self.lineEdit.setObjectName("lineEdit")
        self.gridLayout.addWidget(self.lineEdit, 5, 3, 1, 1)
        self.label_3 = QtWidgets.QLabel(self.centralwidget)
        self.label_3.setObjectName("label_3")
        self.gridLayout.addWidget(self.label_3, 7, 1, 1, 1)
        self.line = QtWidgets.QFrame(self.centralwidget)
        self.line.setFrameShape(QtWidgets.QFrame.VLine)
        self.line.setFrameShadow(QtWidgets.QFrame.Sunken)
        self.line.setObjectName("line")
        self.gridLayout.addWidget(self.line, 5, 4, 3, 1)
        self.textEdit = QtWidgets.QTextEdit(self.centralwidget)
        self.textEdit.setObjectName("textEdit")
        self.gridLayout.addWidget(self.textEdit, 5, 5, 3, 2)
        spacerItem2 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
        self.gridLayout.addItem(spacerItem2, 1, 1, 1, 1)
        self.textEdit_2 = QtWidgets.QTextEdit(self.centralwidget)
        self.textEdit_2.setObjectName("textEdit_2")
        self.textEdit_2.setReadOnly(True)
        self.gridLayout.addWidget(self.textEdit_2, 0, 3, 2, 4)
        self.pushButton_2 = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton_2.setObjectName("pushButton_2")
        self.gridLayout.addWidget(self.pushButton_2, 8, 1, 1, 1)
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 24))
        self.menubar.setObjectName("menubar")
        self.menu = QtWidgets.QMenu(self.menubar)
        self.menu.setObjectName("menu")
        self.menulanguage = QtWidgets.QMenu(self.menu)
        self.menulanguage.setObjectName("menulanguage")
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)
        self.actionsocket_connet = QtWidgets.QAction(MainWindow)
        self.actionsocket_connet.setObjectName("actionsocket_connet")
        self.actionChinese = QtWidgets.QAction(MainWindow)
        self.actionChinese.setObjectName("actionChinese")
        self.actionip_socket_gethostbyname_socket_gethostname = QtWidgets.QAction(MainWindow)
        self.actionip_socket_gethostbyname_socket_gethostname.setObjectName("actionip_socket_gethostbyname_socket_gethostname")
        self.menulanguage.addSeparator()
        self.menulanguage.addAction(self.actionChinese)
        self.menu.addSeparator()
        self.menu.addAction(self.menulanguage.menuAction())
        self.menu.addAction(self.actionip_socket_gethostbyname_socket_gethostname)
        self.menubar.addAction(self.menu.menuAction())
        self.socket_peername = s.addr[0]
        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)
        self.MainWindow = MainWindow
        self.pushButton.clicked.connect(self.send)
    @to_logging
    def sendmsg(self):
        data = self.textEdit.toPlainText().strip()
        if data:
            s.socket.send(data.encode('utf8'));self.textEdit.clear()
    @to_logging
    def send(self, i):
        if hasattr(s,"_connect") and s._connect:
            if not self.sendmsg():
                QtWidgets.QMessageBox.information(self.MainWindow, 'TraceBack',f'Socket Server<{self.socket_peername}> 断开连接')
                s._connect = False
        else:
            self.Show_Message("<font color='red'>发送异常. 未连接至服务器.</font>")
    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "Socket"))
        self.lineEdit_2.setText(socket.gethostname())
        self.lineEdit.setText(socket.gethostbyname(socket.gethostname()))
        self.lineEdit_3.setText(self.socket_peername)
        self.pushButton.setText(_translate("MainWindow", "send"))
        self.label_2.setText(_translate("MainWindow", "主机名:"))
        self.label.setText(_translate("MainWindow", "本地端口:"))
        self.label_3.setText(_translate("MainWindow", "连接端口:"))
        self.pushButton_2.setText(_translate("MainWindow", "搭建Socket"))
        self.menu.setTitle(_translate("MainWindow", "设置"))
        self.menulanguage.setTitle(_translate("MainWindow", "language"))
        self.actionsocket_connet.setText(_translate("MainWindow", "socket connect"))
        self.actionChinese.setText(_translate("MainWindow", "Chinese"))
        self.actionip_socket_gethostbyname_socket_gethostname.setText(_translate("MainWindow", "ip: "+socket.gethostbyname(socket.gethostname()) ))

        s.set_func(self.Show_Message)
        s.run()
    def show(self):
        self.MainWindow.show()
    def Show_Message(self, data):
        if data:
            for i in data.split('\n'):
                self.textEdit_2.append(i)
                print(i)
if __name__ == "__main__":
        app = QtWidgets.QApplication(sys.argv)
        s = Socket()
        conn = Ui_Dialog()
        sys.exit(app.exec_())
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2022-03-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • |模块
  • |测试
  • |端口映射
  • |端口放行
  • |云服务器
  • |代码讲解
    • [客户端]
      • ·导入,定义
      • ·socket
      • ·logging
      • ·Thread.threading
      • ·datetime
      • ·PyQt5
    • [服务端]
      • ·socket
      • ·PyQt5
  •  pyinstaller打包32位 anaconda 虚拟python系统
  • |全部代码(复制)
相关产品与服务
云服务器
云服务器(Cloud Virtual Machine,CVM)提供安全可靠的弹性计算服务。 您可以实时扩展或缩减计算资源,适应变化的业务需求,并只需按实际使用的资源计费。使用 CVM 可以极大降低您的软硬件采购成本,简化 IT 运维工作。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档