Mon, 16 Dec 2019 17:03:51 +0800

master
大蒟蒻 6 years ago
parent e8e841c934
commit 42d69c229b

@ -0,0 +1 @@
Flat Mountain 18

Binary file not shown.

@ -11,8 +11,10 @@ class MainWindow(QMainWindow, Ui_MainWindow):
def __init__(self): def __init__(self):
super(MainWindow, self).__init__() super(MainWindow, self).__init__()
self.setupUi(self) self.setupUi(self)
# 设置主窗口界面
self.btnSend.clicked.connect(self.btnSend_onclicked) self.btnSend.clicked.connect(self.btnSend_onclicked)
self.btnConnect.clicked.connect(self.btnConnect_onclicked) self.btnConnect.clicked.connect(self.btnConnect_onclicked)
# 绑定按钮点击事件
self.statusbar.showMessage("Disconnected") self.statusbar.showMessage("Disconnected")
self.socket: socket = None self.socket: socket = None
self.isConnected = False self.isConnected = False
@ -20,6 +22,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
def closeEvent(self, event): def closeEvent(self, event):
if self.isConnected: if self.isConnected:
self.btnConnect.click() self.btnConnect.click()
# 在关闭窗口的时候正常断开连接
self.close() self.close()
def btnConnect_onclicked(self): def btnConnect_onclicked(self):
@ -29,22 +32,27 @@ class MainWindow(QMainWindow, Ui_MainWindow):
if sp in [-1, 0, len(server_addr) - 1]: if sp in [-1, 0, len(server_addr) - 1]:
QMessageBox.critical(self, "Error", "Invalid address") QMessageBox.critical(self, "Error", "Invalid address")
return return
# 检查是否是一个合理的host:port组合
addr, port = server_addr[:sp], server_addr[sp + 1:] addr, port = server_addr[:sp], server_addr[sp + 1:]
try: try:
port = int(port) port = int(port)
except: except:
QMessageBox.critical(self, "Error", "Invalid port") QMessageBox.critical(self, "Error", "Invalid port")
return return
# 检查port是否为整数
try: try:
self.socket = socket(AF_INET, SOCK_STREAM) self.socket = socket(AF_INET, SOCK_STREAM)
self.socket.connect((addr, port)) self.socket.connect((addr, port))
except: except:
QMessageBox.critical(self, "Error", "Connect failed") QMessageBox.critical(self, "Error", "Connect failed")
return return
# 尝试连接服务器
self.btnConnect.setText('Disconnect') self.btnConnect.setText('Disconnect')
self.statusbar.showMessage("Connected") self.statusbar.showMessage("Connected")
self.isConnected = True self.isConnected = True
# 设置状态
threading.Thread(target=self.recvmsg_loop).start() threading.Thread(target=self.recvmsg_loop).start()
# 开始监听线程
else: else:
self.socket.close() self.socket.close()
self.btnConnect.setText('Connect') self.btnConnect.setText('Connect')
@ -52,14 +60,17 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self.isConnected = False self.isConnected = False
def btnSend_onclicked(self): def btnSend_onclicked(self):
# 将消息发向服务器
msg = ':'.join([self.txtIDInput.text(), self.txtNewMsg.toPlainText()]) msg = ':'.join([self.txtIDInput.text(), self.txtNewMsg.toPlainText()])
self.txtNewMsg.clear() self.txtNewMsg.clear()
self.socket.send(msg.encode()) self.socket.send(msg.encode())
def recvmsg_loop(self): def recvmsg_loop(self):
while True: while True:
# 如未连接则结束此线程
if not self.isConnected: if not self.isConnected:
return return
# 接收信息
msg = self.socket.recv(1 << 20).decode() msg = self.socket.recv(1 << 20).decode()
print(msg) print(msg)
sp1 = msg.find(':') sp1 = msg.find(':')
@ -68,11 +79,15 @@ class MainWindow(QMainWindow, Ui_MainWindow):
msg[sp2 + 1:]) msg[sp2 + 1:])
self.txtList.append(str(datetime.now()) + " " + msg) self.txtList.append(str(datetime.now()) + " " + msg)
self.txtList.moveCursor(QTextCursor.End) self.txtList.moveCursor(QTextCursor.End)
# 呈现并将文本框滚到最后
if __name__ == "__main__": if __name__ == "__main__":
# 开启HiDPI支持
QApplication.setAttribute(Qt.AA_EnableHighDpiScaling) QApplication.setAttribute(Qt.AA_EnableHighDpiScaling)
app = QApplication(sys.argv) app = QApplication(sys.argv)
mw = MainWindow() mw = MainWindow()
mw.show() mw.show()
# 创建窗口并显示
app.exec() app.exec()
# 开始运行

