TCP聊天+传输文件服务器服务器套接字v2.6



更改的地方:
主要是客户端界面更改

  1. 注册, 登录界面 (都知道啊, v1.8的改进后输入用户名, 到了主界面的时候才能输入密码, 但现在是直接输入用户名和密码, 然后转为json, 等待回复)
  2. 转到注册 (我用了commandLink)
  3. 记住密码 (checkBox, 如果记住报存到config.json, 下次直接转入登录, 设置为默认)
  4. 两大堡垒 (客户端与服务端两次堡垒, 防止更改客户端数据直接发送的[不符合规范的json数据包], 所以在服务端在识别[用户是否存在] + [账户密码是否正确]的前提下 又增加了[检测用户名密码长度]的规则)
  5. 界面淡入淡出

文章目录

  • 客户端更改
  • 服务端更改
      • server.pyw
      • data.py
    • 客户端与服务端两次堡垒, 防止更改客户端数据直接发送的[不符合规范的json数据包], 所以在服务端在识别用户[是否存在] + [账户密码是否正确]的前提下 又增加了[检测用户名密码长度]的规则
  • 资源
  • gitcode

所有版本记录:
v1.0 : TCP聊天服务器套接字|PyQt5+socket(TCP端口映射+端口放行)+logging+Thread(含日志,html)+anaconda打包32位exe(3.4万字)|python高阶
v1.1 : python TCP套接字服务器v1.1-新增服务端命令功能及修改bug(socket+PyQt5)
v1.2 : python TCP服务器v1.2 - 服务端新增用户登录注册(json, md5加密)
v1.3 : python TCP服务器v1.3 - 服务器抗压测试及关闭套接字处理
v1.4 : python TCP服务器v1.4 - 客户端连接服务器异常(异常情况分类)处理
v1.5 : PyQt5可编辑下拉框(comboBox):editable - python TCP服务器v1.5 - 客户端连接界面增加自定义参数(设置超时, 连接地址可选)
v1.6 : Python TCP服务器v1.6 - multiprocessing多进程及Ctrl-c(SIGINT)退出
v1.7 : Python TCP服务器v1.7 - PyQt5 server服务端来临
v1.8 : python TCP服务器v1.8 - PyQt5登录界面美化+淡入淡出
v1.9 : socketTCP协程文件+信息传递 - TCP聊天文件服务器v1.9 - 划时代的版本更新(4.6万字)
v2.0 : TCP聊天文件服务器v2.0 - 重大bug修复+PyQt5文件传输可视化
v2.1 : TCP聊天文件服务器v2.1 - 服务端线程管理(threading.enumerate)
v2.2 : TCP聊天文件服务器v2.2 - 服务端客户端套接字解决分包/粘包问题 - SocketQueue继承以及减少冗余
v2.3 : gzip的使用 - TCP聊天文件服务器v2.3 - 文件传输建立缓存制度和.gz的解压缩/压缩解决运行内存过大
v2.4 : 网络传输测速 - TCP聊天+传输文件服务器服务器套接字v2.4 - socket协程文件传送测速
v2.5 : TCP聊天+传输文件服务器服务器套接字v2.5 - socket测速规范已经gzip的弃用

loading界面参见 我的csdn博客 - pyqt5 等待界面 (QMovie 加载 gif)

客户端更改

