我正在尝试运行LIST
命令来显示文件,但是当我运行它时,它会显示我想要的所有文件,但它只是挂在那里,并且不会破坏菜单。列表的最后3个字符总是一个换行符后跟一个句号然后换行符,所以我把它放在一个if
语句中来检查突破并关闭套接字,但它没有,我错过了什么?
case 'l':
case 'L':
//Handle L case
sprintf(buff, "LIST\n");
send(sockfd, buff, 1000, 0);
int length = strlen(buff);
while ((rsize = recv(sockfd, buff, 1000, 0)) > 0)
{
fwrite(buff, rsize, 1, stdout);
if ( buff[length-3] == '\n' && buff[length-2] == '.' && buff[length-1] == '\n' )
{
break;
}
}
close(sockfd);
break;
答案 0 :(得分:2)
这是你的问题:
if ( buff[length-3] ...
length
来自strlen(buff)
,此时buff
包含您发送的数据,而非您收到的数据,因此buff[length-3]
可能甚至不接近输入数据的末尾,最长可达1000
个字符。
您应该专注于rsize
,这是您收到的字节数,而不是length
。
recv()
在你的结尾中意外停止 - 行序列,特别是如果它在读取少于三个字符后停止,那么你将非法使用数组的负索引。最好编写一个函数来从套接字中读取整行并将其存储在缓冲区中,然后只需调用if ( !strcmp(buffer, ".") )
即可知道何时完成。
以下是一个例子:
#include <unistd.h>
#include <errno.h>
#include <string.h>
ssize_t socket_readline(const int socket, char * buffer, const size_t max_len) {
ssize_t num_read, total_read = 0;
bool finished = false;
memset(buffer, 0, max_len);
for ( size_t index = 0; !finished && index < (max_len - 1); ++index ) {
num_read = read(socket, &buffer[index], 1);
if ( num_read == -1 ) {
if ( errno == EINTR ) {
continue; /* Interrupted by signal, so continue */
}
else {
return -1; /* Other read() error, return error code */
}
}
else {
if ( buffer[index] == '\n' ) {
buffer[index] = '\0'; /* Remove newline */
finished = true; /* End of line, so stop */
}
else {
++total_read;
}
}
}
return total_read;
}
对每个角色使用系统调用是一个开销,但如果你不这样做,你将不得不存储你在某处读取的其他角色,所以除非你想编写自己的缓冲设施,这是最好的选择。
顺便说一句,您还应该检查send()
(以及所有系统调用)的返回,因为不保证一次性发送所有字符,您可能需要额外的尝试。
答案 1 :(得分:1)
你不能单靠rsize
。想想如果对第一个recv()
的{{1}}的一次调用结束,然后下一个'\n'
收到recv()
,会发生什么。或者,如果'.'
没有收到&gt; = 3个字节开头。您将无法在单个if语句中检查recv()
,就像您要尝试的那样。
你应该做的是将套接字数据读入缓冲区,直到遇到"\n.\n"
(不将其存储在缓冲区中),然后根据需要处理缓冲区并清除它,然后重复直到缓冲区本身只包含'\n'
。
尝试这样的事情:
'.'
可替换地:
case 'l':
case 'L':
{
//Handle L case
int linecapacity = 1000;
char *line = (char*) malloc(linecapacity);
if (line)
{
int linelength = 0;
if (send(sockfd, "LIST\n", 5, 0) == 5)
{
bool stop = false;
while (!stop)
{
rsize = recv(sockfd, buff, 1000, 0);
if (rsize <= 0) break;
fwrite(buff, rsize, 1, stdout);
char *start = buff;
char *end = &buff[rsize];
while ((start < end) && (!stop))
{
char *ptr = (char*) memchr(start, '\n', end-start);
if (!ptr) ptr = end;
length = (ptr - start);
int needed = (linelength + length);
if (needed > linecapacity)
{
char *newline = realloc(line, needed);
if (!newline)
{
stop = true;
break;
}
line = newline;
linecapacity = needed;
}
memcpy(buff, &line[linelength], length);
linelength += length;
if ((linelength == 1) && (line[0] == '.'))
{
stop = true;
break;
}
// process line up to linelength characters as needed...
linelength = 0;
start = ptr + 1;
}
}
}
free(line);
}
close(sockfd);
break;
}