【发布时间】:2018-03-22 10:50:23
【问题描述】:
我正在创建一个程序,该程序从服务器请求文件并将文件发回,创建一个新文件并将该文件的内容写入新文件。除了服务器端错误消息(即文件不存在)应在客户端打印外,一切都运行良好。谁能给我一个有关如何完成此任务的线索?我是 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;
}
【问题讨论】:
-
感谢您的回复。我的具体问题是弄清楚如何将错误消息发送回客户端以打印出来。 (即服务器错误:文件不存在)。如果我直接发送消息,客户端会收到一些内容并将其存储在要存储文件的位置。不希望这样,所以我想知道服务器是否有某种方法可以向客户端指示该文件不存在并且客户端打印出该错误发生在服务器端。谢谢
-
你需要一个应用协议。也就是说,客户端和服务器期望彼此看到的一组消息/响应。对于你这里的小项目,不必很复杂。
-
啊好的。所以如果服务器上没有错误消息,我应该只接收。我将查找应用程序协议的文档。我在想我需要将errno存储在某些东西中,并在recv和recv返回返回的字节数时将其发送回客户端,我希望为-1,因为不存在文件,但它返回0,因为没有发送文件,大声笑。
-
除非您在客户端收到错误,否则您永远不会知道服务器端是否有错误。
recv()返回零,因为对等方关闭了连接。
标签: c networking server client