在 Linux 机器中使用套接字发送和接收文件时出现 C++ 问题
C++ issue while sending and receiving a file using sockets within a Linux machine
我正在尝试发送文件 file_to_send.txt:
事实是痛苦本身很重要,其次是肥胖精英。 Duis quam eros, fringilla et accumsan vitae, tincidunt 巧克力湖。没有什么是容易的。这是家庭必需品,但却是一种免费资产。谁都不想当作者,不仅如此,他还很软。喉咙痛,妆也痛。是时候去诊所了。每一团湖水,柔软的都变成了酵母,卡通足球。为了喝酒,他想要那个箭袋,和 rhoncus mauris 一样,没有人会想要 eleifend 的 mauris
使用此代码:
客户端:
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <netinet/in.h>
#define PORT 16000
#define ADDRESS "localhost"
int main(int argc, char **argv)
{
int client_socket;
ssize_t len;
struct sockaddr_in remote_addr;
char buffer[BUFSIZ];
int file_size;
FILE *received_file;
int remain_data = 0;
char* destination_path = argv[1];
memset(&remote_addr, 0, sizeof(remote_addr));
remote_addr.sin_family = AF_INET;
inet_pton(AF_INET, ADDRESS, &(remote_addr.sin_addr));
remote_addr.sin_port = htons(PORT);
client_socket = socket(AF_INET, SOCK_STREAM, 0);
if (client_socket == -1)
{
fprintf(stderr, "Error creating socket --> %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
if (connect(client_socket, (struct sockaddr *)&remote_addr, sizeof(struct sockaddr)) == -1)
{
fprintf(stderr, "Error on connect --> %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
recv(client_socket, buffer, BUFSIZ, 0);
file_size = atoi(buffer);
fprintf(stdout, "\nFile size : %d\n", file_size);
received_file = fopen(destination_path, "w");
if (received_file == NULL)
{
fprintf(stderr, "Failed to open file foo --> %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
remain_data = file_size;
while ((len = recv(client_socket, buffer, BUFSIZ, 0) > 0) && (remain_data > 0))
{
fwrite(buffer, sizeof(char), len, received_file);
remain_data -= len;
fprintf(stdout, "Receive %d bytes and we hope :- %d bytes\n", static_cast<int>(len), remain_data);
}
fclose(received_file);
close(client_socket);
return 0;
}
服务器端:
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <netinet/in.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/sendfile.h>
using namespace std;
#define PORT 16000
#define ADDRESS "localhost"
int main(int argc, char **argv)
{
int server_socket;
int peer_socket;
socklen_t sock_len;
ssize_t len;
struct sockaddr_in server_addr;
struct sockaddr_in peer_addr;
int fd;
int sent_bytes = 0;
char file_size[BUFSIZ];
struct stat file_stat;
off_t offset;
int remain_data;
char* file_to_serve = argv[1];
server_socket = socket(AF_INET, SOCK_STREAM, 0);
if (server_socket == -1)
{
fprintf(stderr, "Error creating socket --> %s", strerror(errno));
exit(EXIT_FAILURE);
}
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
inet_pton(AF_INET, ADDRESS, &(server_addr.sin_addr));
server_addr.sin_port = htons(PORT);
if ((bind(server_socket, (struct sockaddr *)&server_addr, sizeof(struct sockaddr))) == -1)
{
fprintf(stderr, "Error on bind --> %s", strerror(errno));
exit(EXIT_FAILURE);
}
if ((listen(server_socket, 5)) == -1)
{
fprintf(stderr, "Error on listen --> %s", strerror(errno));
exit(EXIT_FAILURE);
}
fd = open(file_to_serve, O_RDONLY);
if (fd == -1)
{
fprintf(stderr, "Error opening file --> %s", strerror(errno));
exit(EXIT_FAILURE);
}
if (fstat(fd, &file_stat) < 0)
{
fprintf(stderr, "Error fstat --> %s", strerror(errno));
exit(EXIT_FAILURE);
}
fprintf(stdout, "File Size: \n%d bytes\n",static_cast<int>(file_stat.st_size));
sock_len = sizeof(struct sockaddr_in);
peer_socket = accept(server_socket, (struct sockaddr *)&peer_addr, &sock_len);
if (peer_socket == -1)
{
fprintf(stderr, "Error on accept --> %s", strerror(errno));
exit(EXIT_FAILURE);
}
fprintf(stdout, "Accept peer --> %s\n", inet_ntoa(peer_addr.sin_addr));
sprintf(file_size, "%d", static_cast<int>(file_stat.st_size));
len = send(peer_socket, file_size, sizeof(file_size), 0);
if (len < 0)
{
fprintf(stderr, "Error on sending greetings --> %s", strerror(errno));
exit(EXIT_FAILURE);
}
fprintf(stdout, "Server sent %d bytes for the size\n", static_cast<int>(len));
offset = 0;
remain_data = file_stat.st_size;
while (((sent_bytes = sendfile(peer_socket, fd, &offset, BUFSIZ)) > 0) && (remain_data > 0))
{
fprintf(stdout, "Server sent %d bytes from file's data, offset is now : %d and remaining data = %d\n", sent_bytes, static_cast<int>(offset), static_cast<int>(remain_data));
remain_data -= sent_bytes;
fprintf(stdout, "Server sent %d bytes from file's data, offset is now : %d and remaining data = %d\n", sent_bytes, static_cast<int>(offset), static_cast<int>(remain_data));
}
close(peer_socket);
close(server_socket);
return 0;
}
到 运行 来自终端的代码:
服务器端:
// compile
$ g++ server.cpp -o server_side
// run client
$ ./server_side "$HOME/file_to_send.txt"
客户端:
// compile
$ g++ client.cpp -o client_side
// run client
$ ./client_side "$HOME/received_file.txt"
我没有收到所有文件。
有人可以测试此代码并帮助我解决问题吗?
谢谢。
您需要了解 recv()
调用不会一对一映射到 send()
调用。
这可能会从一开始就引起问题:当您在服务器端发送 ascii 格式的文件大小(例如:508)时,在客户端,您可能会一次收到所有字节。但是您也可能会分段接收它(先是 50,然后是 8),在这种情况下,您的客户会认为大小比预期的要小得多,因此会削减数据。
另请注意,您最初发送 BUFSIZ 的完整缓冲区以交出 ascii 格式的大小。但是在接收大小时,您也可能只接收其中的一部分(例如 10 个字节,足以获得正确的大小)。初始发送的剩余字节将随后到达,但将由循环中期望接收有效负载的第一个调用接收。在这种情况下,这些额外的字节(示例中的 BUFSIZ-10)将代替实际文件内容被接收,因此最后发送的字节将在接收文件的末尾被忽略。
我正在尝试发送文件 file_to_send.txt:
事实是痛苦本身很重要,其次是肥胖精英。 Duis quam eros, fringilla et accumsan vitae, tincidunt 巧克力湖。没有什么是容易的。这是家庭必需品,但却是一种免费资产。谁都不想当作者,不仅如此,他还很软。喉咙痛,妆也痛。是时候去诊所了。每一团湖水,柔软的都变成了酵母,卡通足球。为了喝酒,他想要那个箭袋,和 rhoncus mauris 一样,没有人会想要 eleifend 的 mauris
使用此代码:
客户端:
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <netinet/in.h>
#define PORT 16000
#define ADDRESS "localhost"
int main(int argc, char **argv)
{
int client_socket;
ssize_t len;
struct sockaddr_in remote_addr;
char buffer[BUFSIZ];
int file_size;
FILE *received_file;
int remain_data = 0;
char* destination_path = argv[1];
memset(&remote_addr, 0, sizeof(remote_addr));
remote_addr.sin_family = AF_INET;
inet_pton(AF_INET, ADDRESS, &(remote_addr.sin_addr));
remote_addr.sin_port = htons(PORT);
client_socket = socket(AF_INET, SOCK_STREAM, 0);
if (client_socket == -1)
{
fprintf(stderr, "Error creating socket --> %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
if (connect(client_socket, (struct sockaddr *)&remote_addr, sizeof(struct sockaddr)) == -1)
{
fprintf(stderr, "Error on connect --> %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
recv(client_socket, buffer, BUFSIZ, 0);
file_size = atoi(buffer);
fprintf(stdout, "\nFile size : %d\n", file_size);
received_file = fopen(destination_path, "w");
if (received_file == NULL)
{
fprintf(stderr, "Failed to open file foo --> %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
remain_data = file_size;
while ((len = recv(client_socket, buffer, BUFSIZ, 0) > 0) && (remain_data > 0))
{
fwrite(buffer, sizeof(char), len, received_file);
remain_data -= len;
fprintf(stdout, "Receive %d bytes and we hope :- %d bytes\n", static_cast<int>(len), remain_data);
}
fclose(received_file);
close(client_socket);
return 0;
}
服务器端:
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <netinet/in.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/sendfile.h>
using namespace std;
#define PORT 16000
#define ADDRESS "localhost"
int main(int argc, char **argv)
{
int server_socket;
int peer_socket;
socklen_t sock_len;
ssize_t len;
struct sockaddr_in server_addr;
struct sockaddr_in peer_addr;
int fd;
int sent_bytes = 0;
char file_size[BUFSIZ];
struct stat file_stat;
off_t offset;
int remain_data;
char* file_to_serve = argv[1];
server_socket = socket(AF_INET, SOCK_STREAM, 0);
if (server_socket == -1)
{
fprintf(stderr, "Error creating socket --> %s", strerror(errno));
exit(EXIT_FAILURE);
}
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
inet_pton(AF_INET, ADDRESS, &(server_addr.sin_addr));
server_addr.sin_port = htons(PORT);
if ((bind(server_socket, (struct sockaddr *)&server_addr, sizeof(struct sockaddr))) == -1)
{
fprintf(stderr, "Error on bind --> %s", strerror(errno));
exit(EXIT_FAILURE);
}
if ((listen(server_socket, 5)) == -1)
{
fprintf(stderr, "Error on listen --> %s", strerror(errno));
exit(EXIT_FAILURE);
}
fd = open(file_to_serve, O_RDONLY);
if (fd == -1)
{
fprintf(stderr, "Error opening file --> %s", strerror(errno));
exit(EXIT_FAILURE);
}
if (fstat(fd, &file_stat) < 0)
{
fprintf(stderr, "Error fstat --> %s", strerror(errno));
exit(EXIT_FAILURE);
}
fprintf(stdout, "File Size: \n%d bytes\n",static_cast<int>(file_stat.st_size));
sock_len = sizeof(struct sockaddr_in);
peer_socket = accept(server_socket, (struct sockaddr *)&peer_addr, &sock_len);
if (peer_socket == -1)
{
fprintf(stderr, "Error on accept --> %s", strerror(errno));
exit(EXIT_FAILURE);
}
fprintf(stdout, "Accept peer --> %s\n", inet_ntoa(peer_addr.sin_addr));
sprintf(file_size, "%d", static_cast<int>(file_stat.st_size));
len = send(peer_socket, file_size, sizeof(file_size), 0);
if (len < 0)
{
fprintf(stderr, "Error on sending greetings --> %s", strerror(errno));
exit(EXIT_FAILURE);
}
fprintf(stdout, "Server sent %d bytes for the size\n", static_cast<int>(len));
offset = 0;
remain_data = file_stat.st_size;
while (((sent_bytes = sendfile(peer_socket, fd, &offset, BUFSIZ)) > 0) && (remain_data > 0))
{
fprintf(stdout, "Server sent %d bytes from file's data, offset is now : %d and remaining data = %d\n", sent_bytes, static_cast<int>(offset), static_cast<int>(remain_data));
remain_data -= sent_bytes;
fprintf(stdout, "Server sent %d bytes from file's data, offset is now : %d and remaining data = %d\n", sent_bytes, static_cast<int>(offset), static_cast<int>(remain_data));
}
close(peer_socket);
close(server_socket);
return 0;
}
到 运行 来自终端的代码:
服务器端:
// compile
$ g++ server.cpp -o server_side
// run client
$ ./server_side "$HOME/file_to_send.txt"
客户端:
// compile
$ g++ client.cpp -o client_side
// run client
$ ./client_side "$HOME/received_file.txt"
我没有收到所有文件。 有人可以测试此代码并帮助我解决问题吗?
谢谢。
您需要了解 recv()
调用不会一对一映射到 send()
调用。
这可能会从一开始就引起问题:当您在服务器端发送 ascii 格式的文件大小(例如:508)时,在客户端,您可能会一次收到所有字节。但是您也可能会分段接收它(先是 50,然后是 8),在这种情况下,您的客户会认为大小比预期的要小得多,因此会削减数据。
另请注意,您最初发送 BUFSIZ 的完整缓冲区以交出 ascii 格式的大小。但是在接收大小时,您也可能只接收其中的一部分(例如 10 个字节,足以获得正确的大小)。初始发送的剩余字节将随后到达,但将由循环中期望接收有效负载的第一个调用接收。在这种情况下,这些额外的字节(示例中的 BUFSIZ-10)将代替实际文件内容被接收,因此最后发送的字节将在接收文件的末尾被忽略。