我一直在嘗試爲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,這幾乎解決了它。
仔細閱讀該男子-頁的read()/ write()方法和學習至少在插座的兩個功能不一定接收/發送儘可能多的字節,因爲他們被告知,但少數。因此,圍繞此類呼叫進行計數,直到收到/發送所有數據都是一個好主意,而不是說必不可少。如果您不知道要接收的數據量,請逐字節讀取。 – alk
您應該檢查'select'的返回值。我敢打賭它是'-1','errno'設置爲'EINVAL'。我這麼認爲的原因是因爲你沒有正確初始化「電視」結構。 'tv_usec'成員將是一個隨機值,可能是非法的。 –
哦,你當然應該檢查來自所有可能失敗的函數的錯誤。除非函數實際失敗,否則不要檢查'errno'。 –