我尝试使用自己的telnet客户端与ftp服务器(特别是它的ftp.de.debian.org)进行交互。它正常工作,但在匿名登录后,ftp服务器发送欢迎消息 - 它可以在不同的包中发送数据(我是对吗?),当它发生时 - 我无法从套接字中读取它作为整个消息。当我使用GNU telnet客户端时 - 欢迎消息一次打印出来。
我尝试使用select syscall,非阻塞套接字,但结果是相同的 - 接收数据块,套接字就绪,打印出数据。 当前实施"接收响应"功能:
void recv_response(int fd, char *resp_buff, int buff_size) {
memset(resp_buff, 0, 1024);
fd_set rfds;
struct timeval time;
int ret_val;
FD_ZERO(&rfds);
FD_SET(fd, &rfds);
time.tv_sec = 1;
time.tv_usec = 0;
if ((ret_val = recv(fd, resp_buff, 1024, 0)) < 0 && errno != EAGAIN) {
exit_on_error();
} else {
select(fd+1, &rfds, NULL, NULL, &time);
ret_val = recv(fd, resp_buff, 1024, 0);
printf("Bytes received: %d\n", ret_val);
printf("%s\n", resp_buff);
}
}
在从插座读取之前,我只使用睡眠1秒获得了正确的结果。
使用GNU telnet客户端的strace示例显示recvfrom得到了碎片消息,第一部分是142,另一部分是157。
recvfrom(3, "230- Welcome to ftp.de.debian.or"..., 8192, 0, NULL, NULL) = 142
select(4, [0 3], [1], [3], {0, 0}) = 1 (out [1], left {0, 0})
write(1, "230- Welcome to ftp.de.debian.or"..., 139230- Welcome to ftp.de.debian.org,
hosted at Faculty of Computer Science,
Technische Universitaet Dresden, Germany.
) = 139
select(4, [0 3], [], [3], NULL) = 1 (in [3])
recvfrom(3, " \r\n If have any unusual problem"..., 8192, 0, NULL, NULL) = 157
select(4, [0 3], [1], [3], {0, 0}) = 1 (out [1], left {0, 0})
write(1, " \n If have any unusual problems"..., 152
If have any unusual problems,
please report them via e-mail to: ftpadm@inf.tu-dresden.de
230 Anonymous access granted, restrictions apply
) = 152
那么,telnet客户端如何确定有另一部分,第一部分不应该打印到第二部分?
答案 0 :(得分:0)
// you need to know how to determine if whole message has been received.
// in general, for the first char of input, use a longish wait time
// for following characters use a very short wait time.
// do this in a sequence like:
// set number of char read to 0
// set timeout to message start wait time
// while(1)
// selectReturn = select() using timeout
// if 0 == selectReturn (timeout event occurred, no message available or all chars read)
// then exit loop
// if(0 > selectReturn (error occurred, exit loop to handle error
// then exit loop
// if 0 < selectReturn then
// then,
// read a char and toss
// incr number of char read, (for later comparison for validity)
// set timeout to inter char wait time
// end if
// end while
//
答案 1 :(得分:0)
如果要与ftp服务器通信,则必须至少在级别实施ftp传输协议才能将输入流拆分为消息。您可以在此处找到ftp协议的规范:https://www.ietf.org/rfc/rfc959.txt。关于ftp消息格式,它说:
回复定义为包含3位数代码,后跟Space ,后跟一行文字(其中一些最大行长度 已被指定),并由Telnet终止线终止 码。然而,在某些情况下,文本会长于 单行。在这些情况下,必须将完整的文本放在括号内 因此,用户进程知道何时可以停止阅读回复(即 停止处理控制连接上的输入)并继续执行其他操作 的东西。这需要第一行的特殊格式 表示不止一条线路即将到来,另一条线路正在接通 最后一行将其指定为最后一行。其中至少有一个必须 包含适当的回复代码以指示状态 交易。为了满足所有派系,两者都决定了 第一行和最后一行代码应该相同。
因此,多行回复的格式是第一行 将以确切的所需回复代码开头,紧随其后 立即由连字符,&#34; - &#34; (也称为Minus),其次是 文本。最后一行将以相同的代码开头,然后是 立即由Space,可选的一些文本和Telnet 行尾代码。
For example:
123-First line
Second line
234 A line beginning with numbers
123 The last line
请注意,执行的recv
的数量与服务器发送的消息数量之间没有对应关系。 TCP / IP连接只是一个字节流,可以分解为块或由路上的任何路由器以及您自己的系统连接在一起。
答案 2 :(得分:0)
实际上,telnet确实不做你所描述的事情。您可以看到比较输入和输出。它有142个八位字节并打印139个字节(网络式CRLF行结束转换为单个LF),但没有第一个响应行的终止符。然后,第二个块从第一个响应行的行终止符开始。因此,telnet客户端按原样中继其输入,没有任何灌浆。
这里有两件事特别重要:
要获得进一步的进展,请说明您到底想要达到的目标。这是telnet客户端,FTP客户端还是其他什么?