我正在创建一个程序,该程序从服务器请求文件并发回文件,创建新文件并将该文件的内容写入新文件。除了服务器端错误消息(即文件不存在)应该在客户端打印时,一切都工作正常。谁能给我一个如何完成这个的线索?我是C的新手,但愿意了解更多。我的主要问题是,如果我直接发送消息,客户端不知道它是一个错误,并且将完成并创建一个文件并将消息写入该文件。我以为我需要发回-1,所以当客户端调用recv时,它会返回-1作为长度并打印一条消息。
这是我的客户:
ssize_t recvx(int sockfd, void *buf, size_t len) {
int var = recv(sockfd, buf, len, 0);
if(var != -1)
{
return var;
} else {
printf("%s \n","Did not receive.");
exit(1);
}
}
int main(int argc, char *argv[])
{
char buf[MAX_LINE];
struct addrinfo hints;
struct addrinfo *rp, *result;
int bytes_received;
int s;
char *server;
char *port;
char *file;
int fd = -1; //file descriptor
int bytes_written;
if (argc==4)
{
server = argv[1];
port = argv[2];
file = argv[3];
}
else
{
fprintf(stderr, "invalid # of arguments\n");
exit(1);
}
/* Translate host name into peer's IP address */
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = 0;
hints.ai_protocol = 0;
if ((s = getaddrinfo(server, port, &hints, &result)) != 0 )
{
fprintf(stderr, "%s: getaddrinfo: %s\n", argv[0], gai_strerror(s));
exit(1);
}
/* Iterate through the address list and try to connect */
for (rp = result; rp != NULL; rp = rp->ai_next)
{
if ((s = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol)) == -1 )
{
continue;
}
if (connect(s, rp->ai_addr, rp->ai_addrlen) != -1)
{
break;
}
close(s);
}
if (rp == NULL)
{
perror("stream-talk-client: connect");
exit(1);
}
freeaddrinfo(result);
/*send lines of text */
send(s, file, sizeof(file), 0);
while(bytes_received != 0)
{
bytes_received = recvx(s, buf, 20);
if(bytes_received == -1)
{
fprintf(stderr, "Client Error: Error receiving file \n");
exit(1);
} else {
if(fd == -1)
{
fd = open(file, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
if(fd == -1)
{
fprintf(stderr,"Client Error: Open failed \n");
exit(1);
}
bytes_written = write(fd,buf,bytes_received);
if(bytes_written == -1)
{
fprintf(stderr,"%s \n", "Client Error: Write error");
exit(1);
}
} else {
bytes_written = write(fd,buf,bytes_received);
if(bytes_written == -1)
{
fprintf(stderr,"%s \n", "Client Error: Write error");
exit(1);
}
}
}
}
if(close(fd) != 0)
{
printf("%s \n", "Client Error: File did not close successfully");
exit(1);
}
close(s);
return 0;
}
这是我的服务器:
int main(int argc, char *argv[])
{
struct addrinfo hints;
struct addrinfo *rp, *result;
char filename[MAX_LINE];
int s, new_s;
int bytes_transferred;
int fd; //file descriptor
struct stat statBuffer; //to hold file info
off_t offset = 0;
/* Build address data structure */
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
hints.ai_protocol = 0;
hints.ai_canonname = NULL;
hints.ai_addr = NULL;
hints.ai_next = NULL;
/* Get local address info */
if ((s = getaddrinfo(NULL, argv[1], &hints, &result)) != 0 )
{
fprintf(stderr, "%s: getaddrinfo: %s\n", argv[0], gai_strerror(s));
exit(1);
}
/* Iterate through the address list and try to perform passive open */
for (rp = result; rp != NULL; rp = rp->ai_next)
{
if ((s = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol)) == -1 )
{
continue;
}
if (!bind(s, rp->ai_addr, rp->ai_addrlen))
{
break;
}
close(s);
}
if (rp == NULL)
{
perror("stream-talk-server: bind");
exit(1);
}
if (listen(s, MAX_PENDING) == -1)
{
perror("stream-talk-server: listen");
close(s);
exit(1);
}
freeaddrinfo(result);
/* Wait for connection, then receive and print text */
while(1)
{
if ((new_s = accept(s, rp->ai_addr, &(rp->ai_addrlen))) < 0)
{
perror("stream-talk-server: accept");
close(s);
exit(1);
}
while(bytes_transferred == recv(new_s,filename,sizeof(filename),0))
{
if(bytes_transferred == -1)
{
fprintf(stderr, "Server Error: Error receiving filename \n");
exit(1);
}
}
printf("%s \n", filename);
fd =open(filename,O_RDONLY);
if(fd < 0)
{
fprintf(stderr,"Server Error: file doesn't exist\n");
exit(1);
}
else
{
printf("%s \n","file opened successfully");
}
/*get info from file descriptor (fd) and store it in statBuffer struct */
fstat(fd, &statBuffer);
bytes_transferred = sendfile(new_s,fd,&offset,statBuffer.st_size);
if(bytes_transferred == -1)
{
fprintf(stderr, "Server Error: File not transferred successfully");
}
else
{
printf("%s \n", "File transferred successfully");
}
if(close(fd) != 0)
{
fprintf(stderr, "Server Error: File not close successfully");
}
else{
break;
}
}
close(new_s);
return 0;
}
答案 0 :(得分:0)
基本上你正在实施的是HTTP和FTP服务器所做的事情。两者都有特定但相当不同的协议步骤来处理错误。 HTTP情况很容易理解 - 服务器不会发回文件:它会发回一堆标题,然后是文件。客户端可以检查标头以了解是否有任何文件数据要遵循。
在一个非常简单的例子中,我怀疑你可以在代码中实现类似的东西而不需要太多的工作 - 只需让服务器在文件的其余部分之前发送一个单字节的响应代码。您可以使用0(例如)来指示有效文件,以及其他数字以指示特定的错误条件。客户端只会像当前一样读取数据,但如果第一个字节不为零,则它知道后面没有任何其他内容(如果有的话)是有效的。
或者您可以安排,如果第一个字节不为零,则后面的文本不是预期的文件,而是一条错误消息,应该由客户端显示。
你可以根据自己的喜好来扩展这样的方案,直到最终得到HTTP:)