简单 Client/Server 的问题,文件打印错误
Problem with simple Client/Server, file gets printed wrong
基本上,服务器需要将客户端填充的结构打印到文件中,客户端和服务器都应该在 message.fine == 1 时停止。问题是每次创建文件时,它填满了千位零,说明读写功能没有正常工作。你能帮我解决这个问题吗?
这是客户:
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <pthread.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
struct Data
{
int a;
float b;
int fine;
int risultato;
};
int main()
{
int sock;
struct Data message, response;
message.fine = 0;
struct sockaddr_in address;
address.sin_family = AF_INET;
address.sin_port = htons(6869);
address.sin_addr.s_addr = inet_addr("127.0.0.1");
sock = socket(AF_INET, SOCK_STREAM, 0);
connect(sock, (struct sockaddr *)&address, sizeof(address));
while(message.fine != 1)
{
printf("\nInsert an integer number:");
scanf("%d", &message.a);
printf("\nInsert a float number:");
scanf("%f", &message.b);
printf("\nIs this the final message? (0 = no, 1 = yes)\n");
scanf("%d", &message.fine);
write(sock, &message, sizeof(struct Data));
read(sock, &response, sizeof(struct Data));
if(response.risultato == -1)
{
fprintf(stderr, "\nServer returned Writing Error\n");
exit(EXIT_FAILURE);
}
else if(response.risultato == 1)
{
printf("\nSuccess in Operation\n");
}
}
close(sock);
exit(EXIT_SUCCESS);
}
这是服务器:
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <pthread.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
struct Data
{
int a;
float b;
int fine;
int risultato;
};
void * handler(void * args)
{
struct Data message;
int sock = *(int *)args;
FILE *fp;
if(!(fp = fopen("result.txt", "a")))
{
fprintf(stderr, "Error in opening file\n");
exit(EXIT_FAILURE);
}
while(1)
{
read(sock, &message, sizeof(struct Data));
printf("%d, %f, %d", message.a, message.b, message.fine);
if(fprintf(fp,"\n[%d] [%.2f]\n", message.a, message.b) < 0)
{
message.risultato = -1;
}
else{
message.risultato = 1;
}
if(message.fine == 1)
{
break;
}
write(sock, &message, sizeof(struct Data));
}
fclose(fp);
close(sock);
free(args);
pthread_exit(NULL);
}
int main()
{
int sock, client_sock;
int * new_sock;
pthread_t tid;
struct sockaddr_in address, client_address;
address.sin_family = AF_INET;
address.sin_port = htons(6869);
address.sin_addr.s_addr = inet_addr("127.0.0.1");
socklen_t sock_len = (socklen_t)sizeof(address);
sock = socket(AF_INET, SOCK_STREAM, 0);
bind(sock, (struct sockaddr *)&address, sock_len);
listen(sock, 3);
while(1)
{
new_sock = (int *)malloc(sizeof(int));
sock_len = sizeof(client_address);
client_sock = accept(sock, (struct sockaddr *)&client_address, &sock_len);
*new_sock = client_sock;
pthread_create(&tid, NULL, handler, (void *)new_sock);
pthread_detach(tid);
}
}
实际结果应该是message.a和message.b中的数字依次打印在文件上。
The problem is that every time the file is created, it gets filled with thousands of zero, which indicates that the read and write function didn't work correctly
警告 您使用 SOCK_STREAM,您无法保证在 one 上读取所有预期的字节。
在服务器中你需要检查
的结果
read(sock, &message, sizeof(struct Data));
在所有 if 未被读取时中断或再次读取,否则当未读取任何内容或读取小于预期大小时 消息 完全或部分未更改或unset 如果它是在第一个循环并且你有 机会 循环到时间结束,当然你在文件中打印的值也没有改变或无效。
您遇到的可能情况是:在服务器中的交换期间(可能是第一次)read 没有读取所有结构,因此 message.fine
未设置为 1 并且其他一些值也未设置,因为 message.fine != 1
你再次循环并再次读取但是从未读字节而不是从结构的开头读取,所以即使你读取 sizeof(Data)
字节,此时结构没有很好地填充,并且 message.fine
没有设置为 1,其他属性没有设置正确的值,等等,此刻没有什么可读的,你无限期地循环,因为 消息保持不变。
当然,我鼓励您也检查 write 的结果,并且在您的客户端
中读取时遇到同样的问题
您的 client/server 端读取代码必须修改以检查读取调用的 return 值。请记住,当您使用 SOCK_STREAM 时,所有发送的数据都作为流(而不是数据报)发送和接收,导致后续发送的数据被放在一起,同样不需要单个发送的所有数据在另一边一次性收到。
服务器修改代码片段(伪代码),请检查并适当修改您的原始代码:
while(1)
{
int res_bytes = 0;
int res = 0;
while (res_bytes < sizeof(struct Data))
{
res = read(sock, &message+res_bytes, (sizeof(struct Data) - res_bytes));
if ((res == 0) || (res == -1))
{
printf("read returned an error, returning");
return;
}
res_bytes = res_bytes + res;
}
printf("%d, %f, %d", message.a, message.b, message.fine);
if(fprintf(fp,"\n[%d] [%.2f]\n", message.a, message.b) < 0)
{
message.risultato = -1;
}
else{
message.risultato = 1;
}
if(message.fine == 1)
{
break;
}
res = write(sock, &message, sizeof(struct Data));
if ((res == 0) || (res == -1))
{
printf("Error while writing");
return;
}
}
感谢@bruno 和@Jay 的帮助和所有建议。我把阅读部分安排成这样:
do{
res = read(sock, &message, sizeof(struct Data));
}while(res < sizeof(struct Data));
写同样的事情,现在可以了!
P.S。我注意到如果我在 fprintf 成功后不刷新文件流,则文件不会被打印,它会在循环中断后打印它。为什么会这样?
基本上,服务器需要将客户端填充的结构打印到文件中,客户端和服务器都应该在 message.fine == 1 时停止。问题是每次创建文件时,它填满了千位零,说明读写功能没有正常工作。你能帮我解决这个问题吗?
这是客户:
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <pthread.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
struct Data
{
int a;
float b;
int fine;
int risultato;
};
int main()
{
int sock;
struct Data message, response;
message.fine = 0;
struct sockaddr_in address;
address.sin_family = AF_INET;
address.sin_port = htons(6869);
address.sin_addr.s_addr = inet_addr("127.0.0.1");
sock = socket(AF_INET, SOCK_STREAM, 0);
connect(sock, (struct sockaddr *)&address, sizeof(address));
while(message.fine != 1)
{
printf("\nInsert an integer number:");
scanf("%d", &message.a);
printf("\nInsert a float number:");
scanf("%f", &message.b);
printf("\nIs this the final message? (0 = no, 1 = yes)\n");
scanf("%d", &message.fine);
write(sock, &message, sizeof(struct Data));
read(sock, &response, sizeof(struct Data));
if(response.risultato == -1)
{
fprintf(stderr, "\nServer returned Writing Error\n");
exit(EXIT_FAILURE);
}
else if(response.risultato == 1)
{
printf("\nSuccess in Operation\n");
}
}
close(sock);
exit(EXIT_SUCCESS);
}
这是服务器:
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <pthread.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
struct Data
{
int a;
float b;
int fine;
int risultato;
};
void * handler(void * args)
{
struct Data message;
int sock = *(int *)args;
FILE *fp;
if(!(fp = fopen("result.txt", "a")))
{
fprintf(stderr, "Error in opening file\n");
exit(EXIT_FAILURE);
}
while(1)
{
read(sock, &message, sizeof(struct Data));
printf("%d, %f, %d", message.a, message.b, message.fine);
if(fprintf(fp,"\n[%d] [%.2f]\n", message.a, message.b) < 0)
{
message.risultato = -1;
}
else{
message.risultato = 1;
}
if(message.fine == 1)
{
break;
}
write(sock, &message, sizeof(struct Data));
}
fclose(fp);
close(sock);
free(args);
pthread_exit(NULL);
}
int main()
{
int sock, client_sock;
int * new_sock;
pthread_t tid;
struct sockaddr_in address, client_address;
address.sin_family = AF_INET;
address.sin_port = htons(6869);
address.sin_addr.s_addr = inet_addr("127.0.0.1");
socklen_t sock_len = (socklen_t)sizeof(address);
sock = socket(AF_INET, SOCK_STREAM, 0);
bind(sock, (struct sockaddr *)&address, sock_len);
listen(sock, 3);
while(1)
{
new_sock = (int *)malloc(sizeof(int));
sock_len = sizeof(client_address);
client_sock = accept(sock, (struct sockaddr *)&client_address, &sock_len);
*new_sock = client_sock;
pthread_create(&tid, NULL, handler, (void *)new_sock);
pthread_detach(tid);
}
}
实际结果应该是message.a和message.b中的数字依次打印在文件上。
The problem is that every time the file is created, it gets filled with thousands of zero, which indicates that the read and write function didn't work correctly
警告 您使用 SOCK_STREAM,您无法保证在 one 上读取所有预期的字节。
在服务器中你需要检查
的结果 read(sock, &message, sizeof(struct Data));
在所有 if 未被读取时中断或再次读取,否则当未读取任何内容或读取小于预期大小时 消息 完全或部分未更改或unset 如果它是在第一个循环并且你有 机会 循环到时间结束,当然你在文件中打印的值也没有改变或无效。
您遇到的可能情况是:在服务器中的交换期间(可能是第一次)read 没有读取所有结构,因此 message.fine
未设置为 1 并且其他一些值也未设置,因为 message.fine != 1
你再次循环并再次读取但是从未读字节而不是从结构的开头读取,所以即使你读取 sizeof(Data)
字节,此时结构没有很好地填充,并且 message.fine
没有设置为 1,其他属性没有设置正确的值,等等,此刻没有什么可读的,你无限期地循环,因为 消息保持不变。
当然,我鼓励您也检查 write 的结果,并且在您的客户端
中读取时遇到同样的问题您的 client/server 端读取代码必须修改以检查读取调用的 return 值。请记住,当您使用 SOCK_STREAM 时,所有发送的数据都作为流(而不是数据报)发送和接收,导致后续发送的数据被放在一起,同样不需要单个发送的所有数据在另一边一次性收到。
服务器修改代码片段(伪代码),请检查并适当修改您的原始代码:
while(1)
{
int res_bytes = 0;
int res = 0;
while (res_bytes < sizeof(struct Data))
{
res = read(sock, &message+res_bytes, (sizeof(struct Data) - res_bytes));
if ((res == 0) || (res == -1))
{
printf("read returned an error, returning");
return;
}
res_bytes = res_bytes + res;
}
printf("%d, %f, %d", message.a, message.b, message.fine);
if(fprintf(fp,"\n[%d] [%.2f]\n", message.a, message.b) < 0)
{
message.risultato = -1;
}
else{
message.risultato = 1;
}
if(message.fine == 1)
{
break;
}
res = write(sock, &message, sizeof(struct Data));
if ((res == 0) || (res == -1))
{
printf("Error while writing");
return;
}
}
感谢@bruno 和@Jay 的帮助和所有建议。我把阅读部分安排成这样:
do{
res = read(sock, &message, sizeof(struct Data));
}while(res < sizeof(struct Data));
写同样的事情,现在可以了!
P.S。我注意到如果我在 fprintf 成功后不刷新文件流,则文件不会被打印,它会在循环中断后打印它。为什么会这样?