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

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

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

Loading…
Cancel
Save