利用socket編程,Java基於pop3實現收郵件的功能

java實現POP3郵件客戶端

java實現POP3郵件客戶端

第一步:利用socket編程,在客戶端與服務器端之間建立TCP連接,POP3默認端口號爲110;

第二步:通過pop3定義的各種命令,用戶可以操作自己的郵箱。

注:

POP3協議中有三種狀態,認正狀態,處理狀態,和更新狀態。 命令的執行可以改變協議的狀態,而對於具體的某命令,它只能在具體的某狀態下使用,這些請參看表1和RFC193。

客戶機與服務器剛與服務器建立連接時,它的狀態爲認證狀態;一旦客戶機提供了自己身份並被成功地確認,即由認可狀態轉入處理狀態; 在完成相應的操作後客戶機發出QUIT命令(具體說明見後續內容),則進入更新狀態,更新之後又重返認可狀態;當然在認可狀態下執行QUIT命令,可釋放連接。狀態間的轉移如圖 1所示。

---建立連接---|認可|--認證成功--|處理|--執行QUIT--|更新|        

            |_______ -QUIT結束_________________|

 

 

常用命令:

命令

參數

使用在何種狀態中

描述

USER

Username

認證

此命令與下面的pass命令若成功,將導致狀態轉換

PASS

Password

認證

此命令若成功,狀態轉化爲更新

APOP

Name,Digest

認證

Digest是MD5消息摘要

STAT

None

處理

請求服務器發回關於郵箱的統計資料,如郵件總數和總字節數

UIDL