class Socket(SocketClient):def __init__(self, Function=lambda i: None, code='utf-8'):super(Socket, self).__init__(codec=code)self.handler = message_handle(self.send)def parse_argument(self, arg: str) -> str:return self.handler.handle(arg.strip())def receive_text(self):return super(Socket, self).recv()def recv(self):result = super(Socket, self).recv()if isinstance(result, str) and result:self._traceback(f'{result}                  <font size=1>{convert(len(result))}</font>')return self.isOpen()def forever_receive(self) -> None:self.handler.send_text(self.header)while True:if not self.recv():returndef Check_info(self, *args, **kwargs):threading(True, target = lambda: self.__Check_info(*args, **kwargs))def __Check_info(self, info, emit, return_func, err_func):if not self.is_connect():res, trace = self.connect()emit(bool(res))if not res:return err_func(trace)self.handler.send_text(json.dumps(info))emit(True)data = self.receive_text()emit(True)try:data = json.loads(data)except (ValueError, KeyError):return err_func("解析异常!")else:emit(True)return_func(data)def run(self):  # 线程threading(True, target=self.forever_receive)def quitEvent(self):self.__is_connect = Falseif main.is_setup:main.ConnectionError_signal.emit()LOGIN_INFO_FILE = "config.json"
LOGIN_INFO = {"type": 0,"username": "","password": ""}if os.path.isfile(LOGIN_INFO_FILE):with open(LOGIN_INFO_FILE, "r") as f:LOGIN_INFO = json.load(f)def json_dump():with open(LOGIN_INFO_FILE, "w") as f:json.dump(LOGIN_INFO, f, indent=4)def Animation(parent, type=b"windowOpacity", from_value=0, to_value=1, ms=1000, connect=None):anim = QPropertyAnimation(parent, type)anim.setDuration(ms)anim.setStartValue(from_value)anim.setEndValue(to_value)if connect:anim.finished.connect(connect)anim.start()return animclass LoadingProgress(QtWidgets.QDialog):update_signal = QtCore.pyqtSignal(bool)def __init__(self, parent=None):super(LoadingProgress, self).__init__(parent)self.value = 0self.update_signal.connect(self.update_progress)vbox = QtWidgets.QVBoxLayout(self)self.steps = [f"连接服务器中({TIMEOUT}s)...","发送数据中...","接收数据中...","解析数据中..."]self.movie_label = QtWidgets.QLabel()self.movie = QtGui.QMovie("images/loading.gif")self.movie_label.setMovie(self.movie)self.movie.start()self.progress_label = QtWidgets.QLabel()self.label_update()vbox.addWidget(self.movie_label)vbox.addWidget(self.progress_label)self.setLayout(vbox)# self.exec_()def label_update(self):self.progress_label.setText(self.steps[self.value])def update_progress(self, boolean: bool) -> None:self.value += 1if boolean and self.value < len(self.steps):self.label_update()else:self.close()class User_Setup(QtWidgets.QDialog):end_anim, start_anim = None, Nonelog_progress_signal = QtCore.pyqtSignal(str)reg_progress_signal = QtCore.pyqtSignal(str)handle_signal = QtCore.pyqtSignal(dict)err_signal = QtCore.pyqtSignal(str)loading_dialog = Nonesuccessful = Falsedef closeEvent(self, event: QtGui.QCloseEvent) -> None:if not self.end_anim:self.end_anim = Animation(self, ms=2000, from_value=1, to_value=0, connect=self.close)event.ignore()else:if self.successful:main.SetupUi()def __init__(self, parent=None):super().__init__(parent)self.start_anim = Animation(self, ms=2000)self.setObjectName("Dialog")self.resize(362, 394)font = QtGui.QFont()font.setFamily("Consolas")font.setPointSize(12)self.setFont(font)icon = QtGui.QIcon()icon.addPixmap(QtGui.QPixmap("images/user.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)self.setWindowIcon(icon)self.setAutoFillBackground(True)self.gridLayout = QtWidgets.QGridLayout(self)self.gridLayout.setObjectName("gridLayout")self.label = QtWidgets.QLabel(self)self.label.setFocusPolicy(QtCore.Qt.StrongFocus)self.label.setStyleSheet("")self.label.setText("")self.label.setPixmap(QtGui.QPixmap("images/zmh.png"))self.label.setObjectName("label")self.gridLayout.addWidget(self.label, 0, 0, 1, 1)self.tabWidget = QtWidgets.QTabWidget(self)self.tabWidget.setAccessibleName("")self.tabWidget.setAutoFillBackground(True)self.tabWidget.setObjectName("tabWidget")self.log = QtWidgets.QWidget()self.log.setObjectName("login")self.gridLayout_2 = QtWidgets.QGridLayout(self.log)self.gridLayout_2.setObjectName("gridLayout_2")self.lineEdit_5 = QtWidgets.QLineEdit(self.log)self.lineEdit_5.setStyleSheet("            QLineEdit\n""            {border:0px;\n""            border-radius:0;\n""            font: 12pt \"Consolas\";\n""            margin:15px;\n""            border-bottom: 2px solid #B3B3B3;}\n""            QLineEdit:hover{\n""                border-bottom:3px solid #66A3FF;\n""            }\n""            QLineEdit:focus{\n""                border-bottom:3px solid #E680BD\n""            }")self.lineEdit_5.setText("")self.lineEdit_5.setEchoMode(QtWidgets.QLineEdit.Password)self.lineEdit_5.setClearButtonEnabled(True)self.lineEdit_5.setObjectName("lineEdit_5")self.gridLayout_2.addWidget(self.lineEdit_5, 2, 0, 1, 2)self.lineEdit_4 = QtWidgets.QLineEdit(self.log)self.lineEdit_4.setStyleSheet("            QLineEdit\n""            {border:0px;\n""            border-radius:0;\n""            font: 12pt \"Consolas\";\n""            margin:15px;\n""            border-bottom: 2px solid #B3B3B3;}\n""            QLineEdit:hover{\n""                border-bottom:3px solid #66A3FF;\n""            }\n""            QLineEdit:focus{\n""                border-bottom:3px solid #E680BD\n""            }")self.lineEdit_4.setClearButtonEnabled(True)self.lineEdit_4.setObjectName("lineEdit_4")self.gridLayout_2.addWidget(self.lineEdit_4, 1, 0, 1, 2)self.pushButton_2 = QtWidgets.QPushButton(self.log)icon1 = QtGui.QIcon()icon1.addPixmap(QtGui.QPixmap("images/login.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)self.pushButton_2.setIcon(icon1)self.pushButton_2.setObjectName("pushButton_2")self.gridLayout_2.addWidget(self.pushButton_2, 6, 1, 1, 1)self.checkBox_2 = QtWidgets.QCheckBox(self.log)self.checkBox_2.setChecked(True)self.checkBox_2.setObjectName("checkBox_2")self.gridLayout_2.addWidget(self.checkBox_2, 6, 0, 1, 1)self.label_3 = QtWidgets.QLabel(self.log)font = QtGui.QFont()font.setFamily("Comic Sans MS")font.setPointSize(11)font.setBold(False)font.setItalic(False)font.setWeight(50)self.label_3.setFont(font)self.label_3.setStyleSheet("color: rgb(255, 1, 39);\n""font: 11pt \"宋体\";")self.label_3.setObjectName("label_3")self.gridLayout_2.addWidget(self.label_3, 4, 0, 1, 2)self.commandLinkButton = QtWidgets.QCommandLinkButton(self.log)font = QtGui.QFont()font.setFamily("Segoe UI")font.setPointSize(12)self.commandLinkButton.setFont(font)self.commandLinkButton.setObjectName("commandLinkButton")self.gridLayout_2.addWidget(self.commandLinkButton, 3, 0, 1, 2)self.tabWidget.addTab(self.log, "")self.reg = QtWidgets.QWidget()self.reg.setObjectName("reg")self.gridLayout_3 = QtWidgets.QGridLayout(self.reg)self.gridLayout_3.setObjectName("gridLayout_3")self.pushButton = QtWidgets.QPushButton(self.reg)icon2 = QtGui.QIcon()icon2.addPixmap(QtGui.QPixmap("images/register.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)self.pushButton.setIcon(icon2)self.pushButton.setObjectName("pushButton")self.gridLayout_3.addWidget(self.pushButton, 5, 1, 1, 1)self.checkBox = QtWidgets.QCheckBox(self.reg)self.checkBox.setChecked(True)self.checkBox.setTristate(False)self.checkBox.setObjectName("checkBox")self.gridLayout_3.addWidget(self.checkBox, 5, 0, 1, 1)self.lineEdit_3 = QtWidgets.QLineEdit(self.reg)self.lineEdit_3.setContextMenuPolicy(QtCore.Qt.DefaultContextMenu)self.lineEdit_3.setAccessibleName("")self.lineEdit_3.setStyleSheet("            QLineEdit\n""            {border:0px;\n""            border-radius:0;\n""            font: 12pt \"Consolas\";\n""            margin:15px;\n""            border-bottom: 2px solid #B3B3B3;}\n""            QLineEdit:hover{\n""                border-bottom:3px solid #66A3FF;\n""            }\n""            QLineEdit:focus{\n""                border-bottom:3px solid #E680BD\n""            }")self.lineEdit_3.setEchoMode(QtWidgets.QLineEdit.Password)self.lineEdit_3.setDragEnabled(False)self.lineEdit_3.setClearButtonEnabled(True)self.lineEdit_3.setObjectName("lineEdit_3")self.gridLayout_3.addWidget(self.lineEdit_3, 2, 0, 1, 2)self.lineEdit_2 = QtWidgets.QLineEdit(self.reg)font = QtGui.QFont()font.setFamily("Consolas")font.setPointSize(12)font.setBold(False)font.setItalic(False)font.setWeight(50)self.lineEdit_2.setFont(font)self.lineEdit_2.setStyleSheet("            QLineEdit\n""            {border:0px;\n""            border-radius:0;\n""            font: 12pt \"Consolas\";\n""            margin:15px;\n""            border-bottom: 2px solid #B3B3B3;}\n""            QLineEdit:hover{\n""                border-bottom:3px solid #66A3FF;\n""            }\n""            QLineEdit:focus{\n""                border-bottom:3px solid #E680BD\n""            }")self.lineEdit_2.setInputMask("")self.lineEdit_2.setEchoMode(QtWidgets.QLineEdit.Password)self.lineEdit_2.setDragEnabled(False)self.lineEdit_2.setCursorMoveStyle(QtCore.Qt.LogicalMoveStyle)self.lineEdit_2.setClearButtonEnabled(True)self.lineEdit_2.setObjectName("lineEdit_2")self.gridLayout_3.addWidget(self.lineEdit_2, 1, 0, 1, 2)self.lineEdit = QtWidgets.QLineEdit(self.reg)font = QtGui.QFont()font.setFamily("Consolas")font.setPointSize(12)font.setBold(False)font.setItalic(False)font.setWeight(50)self.lineEdit.setFont(font)self.lineEdit.setStyleSheet("            QLineEdit\n""            {border:0px;\n""            border-radius:0;\n""            font: 12pt \"Consolas\";\n""            margin:15px;\n""            border-bottom: 2px solid #B3B3B3;}\n""            QLineEdit:hover{\n""                border-bottom:3px solid #66A3FF;\n""            }\n""            QLineEdit:focus{\n""                border-bottom:3px solid #E680BD\n""            }")self.lineEdit.setEchoMode(QtWidgets.QLineEdit.Normal)self.lineEdit.setClearButtonEnabled(True)self.lineEdit.setObjectName("lineEdit")self.gridLayout_3.addWidget(self.lineEdit, 0, 0, 1, 2)self.label_6 = QtWidgets.QLabel(self.reg)self.label_6.setStyleSheet("color: rgb(255, 1, 39);\n""font: 11pt \"宋体\";")self.label_6.setObjectName("label_6")self.gridLayout_3.addWidget(self.label_6, 3, 0, 1, 2)self.tabWidget.addTab(self.reg, "")self.gridLayout.addWidget(self.tabWidget, 2, 0, 1, 3)self.label_2 = QtWidgets.QLabel(self)font = QtGui.QFont()font.setFamily("Comic Sans MS")font.setPointSize(14)self.label_2.setFont(font)self.label_2.setObjectName("label_2")self.gridLayout.addWidget(self.label_2, 0, 1, 1, 1)spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)self.gridLayout.addItem(spacerItem, 0, 2, 1, 1)self.comboBox = QtWidgets.QComboBox(self)font = QtGui.QFont()font.setFamily("Prestige Elite Std")font.setPointSize(13)font.setBold(False)font.setItalic(False)font.setWeight(50)self.comboBox.setFont(font)self.comboBox.setStyleSheet("")self.comboBox.setEditable(True)self.comboBox.setObjectName("comboBox")self.gridLayout.addWidget(self.comboBox, 1, 0, 1, 2)self.tabWidget.setCurrentIndex(LOGIN_INFO["type"])QtCore.QMetaObject.connectSlotsByName(self)self.commandLinkButton.clicked.connect(lambda: self.tabWidget.setCurrentIndex(1))_translate = QtCore.QCoreApplication.translateself.setWindowTitle(_translate("Dialog", "登录 - 注册"))self.lineEdit_5.setPlaceholderText(_translate("Dialog", "密码(4-10字符)"))self.lineEdit_4.setPlaceholderText(_translate("Dialog", "用户名(2-12字符)"))self.pushButton_2.setText(_translate("Dialog", "登录"))self.checkBox_2.setText(_translate("Dialog", "记住密码"))self.label_3.setText(_translate("Dialog", ""))self.commandLinkButton.setText(_translate("Dialog", "没有账号? 注册一个"))self.tabWidget.setTabText(self.tabWidget.indexOf(self.log), _translate("Dialog", "登录"))self.pushButton.setText(_translate("Dialog", "注册"))self.checkBox.setText(_translate("Dialog", "记住密码"))self.lineEdit_3.setPlaceholderText(_translate("Dialog", "再次输入密码(4-10字符)"))self.lineEdit_2.setPlaceholderText(_translate("Dialog", "密码(4-10字符)"))self.lineEdit.setPlaceholderText(_translate("Dialog", "用户名(2-12字符)"))self.label_6.setText(_translate("Dialog", ""))self.tabWidget.setTabText(self.tabWidget.indexOf(self.reg), _translate("Dialog", "注册"))self.label_2.setText(_translate("Dialog", "Socketserver"))self.comboBox.addItems(ip_list)self.log_progress_signal.connect(self.label_3.setText)self.reg_progress_signal.connect(self.label_6.setText)self.handle_signal.connect(self.handle)self.err_signal.connect(self.err_handle)if LOGIN_INFO["type"] == 0:#  loginself.lineEdit_4.setText(LOGIN_INFO["username"])self.lineEdit_5.setText(LOGIN_INFO["password"])elif LOGIN_INFO["type"] == 1:self.lineEdit.setText(LOGIN_INFO["username"])self.lineEdit_2.setText(LOGIN_INFO["password"])self.lineEdit_3.setText(LOGIN_INFO["password"])self.pushButton.clicked.connect(self.register)self.pushButton_2.clicked.connect(self.login)self.show()def Enable(self, boolean):self.pushButton.setEnabled(boolean)self.pushButton_2.setEnabled(boolean)def get_ip(self) -> str:return self.comboBox.currentText()def clear(self):self.label_3.setText("")self.label_6.setText("")def login(self, *args):self.clear()self.Enable(False)self._login()def err_handle(self, string):self.label_3.setText(string)self.label_6.setText(string)self.Enable(True)def handle(self, dictionary: (dict, str)):if isinstance(dictionary, dict):result = dictionary.get("result", False)reason = dictionary.get("reason", False)if not result:self.err_handle(reason)else:self.successful = Trueself.close()self.Enable(True)def login_trace(self, res: bool, reason: str):self.label_3.setText(reason)self.Enable(True)def loading(self) -> callable:self.loading_dialog = LoadingProgress(self)return self.loading_dialog.update_signal.emitdef exec_loading_dialog(self):if isinstance(self.loading_dialog, LoadingProgress):self.loading_dialog.exec_()  # 直接使用造成阻塞, 为此单独调用.def _login(self):username = self.lineEdit_4.text().strip()password = self.lineEdit_5.text().strip()if not username:return self.login_trace(False, "未填写用户名!")if not password:return self.login_trace(False, "未填写密码!")if not 2 <= len(username) <= 12:return self.login_trace(False, "用户名需在2~12位之间!")if not 4 <= len(password) <= 10:return self.login_trace(False, "密码需在4~10位之间!")try:addr, port = self.get_ip().split(":")assert isinstance(addr, str)port = int(port)except (ValueError, AssertionError):return self.login_trace(False, "ipv4地址不正确! 结构:[host:port]")s.change_address(addr, port)s.Check_info({"type": 0, "username": username, "password": password}, self.loading(),self.handle_signal.emit, self.err_signal.emit)  # self.log_progress_signalself.exec_loading_dialog()global LOGIN_INFOLOGIN_INFO["username"] = usernameLOGIN_INFO["password"] = passwordif self.checkBox_2.isChecked():json_dump()return True, ""def register(self, *args):self.Enable(False)self.clear()self._register()def register_trace(self, res: bool, reason: str):self.label_6.setText(reason)self.Enable(True)def _register(self):username = self.lineEdit.text().strip()password = self.lineEdit_2.text().strip()password_check = self.lineEdit_3.text().strip()if not password_check == password:return self.register_trace(False, "两次输入密码不同!")if not username:return self.register_trace(False, "未填写用户名!")if not password:return self.register_trace(False, "未填写密码!")if not 2 <= len(username) <= 12:return self.register_trace(False, "用户名需在2~12位之间!")if not 4 <= len(password) <= 10:return self.register_trace(False, "密码需在4~10位之间!")try:addr, port = self.get_ip().split(":")assert isinstance(addr, str)port = int(port)except (ValueError, AssertionError):return self.register_trace(False, "ipv4地址不正确! 结构:[host:port]")s.change_address(addr, port)s.Check_info({"type": 1, "username": username, "password": password}, self.loading(),self.handle_signal.emit, self.err_signal.emit)  # self.reg_progress_signalself.exec_loading_dialog()global LOGIN_INFOLOGIN_INFO["username"] = usernameLOGIN_INFO["password"] = passwordif self.checkBox.isChecked():json_dump()return True, ""

