问题描述
我已经使用linux tcp套接字编写了服务器客户端程序。
客户向服务器询问当前目录文件的列表 发送 ls 命令
server replies all the list of files in server dir.
I was testing it for more files in server working dir.
server response format in the buffer
file/dir [tab] file_name [tab] file_change_time
for each 1000 files to client.
服务器发送代码:
#define BUFSIZE 1400
void lsfun(node_t *pclient)
{
DIR *directory;
int status;
int cpylen = 0;
int msglen = 0;
unsigned int tt_count = 0;
unsigned int no_files = 0;
unsigned int no_sends = 0;
int clientfd = *(pclient->client_socket);
char *filectime;
char *buffer = malloc(BUFSIZE * sizeof(char));
char *tmp = malloc(BUFSIZE * sizeof(char));
char ending[] = "#####";
struct dirent *dir;
struct stat type;
pthread_mutex_lock(&lock);
chdir(pclient->pwd);
directory = opendir(".");
pthread_mutex_unlock(&lock);
if(tmp == NULL || buffer == NULL)
printf("malloc error for client conn:%d\n",clientfd);
if(directory)
{
while((dir = readdir(directory)) != NULL)
{
if(!strcmp(dir->d_name,".") || !strcmp(dir->d_name,".."))
continue;
status = stat(dir->d_name,&type);
if(status == 0)
{
filectime = ctime(&type.st_ctime);
if(dir->d_type != DT_REG)
cpylen = snprintf(tmp,BUFSIZE,"dir\t%s\t%s",dir->d_name,filectime);
else
cpylen = snprintf(tmp,"file\t%s\t%s",filectime);
tmp[cpylen] = 0;
if((cpylen + msglen) < BUFSIZE)
{
strlcpy(buffer + msglen,tmp,cpylen);
msglen += cpylen;
no_files += 1;
}
else
{
tt_count += msglen;
printf("%s",buffer);
fflush(stdout);
send(clientfd,buffer,strlen(buffer),0);
memset(buffer,BUFSIZE + 5);
snprintf(buffer,cpylen,"%s",tmp);
msglen = cpylen;
cpylen = 0;
no_files += 1;
no_sends += 1;
}
}
else
{
cpylen = snprintf(buffer + msglen,"%s%s\n","file stat error:",dir->d_name);
msglen += cpylen;
}
memset(tmp,BUFSIZE);
}
}
cpylen = strlen(buffer);
if(msglen == cpylen)
send(clientfd,0);
send(clientfd,ending,strlen(ending),0); //sending msg ending for client read to close
printf("\nlssize :%d\tnofile:%d,msglen:%d\tcpylen:%d\tno_sends:%d\n",tt_count + msglen,no_files,msglen,no_sends);
free(tmp);
free(buffer);
closedir(directory);
}
客户收到代码:
#define BUFSIZE 1400
while(true)
{
msgsize = read(socketfd,BUFSIZE);
buffer[msgsize] = 0;
snprintf(ending,6,buffer + (strlen(buffer) - 5));
if(strcmp(ending,"#####") == 0)
{
buffer[strlen(buffer) - 5] = 0;
if(buffer[strlen(buffer) - 1] == '\n')
printf("%s",buffer);
else
printf("%s\n",buffer);
fflush(stdout);
break;
}
else
{
printf("%s",buffer);
memset(buffer,BUFSIZE);
}
}
服务器重播调试打印:
lssize:19931 nofile:501,msglen:437 cpylen:39 no_sends: 14
为什么我只收到两个数据包,而不是来自的14个数据包
每个大约1400字节的服务器数据包?
错误在哪里?
也欢迎任何代码改进建议。
解决方法
除了注释中指出的错误外,您的代码还有一些更基本的问题,这些问题过于广泛,无法仅对其进行注释。
此代码暗示使用多线程:
pthread_mutex_lock(&lock);
chdir(pclient->pwd);
directory = opendir(".");
pthread_mutex_unlock(&lock);
但,此代码假设当前工作目录始终是当前函数的pclient->pwd
:
status = stat(dir->d_name,&type);
不会在循环运行时是否有另一个线程调用chdir()
到另一个目录,因此您的结果
stat()
始终检查整个过程中当前工作目录的相对路径。在您发布的代码中,哪个可以更改。
要遵循的一个很好的规则是,如果您正在编写多线程代码,则从不执行不会更改进程的任何全局属性的操作。
您对snprintf()
的使用也容易出错。例如:
cpylen = snprintf(buffer + msglen,BUFSIZE,"%s%s\n","file stat error:",dir->d_name);
每7.21.6.5 The snprintf function,paragraph 2 of the C11 standard(正在炸雷):
snprintf函数返回n足够大的情况下要写入的字符数,不计算终止的空字符,如果发生编码错误,则不计算负数。因此,当且仅当返回值是非负且小于n时,以零结尾的输出已被完全写入。
您盲目地假设对snprintf()
的每个呼叫都能正常工作。如果对snprintf()
的任何一次调用失败,则消息内容非常不确定,并且msglen
的值将无法准确反映缓冲区的内容。
这意味着此代码不会发送任何内容:
cpylen = strlen(buffer);
if(msglen == cpylen)
send(clientfd,buffer,strlen(buffer),0);