TCP Server 多包发送问题
TCP Server multiple packet sending issue
我已经使用 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, BUFSIZE, "file\t%s\t%s", dir->d_name, 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, 0, BUFSIZE + 5);
snprintf(buffer, cpylen, "%s", tmp);
msglen = cpylen;
cpylen = 0;
no_files += 1;
no_sends += 1;
}
}
else
{
cpylen = snprintf(buffer + msglen, BUFSIZE, "%s%s\n", "file stat error:", dir->d_name);
msglen += cpylen;
}
memset(tmp, 0, BUFSIZE);
}
}
cpylen = strlen(buffer);
if(msglen == cpylen)
send(clientfd, buffer, strlen(buffer), 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, cpylen, no_sends);
free(tmp);
free(buffer);
closedir(directory);
}
客户端接收码:
#define BUFSIZE 1400
while(true)
{
msgsize = read(socketfd, buffer, BUFSIZE);
buffer[msgsize] = 0;
snprintf(ending, 6, "%s", 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, 0, 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);
BUT,此代码假定当前工作目录始终是当前函数的 pclient->pwd
:
status = stat(dir->d_name, &type);
如果在循环 运行 时另一个线程调用 chdir()
到另一个目录则不会,所以你的结果
stat()
始终检查整个进程当前工作目录的相对路径。在您发布的代码中,哪些可以更改。
要遵循的一个好规则是,如果您正在编写多线程代码,从不 做会改变进程的任何全局 属性 的事情。
你使用snprintf()
也是bug-prone。例如:
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(加粗我的):
The snprintf function returns the number of characters that would have been written had n been sufficiently large, not counting the terminating null character, or a negative value if an encoding error occurred. Thus, the null-terminated output has been completely written if and only if the returned value is nonnegative and less than n.
您盲目地假设您对 snprintf()
的每一次调用都有效。如果对 snprintf()
的任何一次调用失败,您的消息内容将非常不确定,并且您对 msglen
的值将不会准确反映缓冲区的内容。
这意味着此代码不会发送任何内容:
cpylen = strlen(buffer);
if(msglen == cpylen)
send(clientfd, buffer, strlen(buffer), 0);
我已经使用 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, BUFSIZE, "file\t%s\t%s", dir->d_name, 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, 0, BUFSIZE + 5);
snprintf(buffer, cpylen, "%s", tmp);
msglen = cpylen;
cpylen = 0;
no_files += 1;
no_sends += 1;
}
}
else
{
cpylen = snprintf(buffer + msglen, BUFSIZE, "%s%s\n", "file stat error:", dir->d_name);
msglen += cpylen;
}
memset(tmp, 0, BUFSIZE);
}
}
cpylen = strlen(buffer);
if(msglen == cpylen)
send(clientfd, buffer, strlen(buffer), 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, cpylen, no_sends);
free(tmp);
free(buffer);
closedir(directory);
}
客户端接收码:
#define BUFSIZE 1400
while(true)
{
msgsize = read(socketfd, buffer, BUFSIZE);
buffer[msgsize] = 0;
snprintf(ending, 6, "%s", 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, 0, 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);
BUT,此代码假定当前工作目录始终是当前函数的 pclient->pwd
:
status = stat(dir->d_name, &type);
如果在循环 运行 时另一个线程调用 chdir()
到另一个目录则不会,所以你的结果
stat()
始终检查整个进程当前工作目录的相对路径。在您发布的代码中,哪些可以更改。
要遵循的一个好规则是,如果您正在编写多线程代码,从不 做会改变进程的任何全局 属性 的事情。
你使用snprintf()
也是bug-prone。例如:
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(加粗我的):
The snprintf function returns the number of characters that would have been written had n been sufficiently large, not counting the terminating null character, or a negative value if an encoding error occurred. Thus, the null-terminated output has been completely written if and only if the returned value is nonnegative and less than n.
您盲目地假设您对 snprintf()
的每一次调用都有效。如果对 snprintf()
的任何一次调用失败,您的消息内容将非常不确定,并且您对 msglen
的值将不会准确反映缓冲区的内容。
这意味着此代码不会发送任何内容:
cpylen = strlen(buffer);
if(msglen == cpylen)
send(clientfd, buffer, strlen(buffer), 0);