服务端更改

server.pyw

class Client(...):...@ignoredef forever_receive(self):while self.isOpen():result, reason, uname = self.server.user_record.handler(**self.json_data())self.send(json.dumps({"result": result, "reason": reason}))if result:self.username = unamebreakself._login = Trueself.server.login(self.username, self.addr)while self.isOpen():string = self.recv()if string is None:continueelif self.com.iscommand(string):self.send(self.com.handler(string))else:self.server.UserMessage(self.addr, self.username, string)

data.py

file = r'.\clients\data.json'
folder = r'.\clients'
if not path.exists(folder):mkdir(folder)class data:def __init__(self):if path.exists(file):with open(file, 'r') as f:self.data = load(f)else:self.data = {}def __get__(self, username, default=None) -> tuple:return self.data.get(username, default)def __in__(self, username) -> bool:return username in self.data.keys()def __write__(self) -> None:with open(file, 'w') as f:dump(self.data, f, indent=4)def __register__(self, username, password, time: (int, float) = time()) -> None:self.data[username] = (encode(password), int(time))self.__write__()def __login__(self, username, password) -> bool:return self.data[username][0] == encode(password)def get_time(self, username):return self.data[username][1]def handler(self, type: int, username: str, password: str):username = username.strip()if not username:return False, "未填写用户名!", ""password = password.strip()if not password:return False, "未填写密码!", ""if not 2 <= len(username) <= 12:return False, "用户名需在2~12位之间!", ""if not 4 <= len(password) <= 10:return False, "密码需在4~10位之间!", ""if type == 0:  # loginif not self.__in__(username):return False, "用户不存在!", ""if not self.__login__(username, password):return False, "用户名 / 密码错误!", ""return True, "欢迎回来, " + username, usernameelif type == 1:  # registerif self.__in__(username):return False, "已存在用户!", ""self.__register__(username, password)return True, "初来乍到, " + username, username