@ -18,6 +18,7 @@ def static_vars(**kwargs):
return decorate return decorate
# 检查邮件地址是否合法
@static_vars( @static_vars(
matcher=re.compile(r"(^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$)")) matcher=re.compile(r"(^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$)"))
def validate_email(email: str): def validate_email(email: str):
@ -28,11 +29,9 @@ class MainWindow(QMainWindow, Ui_MainWindow):
def __init__(self): def __init__(self):
super(MainWindow, self).__init__() super(MainWindow, self).__init__()
self.setupUi(self) self.setupUi(self)
# 设置Ui
self.btnSendMail.clicked.connect(self.send_mail) self.btnSendMail.clicked.connect(self.send_mail)
self.txtFrom.textChanged.connect(self.mail_changed) # 绑定点击事件
def mail_changed(self):
pass
def send_mail(self): def send_mail(self):
servaddr = self.txtServer.text() servaddr = self.txtServer.text()
@ -41,30 +40,38 @@ class MainWindow(QMainWindow, Ui_MainWindow):
receiver = self.txtTo.text() receiver = self.txtTo.text()
subjects = self.txtSubject.text() subjects = self.txtSubject.text()
contents = self.txtContent.toPlainText() contents = self.txtContent.toPlainText()
# 获取必要信息
if not validate_email(username) or not validate_email(receiver): if not validate_email(username) or not validate_email(receiver):
QMessageBox.critical(self, "Invalid address", "Invalid From or To") QMessageBox.critical(self, "Invalid address", "Invalid From or To")
return return
# 检查发件人与收件人邮箱是否合法
lw = LogWindow( lw = LogWindow(
(servaddr, username, password, receiver, subjects, contents)) (servaddr, username, password, receiver, subjects, contents))
lw.exec() lw.exec()
# 启动发送窗口
class LogWindow(QDialog, Ui_Dialog): class LogWindow(QDialog, Ui_Dialog):
def __init__(self, data): def __init__(self, data):
super(LogWindow, self).__init__() super(LogWindow, self).__init__()
self.setupUi(self) self.setupUi(self)
# 设置Ui
threading.Thread(target=self.do_update_status, args=(data, )).start() threading.Thread(target=self.do_update_status, args=(data, )).start()
# 启动实际发送线程
def do_update_status(self, data): def do_update_status(self, data):
(servaddr, username, password, receiver, subjects, contents) = data (servaddr, username, password, receiver, subjects, contents) = data
ss = socket(AF_INET, SOCK_STREAM) ss = socket(AF_INET, SOCK_STREAM)
# 接收数据
try: try:
ss.connect((servaddr, 25)) ss.connect((servaddr, 25))
# 尝试连接
except Exception: except Exception:
QMessageBox.critical(self, "Connection Failed", QMessageBox.critical(self, "Connection Failed",
"Failed connecting smtp server") "Failed connecting smtp server")
return return
# 与服务端单次交互及显示到界面
def comm(msg: str): def comm(msg: str):
msg += "\r\n" msg += "\r\n"
ss.sendall(msg.encode()) ss.sendall(msg.encode())
@ -72,15 +79,15 @@ class LogWindow(QDialog, Ui_Dialog):
self.textBrowser.append("S: " + ss.recv(1 << 20).decode()) self.textBrowser.append("S: " + ss.recv(1 << 20).decode())
self.textBrowser.moveCursor(QTextCursor.End) self.textBrowser.moveCursor(QTextCursor.End)
comm("HELO " + servaddr) comm("HELO " + servaddr) # HELO
comm("AUTH LOGIN") comm("AUTH LOGIN") # 现在的SMTP服务器要认证了
comm(b64encode(username.encode()).decode()) comm(b64encode(username.encode()).decode()) # 发送用户名
comm(b64encode(password.encode()).decode()) comm(b64encode(password.encode()).decode()) # 发送密码
comm("MAIL FROM:<{}>".format(username)) comm("MAIL FROM:<{}>".format(username)) # 发件人
comm("RCPT TO:<{}>".format(receiver)) comm("RCPT TO:<{}>".format(receiver)) # 收件人
comm("DATA") comm("DATA") # 开始实际数据
comm('\r\n'.join(["Subject: " + subjects, "", contents, "."])) comm('\r\n'.join(["Subject: " + subjects, "", contents, "."])) # 主题与正文
comm("QUIT") comm("QUIT") # 结束
if __name__ == "__main__": if __name__ == "__main__":

@ -1,11 +1,14 @@
from gevent import monkey, spawn from gevent import monkey, spawn
monkey.patch_all() monkey.patch_all()
# 引入协程库并替换python的各种内部实现
from socket import * from socket import *
from typing import * from typing import *
# 当前连接
conns: Set[Tuple[socket, Any]] = set() conns: Set[Tuple[socket, Any]] = set()
# 将消息发至所有客户端
def boardcast(message: str): def boardcast(message: str):
print(message) print(message)
for conn, addr in conns: for conn, addr in conns:
@ -13,6 +16,7 @@ def boardcast(message: str):
conn.send(message.encode()) conn.send(message.encode())
# 处理一个新的传入连接
def process_connection(conn: socket, addr): def process_connection(conn: socket, addr):
conns.add((conn, addr)) conns.add((conn, addr))
boardcast('server:global:{} connected.'.format(addr)) boardcast('server:global:{} connected.'.format(addr))
@ -22,6 +26,7 @@ def process_connection(conn: socket, addr):
if not res_raw: if not res_raw:
raise raise
except Exception: except Exception:
# 异常处理:移除当前连接并通知剩余用户
conns.remove((conn, addr)) conns.remove((conn, addr))
boardcast('server:global:{} disconnected.'.format(addr)) boardcast('server:global:{} disconnected.'.format(addr))
return return
@ -35,4 +40,5 @@ if __name__ == "__main__":
s.listen(1 << 16) s.listen(1 << 16)
while True: while True:
conn, addr = s.accept() conn, addr = s.accept()
# 启动一个新的协程来处理连接
spawn(process_connection, conn, addr) spawn(process_connection, conn, addr)

Loading…
Cancel
Save