2013-12-08 29 views
0

我一直在嘗試爲yahoo寫一個POP3客戶端,但每當我發送有效命令時,我都無法從socket讀取。我知道創建通過網絡處理plaintext的應用程序並不安全,但我現在只想更詳細地瞭解POP3在Linux中使用C的純文本POP3客戶端 - 向服務器發送命令後發生錯誤

我創建使用QT圖形界面,但我相信這是無關緊要的了。

首先,我確信,雅虎支持plaintext通信在終端運行簡單的命令:

telnet pop.mail.yahoo.com 110 
+OK hello from popgate-0.8.0.504347 pop011.mail.ir2.yahoo.com 
user validuser 
+OK password required. 
pass validpassword 
+OK maildrop ready, 100 messages (134513 octets) (13531) 

這是我如何處理打開連接:

int openConnection(char ip[], int port) 
{ 
//descriptor of socket 
int sd; 

struct sockaddr_in server; 


//fill in server structure 
server.sin_family = AF_INET; 
server.sin_addr.s_addr = inet_addr (ip); 
server.sin_port = htons (port); 

//create communication socket 
if ((sd = socket (AF_INET, SOCK_STREAM, 0)) == -1) 
    { 
     //if cannot create, return error 
     return -2; 
    } 

if (connect (sd, (struct sockaddr *) &server,sizeof (struct sockaddr)) == -1) 
    { 
    return -1; 
    } 

return sd; 

//values to be returned 
//-2 - could not create socket 
//-1 - could not connect to server 
//socket descriptor in case of success 
} 

我沒有得到任何我打電話時創建套接字和連接的問題

int sd = openConnection ("188.125.68.106", 110) 

(188.125.68.106 = pop.mail.yahoo.com的IP)

我甚至可以讀取歡迎消息,而不使用選擇或epoll的。

char message[80]; 
read (sd, message, 80); 

消息:

+OK hello from popgate-0.8.0.504347 pop011.mail.ir2.yahoo.com 

我還可以發送各種無效的命令,並讀取錯誤返回

int sd = openConnection ("188.125.68.106", 110) 
write (sd,"this command is invalid",80); 
char messageFromS [80]; 
bzero (messageFromS, 80); 
read (sd,messageFromS,80); 

而且我得到的

-ERR invalid command  
字裏行間的東西

但是每當我最後一個有效的命令,我的客戶打電話只是閱讀後凍結了,我必須強制退出

write (sd,"user validuser",80); 
char messageFromS [80]; 
bzero (messageFromS, 80); 
read (sd,messageFromS,80); 

之後,我決定使用select(),因爲我知道這是一個很好的做法,也許它可以得到好的結果

//function returns true (1) if we can read from the socket 
bool isClosed(int sock) 
{ 
fd_set rfd; 
FD_ZERO(&rfd); 
FD_SET(sock, &rfd); 
timeval tv; 

//timeout value is set to 5 seconds 
tv.tv_sec = 5; 

select(sock+1, &rfd, 0, 0, &tv); 
if (!FD_ISSET(sock, &rfd)) 
    return false; 
int n = 0; 
ioctl(sock, FIONREAD, &n); 
return n == 0; 
} 

但似乎每當我打電話

isClosed(sd) 

它總是返回true。

這是我想不出任何其他選項的地步。 Telnet有什麼,我的微型客戶端沒有?

編輯:謝謝您的解答。 我讀通過接收的字節一個字節的所有信息發揮各地,直到它找到了一個終止符(顯然這不是NULL),並且,之後再閱讀POP3(http://tools.ietf.org/html/rfc1081)的RFC密切,我意識到,我是不是正確結束我的命令。我應該在發送的所有命令的末尾添加'\ r'和'\ n'。 我也檢查了select()命令,它返回-1,並設置tv.tv_usec = 0,這幾乎解決了它。

+1

仔細閱讀該男子-頁的read()/ write()方法和學習至少在插座的兩個功能不一定接收/發送儘可能多的字節,因爲他們被告知,但少數。因此,圍繞此類呼叫進行計數,直到收到/發送所有數據都是一個好主意,而不是說必不可少。如果您不知道要接收的數據量,請逐字節讀取。 – alk

+1

您應該檢查'select'的返回值。我敢打賭它是'-1','errno'設置爲'EINVAL'。我這麼認爲的原因是因爲你沒有正確初始化「電視」結構。 'tv_usec'成員將是一個隨機值,可能是非法的。 –

+2

哦,你當然應該檢查來自所有可能失敗的函數的錯誤。除非函數實際失敗,否則不要檢查'errno'。 –

回答

0

謝謝你的回答。我玩弄了所有逐字節接收的消息,直到找到終止字符(顯然它不是NULL),並且在重新讀取pop3(http://tools.ietf.org/html/rfc1081)的RFC後,我意識到我並不是正確結束我的命令。我應該在發送的所有命令的末尾添加'\ r'和'\ n'。 我也檢查了select()命令,它返回-1,並設置tv.tv_usec = 0,這幾乎解決了它。

- Shoshinsha purogurama

相關問題