[Msg#](郵件號,下同)

處理

返回郵件的唯一標識符,POP3會話的每個標識符都將是唯一的

LIST

[Msg#]

處理

返回郵件的唯一標識符,POP3會話的每個標識符都將是唯一的

RETR

[Msg#]

處理

返回由參數標識的郵件的全部文本

DELE

[Msg#]

處理

服務器將由參數標識的郵件標記爲刪除,由QUIT命令執行

TOP

[Msg#]

處理

服務器將返回由參數標識的郵件的郵件頭+前n行內容,n必須是正整數

NOOP

None

處理

服務器返回一個肯定的響應,用於測試連接是否成功

QUIT

None

處理、認證

1)        如果服務器處於“處理”狀態,麼將進入“更新”狀態以刪除任何標記爲刪除的郵件,並重返“認證”狀態。

2)        如果服務器處於“認證”狀態,則結束會話,退出連接

 

/**
 * @author hewenwu
 * 這個程序實現了基於POP3協議的郵件接收功能
 * */
package mail;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.StringTokenizer;

public class POP3Client {

    private Socket socket = null;
 
    private boolean debug=true;
 
    public static void main(String[] args) throws UnknownHostException, IOException {
  
        String server="pop3.163.com";//POP3服務器地址
  
        String user="**********";//用戶名,填寫自己的郵箱用戶名
  
        String password="*********";//密碼,填寫自己的密碼
 
        POP3Client pop3Client=new POP3Client(server,110);
 
    pop3Client.recieveMail(user,password);
 }
 
    /*構造函數*/
    public POP3Client(String server,int port) throws UnknownHostException, IOException{
        try{
   
            socket=new Socket(server,port);//在新建socket的時候就已經與服務器建立了連接

        }catch(Exception e){
   
            e.printStackTrace();
 
        }finally{
 
            System.out.println("建立連接!");
        }
    }
 
    
    //接收郵件程序
    public boolean recieveMail(String user,String password){
            
        try {
                BufferedReader in=new BufferedReader(new InputStreamReader(socket.getInputStream()));
       
                BufferedWriter out=new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
      
                user(user,in,out);//輸入用戶名
       
                System.out.println("user 命令執行完畢!");
                
                pass(password,in,out);//輸入密碼
      
                System.out.println("pass 命令執行完畢!");
      
                stat(in,out);
      
                System.out.println("stat 命令執行完畢!");
                
                list(in,out);
                  
                System.out.println("list 命令執行完畢!");
                
                retr(2,in,out);
                
                System.out.println("retr 命令執行完畢!");
      
                quit(in,out);
                
                System.out.println("quit 命令執行完畢!");
     
            }catch(Exception e){
      
                e.printStackTrace();
      
                return false;
            }
            return true;
        }
    
    //得到服務器返回的一行命令
    public String getReturn(BufferedReader in){
    
        String line="";
  
        try{
            line=in.readLine();
   
            if(debug){
   
                System.out.println("服務器返回狀態:"+line);
            }
        }catch(Exception e){
 
            e.printStackTrace();
        }
        return line;
    }
 
    //從返回的命令中得到第一個字段,也就是服務器的返回狀態碼(+OK或者-ERR)
    public String getResult(String line){

        StringTokenizer st=new StringTokenizer(line," ");

        return st.nextToken();
    }
 
    //發送命令
    private String sendServer(String str,BufferedReader in,BufferedWriter out) throws IOException{
        
        out.write(str);//發送命令
 
        out.newLine();//發送空行
 
        out.flush();//清空緩衝區
  
        if(debug){
  
            System.out.println("已發送命令:"+str);
         }
         return getReturn(in);
     }
 
    //user命令
    
    public void user(String user,BufferedReader in,BufferedWriter out) throws IOException{

        String result = null;
 
        result=getResult(getReturn(in));//先檢測連接服務器是否已經成功
 
        if(!"+OK".equals(result)){
   
            throw new IOException("連接服務器失敗!");
        }
 
        result=getResult(sendServer("user "+user,in,out));//發送user命令

        if(!"+OK".equals(result)){
  
            throw new IOException("用戶名錯誤!");
        }
    }
 
    //pass命令
    public void pass(String password,BufferedReader in,BufferedWriter out) throws IOException{
 
        String result = null;
 
        result = getResult(sendServer("pass "+password,in,out)); 
 
        if(!"+OK".equals(result)){

            throw new IOException("密碼錯誤!");
        }
    }

    
    //stat命令

    public int stat(BufferedReader in,BufferedWriter out) throws IOException{
 
        String result = null;
 
        String line = null;
  
        int mailNum = 0;
 
        line=sendServer("stat",in,out); 
 
        StringTokenizer st=new StringTokenizer(line," ");
  
        result=st.nextToken();
  
        if(st.hasMoreTokens())
 
            mailNum=Integer.parseInt(st.nextToken());
 
        else{
            
            mailNum=0;
            
        }
        
        if(!"+OK".equals(result)){
 
            throw new IOException("查看郵箱狀態出錯!");
        }
 
        System.out.println("共有郵件"+mailNum+"封");
        return mailNum;
 }
    
        //無參數list命令
        public void list(BufferedReader in,BufferedWriter out) throws IOException{
     
            String message = "";
     
            String line = null;
     
            line=sendServer("list",in,out); 
     
            while(!".".equalsIgnoreCase(line)){
       
                message=message+line+"\n";    
            
                line=in.readLine().toString();
                }
            
                System.out.println(message);
     }
        
          //帶參數list命令
                public void list_one(int mailNumber ,BufferedReader in,BufferedWriter out) throws IOException{

                    String result = null;
                     
                    result = getResult(sendServer("list "+mailNumber,in,out)); 
             
                    if(!"+OK".equals(result)){

                        throw new IOException("list錯誤!");
                    }
             }
 
 //得到郵件詳細信息
 
    public String getMessagedetail(BufferedReader in) throws UnsupportedEncodingException{
 
        String message = "";
  
        String line = null;
 
        try{
            line=in.readLine().toString();
  
            while(!".".equalsIgnoreCase(line)){
   
                message=message+line+"\n";
   
                line=in.readLine().toString();
            }
        }catch(Exception e){
  
            e.printStackTrace();
        }
    
            return message;
    }
 
 //retr命令
    public void retr(int mailNum,BufferedReader in,BufferedWriter out) throws IOException, InterruptedException{
  
            String result = null;
   
            result=getResult(sendServer("retr "+mailNum,in,out));
  
            if(!"+OK".equals(result)){
  
                throw new IOException("接收郵件出錯!");
            }
            
            System.out.println("第"+mailNum+"封");
            System.out.println(getMessagedetail(in));
            Thread.sleep(3000);
    }
 
    //退出
    public void quit(BufferedReader in,BufferedWriter out) throws IOException{
 
        String result;
 
        result=getResult(sendServer("QUIT",in,out));
 
        if(!"+OK".equals(result)){
  
            throw new IOException("未能正確退出");
        }
    }
 
}

 

總結:

    這個項目其實非常簡單,關鍵要理解兩個方面,一是怎麼利用socket編程連接到服務器,二是POP3協議命令的格式和返回值的格式。理解了這兩個方面,就好做了。首先建立連接,然後通過socket對象獲取輸入輸出流對象,在輸入輸出流對象上發送命令和接受返回值,接收到返回值之後自己本地處理這些返回值就行啦。

說到輸入輸出流,java的輸入輸出流真的比較多,有點不好記,但是每個輸出流的原理是一樣,而且有封裝的特性。接下來一定要狠狠的把它搞懂了!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章