基本上,服务器需要将由客户端填充的结构打印到文件中,当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中的数字顺序打印在文件上。
答案 0 :(得分:2)
问题在于,每次创建文件时,它都会填充成千上万个零,这表明读写功能无法正常工作
警告:您使用SOCK_STREAM,但不保证在一个读取时读取所有预期的字节。
在服务器中,您需要检查结果
read(sock, &message, sizeof(struct Data));
出错时中断或重新读取,如果全部未读,则未读,或者如果读取的内容少于预期大小,则 message 完全或部分不变,或者在未设置时未设置在第一个循环中,您有一个机会可以循环到最后一次,当然,您在文件中打印的值也保持不变或无效。
您可能遇到的情况是:在服务器中的交换期间(可能是第一次), read 不会读取所有结构,因为未设置message.fine
设置为1以及其他一些值也未设置,因为message.fine != 1
再次循环并再次读取,但是从未读字节开始读取,而不是从结构的开头读取,因此即使您在那时读取sizeof(Data)
字节, struct的填充不正确,并且message.fine
再次未设置为1且其他属性未设置正确的值,依此类推,此刻没有什么可读取的,并且由于 message 而无限期地循环em>保持不变。
当然,我鼓励您也检查 write 的结果,当您在客户端读取内容时遇到同样的问题
答案 1 :(得分:1)
必须修改您的客户端/服务器端读取代码,以检查读取调用的返回值。请记住,当您使用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;
}
}
答案 2 :(得分:0)
感谢@bruno和@Jay的帮助和所有建议。我这样安排阅读部分:
do{
res = read(sock, &message, sizeof(struct Data));
}while(res < sizeof(struct Data));
相同的东西,现在可以了!
P.S。我注意到,如果在fprintf成功后不刷新文件流,则不会打印该文件,而是在循环中断后将其打印出来。为什么会这样?