客户端与服务端两次堡垒, 防止更改客户端数据直接发送的[不符合规范的json数据包], 所以在服务端在识别用户[是否存在] + [账户密码是否正确]的前提下 又增加了[检测用户名密码长度]的规则

资源

resource

gitcode

zmh-program / Python套接字Socket服务器

TCP聊天+传输文件服务器服务器套接字v2.6 - 登录注册界面更新 - loading界面应用相关推荐

  1. python 数据库性能提升 - TCP聊天+传输文件服务器服务器套接字v2.7

    TCP聊天+传输文件服务器服务器套接字v2.7 刚创建服务器的时候为了后期便于管理, 主要也是MySQL对我不适合, 跨平台使用, 一打包还有得装, 所以直接自己做了个 这是我写的服务器的数据库代码, ...

  2. MFC基于TCP协议的CSocket类套接字服务器端代码示范

    MFC基于TCP协议的CSocket类套接字服务器端代码示范 https://blog.csdn.net/txwtech/article/details/93417667 转载于:https://ww ...

  3. 前端学习(1856)vue之电商管理系统电商系统之安装mysql出现mysql报错:Can’t start server: Bind on TCP/IP port: 通常每个套接字地址(协议/网络地址

    2020-07-26T11:44:29.778919Z 0 [ERROR] [MY-010262] [Server] Can't start server: Bind on TCP/IP port: ...

  4. svnserve: 不能绑定服务器套接字: 地址已在使用

    [root@host conf]# svnserve -d -r /var/svn svnserve: 不能绑定服务器套接字: 地址已在使用 说明该进程正在使用可以用命令 ps -aux 查看进程 用 ...

  5. 网络协议OSI、TCP/IP协议、Socket套接字和第三方AsyncSock的使用等解析

    一.网络协议定义 1.OSI参考模型:全称(Open System Interconnection), 开放式系统互联参考模型.是一个逻辑上的定义,一个规范,它把网络协议从逻辑上分为七层,只要目的是为 ...

  6. 网络七层协议 五层模型 TCP连接 HTTP连接 socket套接字

    socket(套接字)是通信的基石,是支持TCP/IP协议的网络通信的基本操作单元,包含进行网络通信必须的五种信息:连接使用的协议,本地主机的IP地址,本地进程的协议端口,远地主机的IP地址,远地进程 ...

  7. Mac用Xcode建立TCP和UDP Socket(套接字)编程

    TCP和UDP均采用自己电脑,既做服务器端又做客户端,当然Xcode无法同时运行两个Target,所以可以选择一个在终端,一个在Xcode,或者两个都在终端. TCP服务器端: #include< ...

  8. TCP聊天文件服务器v2.2 - 服务端客户端套接字解决分包/粘包问题 - SocketQueue继承以及减少冗余

    TCP聊天+传输文件服务器服务器套接字v2.2 整个图当封面吧 所有版本记录: v1.0 : TCP聊天服务器套接字|PyQt5+socket(TCP端口映射+端口放行)+logging+Thread ...

  9. TCP聊天文件服务器v2.0 - 重大bug修复+PyQt5文件传输可视化

    TCP聊天+传输文件服务器服务器套接字v2.0 所有版本记录: v1.0 : TCP聊天服务器套接字|PyQt5+socket(TCP端口映射+端口放行)+logging+Thread(含日志,htm ...

最新文章

  1. 计算机基础及应用笔试,计算机基础及应用测试笔试题
  2. 桌面计算机安全策略,设置组策略实现Windows桌面显示计算机信息
  3. oracle 还原归档,ORACLE RMAN 还原归档日志
  4. HUSD审计报告:托管账户储备超7.87亿美元
  5. Android软件安全开发实践(下)
  6. (@WhiteTaken)设计模式学习——代理模式
  7. 数据库系统教程第三版施伯乐
  8. Java Web实战详细教程(一)系列介绍+环境搭建
  9. eclipse如何装php插件,Eclipse PHP插件(PHPEclipse)安装与配置图解
  10. 华为解锁刷机root教程详解
  11. javascript 字符串分割的方法总结区分
  12. 笔记本插入耳机,声音依然外放怎么办?
  13. Python3正则匹配re.split,re.serach,re.sub,re.finditer及re.findall函数用法详解
  14. iOS 9 spotlight搜索 3DTouch
  15. GCF(4)----手机认证相关知识
  16. Ubuntu20.04安装CUDA+CUDNN+Conda+PyTorch
  17. dnf搬砖代码Python_让搬砖变得轻松——python操作excel用的脚本
  18. 大学生计算机装机配置作业,不愧是计算机专业的大学生,自己写配置来装机,万元电脑真霸气...
  19. AD设计PCB从入门到精通(学习思路总结)
  20. 模拟舵机、数字舵机、总线舵机的区别

热门文章

  1. 抖音背后的黑科技究竟是什么?
  2. Dubbo(超级无敌认真好用,万字收藏篇!!!!)
  3. ROP-基础-ret2libc3
  4. 2021-10-18 Android studio 取色器吸管工具点击无效,没反应
  5. 巧用搜索摆脱新手程序员标签
  6. 电脑设置不自动息屏不自动睡眠的多种方法
  7. mysql教程详解之多表联合查询_详解数据库多表连接查询的实现方法
  8. Unity点击按钮没有反应
  9. 鼠标中间无法打开新标签_鼠标中键的这四个操作,你会几个?
  10. 三维坐标与平面坐标的转换(threejs)