【问题标题】:Plaintext POP3 client using C in Linux - error reading after sending command to server在 Linux 中使用 C 的纯文本 POP3 客户端 - 向服务器发送命令后读取错误
【发布时间】:2013-12-08 09:57:25
【问题描述】:

我一直在尝试为 yahoo 编写 POP3 客户端,但是每当我发送有效命令时,我都无法从 socket 读取。我知道在网络上创建处理plaintext 的应用程序是不安全的,但我现在只是想了解更多关于POP3 的信息。

我正在使用 QT 创建一个图形界面,但我认为这暂时无关紧要。

首先,我通过在终端中运行简单的命令来确保 yahoo 支持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)

我什至可以在不使用 select 或 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    

但是每当我发送一个有效的命令时,我的客户端在调用 read 后就会死机,我必须强制退出

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 的 RFC(https://www.rfc-editor.org/rfc/rfc1081)之后,我意识到我不是t 正确结束我的命令。我应该将 '\r' 和 '\n' 附加到所有发送的命令的末尾。 我还检查了 select () 命令,它返回 -1 并设置 tv.tv_usec = 0 几乎解决了它。

【问题讨论】:

  • 仔细阅读 read()/write() 的手册页并了解至少对于套接字,这两个函数不一定接收/发送尽可能多的字节,但很少。因此,围绕此类呼叫计数直到所有数据都已接收/发送是一个好主意,而不是说必不可少的必要性。如果您不知道要接收的数据量,请逐字节读取。
  • 你应该检查select的返回值。我敢打赌它是-1 并且errno 设置为EINVAL。我这么认为的原因是你没有正确初始化tv 结构。 tv_usec 成员将是一个随机值,并且可能是非法的。
  • 哦,您当然应该检查可能失败的所有函数的错误。并且不要检查errno,除非函数确实失败了。

标签: c linux sockets client pop3


【解决方案1】:

感谢您的回答。 我尝试逐字节阅读收到的所有消息,直到它找到一个终止字符(显然它不是 NULL),并且在仔细阅读 pop3 的 RFC(https://www.rfc-editor.org/rfc/rfc1081)之后,我意识到我不是t 正确结束我的命令。我应该将 '\r' 和 '\n' 附加到所有发送的命令的末尾。 我还检查了 select () 命令,它返回 -1 并设置 tv.tv_usec = 0 几乎解决了它。

– 小新社purogurama

【讨论】:

    猜你喜欢
    • 2020-12-16
    • 1970-01-01
    • 1970-01-01
    • 2016-09-16
    • 2014-05-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多