目錄html
1、前言:QQ郵件發送程序java
3、實現多線程接收小程序
一、鏈接按鈕網絡
二、發送按鈕 多線程
5、QQ郵件發送效果演示app
6、總結socket
在上一篇《Java網絡編程:實現QQ郵件發送客戶端》,咱們解決了telnet終端發送郵件誤操做帶來的麻煩,實現了本身的簡單Java界面進行發送QQ郵件,界面可直接與smtp.qq.com服務器端創建鏈接,經過命令方式發送郵件信息。tcp
這一篇爲QQ郵件發送客戶端程序設計的下篇,將實現更加完善的功能,不用命令發送方式,相似平常發送郵件,直接編寫郵件標題、內容,而後直接發送便可,基本實現了QQ郵件發送客戶端的功能,操做更加簡便,實現本身的QQ郵件發送端,之後就用這個啦。
原來的終端發送逐步操做以下:
HELO hostname //回車,hostname能夠是IP或其餘隨意別名
AUTH LOGIN //回車後,先粘貼base64程序編碼的完整郵箱名並回車;再粘貼base64編碼的受權碼並回車
MAIL FROM:<czh_charzeus@qq.com> //在這裏填寫本身的郵箱地址,用於發送郵件(注意冒號後面別有空格)
RCPT TO:<czh_charzeus@qq.com> //接收方的郵箱,在這裏暫時填寫和上面同樣的郵箱地址,即本身發送郵件給本身,驗證是否成功
DATA //回車,接下來開始發送郵件頭相關內容
Subject: the simple mail // 郵件的標題,回車 //在這裏再多發送一行空行,來分隔郵件內容,下面就是郵件正文內容
Hello,the mail content! 測試發送郵件! //控制檯中中文會變成?的亂碼,但不影響接受者接收到中文內容
. //在郵件正文發送完畢後,單獨用一行輸入一個小圓點,做爲結束標誌,而後回車
QUIT //結束通訊(含4次握手斷開)
所以,咱們要避免這種繁瑣的命令形式,只須要將每一個語句封裝到發送程序裏面,在用戶界面則無需進行命令的輸入,只須要輸入內容。
實現的方法很簡單,只須要在發送按鈕中,把命令加進去就能夠,以下:
tcpMailClient.send("HELO friend"); tcpMailClient.send("auth login"); String userNameBase64= encode(senderMail); tcpMailClient.send(userNameBase64); String authCode = encode("你的受權碼"); tcpMailClient.send(authCode); String msg = "mail from:<"+senderMail+">"; tcpMailClient.send(msg); msg = "rcpt to:<"+receiverMail+">"; tcpMailClient.send(msg); tcpMailClient.send("data"); msg="from:"+senderMail; tcpMailClient.send(msg); msg="to:"+receiverMail; tcpMailClient.send(msg); msg="subject:"+sub; tcpMailClient.send(msg); tcpMailClient.send("\n"); // tcpMailClient.send("這是一封測試java客戶端自動發送功能的郵件。");
tcpMailClient.send(content); tcpMailClient.send("."); tcpMailClient.send("quit");
從代碼能夠看到,當發送按鈕一點擊後,程序會執行全部語句,咱們從上一篇知道,郵件服務器也會返回信息,因此QQ客戶端須要使用多線程的技術,來處理返回信息,避免單線程阻塞致使發送不成功。
根據前面分析,將客戶端接收的功能交給一個線程處理,就可以達到目的,不會由於接收語句阻塞使得主進程卡住。
因此,將線程放到鏈接按鈕裏面爲好,在成功鏈接服務器以後,程序就啓動線程,時機正好。鏈接按鈕中的線程代碼以下:
//用於接收服務器信息的單獨線程
readThread = new Thread(()->{ String receiveMsg=null;//從服務器接收一串字符
while ((receiveMsg=tcpMailClient.receive())!=null){ String msgTemp = receiveMsg; Platform.runLater(()->{ taDisplay.appendText(msgTemp+"\n"); }); } Platform.runLater(()->{ taDisplay.appendText("對話已關閉!\n"); }); }); readThread.start();
程序執行發送每一條命令語句的速度比咱們本身輸入發送要快許多,爲了不QQ郵件接收服務器沒法及時響應出錯,程序自動發送過程當中須要設置必定的睡眠等待時間,在send方法設置等待200ms或者500ms。
QQ郵件客戶端實現代碼可見上一篇Java網絡編程:實現QQ郵件發送客戶端,這裏再也不重複介紹。
public void send(String msg){ //輸出字符流,由socket調用系統底層函數,經網卡發送字節流
pw.println(msg); try { //進行郵件交互,發送smtp指令之間應該暫停一段時間
Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } }
界面的設計與以往相似,能夠根據本身的需求設計不一樣的界面風格,可參考本文前言或者總結部分的系列文章進行實現。這裏給出關鍵按鈕的完整代碼。
//鏈接按鈕 btConn.setOnAction(event -> { String ip=ipAddress.getText().trim(); String port=tfport.getText().trim(); try { tcpMailClient = new TCPMailClient(ip, port); //成功鏈接服務器,接受服務器發來的第一條歡迎信息 String firstMsg=tcpMailClient.receive(); taDisplay.appendText(firstMsg+"\n"); //用於接收服務器信息的單獨線程 readThread = new Thread(()->{ String receiveMsg=null;//從服務器接收一串字符 while ((receiveMsg=tcpMailClient.receive())!=null){ //lambda表達式不能直接訪問外部非final類型局部變量,須要定義一個臨時變量 //若將receiveMsg定義爲類成員變量,則無需臨時變量 String msgTemp = receiveMsg; Platform.runLater(()->{ taDisplay.appendText(msgTemp+"\n"); }); } Platform.runLater(()->{ taDisplay.appendText("對話已關閉!\n"); }); }); readThread.start(); } catch (IOException e) { e.printStackTrace(); } });
//發送按鈕 btnSend.setOnAction(event -> { String senderMail = mail.getText().trim(); String receiverMail = toMail.getText().trim(); String sub = subject.getText(); String content = tfSend.getText(); try { tcpMailClient.send("HELO friend"); tcpMailClient.send("auth login"); String userNameBase64= encode(senderMail); tcpMailClient.send(userNameBase64); String authCode = encode("你的受權碼"); tcpMailClient.send(authCode); String msg = "mail from:<"+senderMail+">"; tcpMailClient.send(msg); msg = "rcpt to:<"+receiverMail+">"; tcpMailClient.send(msg); tcpMailClient.send("data"); msg="from:"+senderMail; tcpMailClient.send(msg); msg="to:"+receiverMail; tcpMailClient.send(msg); msg="subject:"+sub; tcpMailClient.send(msg); tcpMailClient.send("\n"); // tcpMailClient.send("這是一封測試java客戶端自動發送功能的郵件。"); tcpMailClient.send(content); tcpMailClient.send("."); tcpMailClient.send("quit"); }catch (Exception e){ taDisplay.appendText("服務器鏈接失敗!"+e.getMessage()+"\n"); } });
QQ客戶端的程序能夠沿用以前的內容,詳見這篇:基於TCP協議網絡socket編程(java實現C/S通訊)
細心的讀者能夠發現,在我點擊發送以後,程序卡斷了一會,其實就是由於我設置發送睡眠1000ms,實際能夠發送成功,建議設置200ms或以上!
發送到本身QQ郵箱:
發送到本身的126郵箱進行測試:
這一篇爲QQ郵件發送客戶端程序設計的下篇,記錄了實現的關鍵部分,不用命令發送方式,相似平常發送郵件,直接編寫郵件標題、內容,而後直接發送便可,基本實現了QQ郵件發送客戶端的功能,操做更加簡便。根據本篇的知識內容,後面能夠實現更加完善的QQ郵件發送小程序,增長一系列小功能!
若是以爲不錯歡迎「一鍵三連」哦,點贊收藏關注,有問題直接評論,交流學習!
個人博客園:https://www.cnblogs.com/chenzhenhong/p/14331829.html
個人CSDN博客:https://blog.csdn.net/Charzous/article/details/111148425