我尝试使用系统调用sendfile()
将文件发送到套接字中,但收到错误:* 错误发送文件:[EINVAL Invalid argument]*。但是调用read()
可以完美地使用相同的参数。我也尝试在参数中给予sendfile()
两个文件描述-得到了相同的结果。
你有什么建议吗?
一些附加信息:操作系统:Ubuntu 22.04.1 LTS on VirtualBox:第6.1.38节r153438(问题5.6.2); Linux内核:5.15.0-52-通用; glibc:2.35。
下面是我使用的两个SIMPLEST程序的示例:
1.程序使用sendfile()
将数据从一个文件复制到另一个文件
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/sendfile.h>
#include "gen_hdr.h"
int main() {
/*** Get file size and open files ***/
int fd;
size_t size;
struct stat statBuf;
if (stat("test_file.txt", &statBuf) == -1) {
errExit("statBuf");
}
size = statBuf.st_size;
fd = open("test_file.txt", O_RDONLY);
if (-1 == fd) {
errExit("open");
}
int fdNew, openFlags;
mode_t filePerms;
openFlags = O_CREAT | O_WRONLY | O_EXCL;
filePerms = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP |
S_IROTH | S_IWOTH; /* rw-rw-rw- */
fdNew = open("clone_test_file.txt", openFlags, filePerms);
/*** END ***/
/*** SENDFILE ***/
off_t offset = 0;
ssize_t sent = 0;
for (; size > 0; ) {
errno = 0;
sent = sendfile(fdNew, fd, &offset, size);
printf("%s\n", strerror(errno));
printf("%ld\n", sent);
if (sent <= 0) { // Error or end of file
if (sent != 0) {
errExit("sendfile"); // Was an error, report it
}
break; // End of file
}
size -= sent; // Decrease the send length by the amount actually sent
}
/*** END ***/
if (close(fd) == -1) {
errExit("close");
}
if (close(fdNew) == -1) {
errExit("close");
}
return 0;
}
1.程序创建了一个简单的TCP服务器,只发送文件到一个连接的客户端。如果我使用系统调用send()
(部分SENDFILE),而不是sendfile()
-所有的工作都很好。
伺服器:
#include <ctype.h>
#include <netinet/in.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/sendfile.h>
#include "gen_hdr.h"
#define PORT_NUM 55550
#define BACKLOG 5
int main() {
/*** Get file size and open it ***/
int fd;
size_t size_to_send;
struct stat statBuf;
if (stat("test_file.txt", &statBuf) == -1) {
errExit("statBuf");
}
size_to_send = statBuf.st_size;
fd = open("test_file.txt", O_RDONLY);
if (-1 == fd) {
errExit("open");
}
/*** END ***/
/*** Server Setup ***/
struct sockaddr_in svaddr, claddr;
//struct sockaddr_storage claddr;
socklen_t len;
int sockfd, connfd;
char claddrStr[INET_ADDRSTRLEN];
memset(&svaddr, 0, sizeof(struct sockaddr_in));
svaddr.sin_family = AF_INET;
svaddr.sin_port = (in_port_t)htons(PORT_NUM);
svaddr.sin_addr.s_addr = htonl(INADDR_ANY);
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (-1 == sockfd) {
errExit("socket");
}
if (bind(sockfd, (struct sockaddr *)&svaddr, sizeof(struct sockaddr_in)) == -1) {
errExit("bind");
}
if (listen(sockfd, BACKLOG) == -1) {
errExit("listen");
}
printf("Server is waiting for connection...\n");
len = sizeof(struct sockaddr_in);
connfd = accept(sockfd, (struct sockaddr*)&claddr, &len);
if (-1 == connfd) {
errExit("accept");
}
if (inet_ntop(AF_INET, &claddr.sin_addr, claddrStr, INET_ADDRSTRLEN) == NULL) {
printf("Coudn't convert client address to string\n");
}
else {
printf("Connection from [%s, %u]\n", claddrStr, ntohs(claddr.sin_port));
}
/*** END ***/
/*** SENDFILE ***/
off_t offset = 0;
ssize_t sent = 0;
for (; size_to_send > 0; ) {
errno = 0;
sent = sendfile(connfd, fd, &offset, size_to_send);
printf("%s\n", strerror(errno));
printf("%ld\n", sent);
if (sent <= 0) { // Error or end of file
if (sent != 0) {
errExit("sendfile"); // Was an error, report it
}
break; // End of file
}
size_to_send -= sent; // Decrease the send length by the amount actually sent
}
/*** END ***/
/*** SEND FILE ***/
// char* buf = (char*)malloc(size_to_send);
// if (NULL == buf) {
// errExit("malloc");
// }
// if (read(fd, buf, size_to_send) == -1) {
// errExit("read");
// }
// if (send(connfd, buf, size_to_send, 0) == -1) {
// errExit("send");
// }
// free(buf);
/*** END ***/
printf("File sent...\n");
if (close(fd) == -1) {
errExit("close");
}
if (close(connfd) == -1) {
printf("ERROR on closing connection\n");
}
if (close(sockfd) == -1) {
printf("ERROR on closing socket\n");
}
return 0;
}
委托单位:
#include <netinet/in.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "gen_hdr.h"
#define PORT_NUM 55550
#define BUF_SIZE 10
int main(int argc, char* argv[]) {
/*** Get file size and allocate memory ***/
char* buf;
size_t size_to_recv;
struct stat statBuf;
if (stat("test_file.txt", &statBuf) == -1) {
errExit("statBuf");
}
size_to_recv = statBuf.st_size;
buf = (char*)malloc(size_to_recv);
if (NULL == buf) {
errExit("malloc");
}
/*** END ***/
/*** Server Setup ***/
struct sockaddr_in svaddr;
socklen_t len;
int sockfd;
ssize_t numBytes;
char claddrStr[INET_ADDRSTRLEN];
memset(&svaddr, 0, sizeof(struct sockaddr_in));
svaddr.sin_family = AF_INET;
svaddr.sin_port = (in_port_t)htons(PORT_NUM);
svaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (-1 == sockfd) {
errExit("socket");
}
if (connect(sockfd, (struct sockaddr *)&svaddr, sizeof(struct sockaddr_in)) == -1) {
errExit("connect");
}
/*** END ***/
printf("Getting file...\n");
/*** RECEIVE FILE ***/
ssize_t numRead; /* Bytes that we read from the last call of read() */
size_t totRead; /* Number of bytes that we have read at the moment */
char* recvBuf = buf;
for (totRead = 0; totRead < size_to_recv; ) {
numRead = read(sockfd, recvBuf, size_to_recv - totRead);
if (numRead > 0) {
totRead += numRead;
recvBuf += numRead;
} else if (numRead == 0) { /* End of file */
return totRead; /* It could be 0, if it is the first call of read() */
} else { /* Error */
if (errno == EINTR) {
continue; /* Interrupted --> recall read() */
}
else {
errExit("read"); /* Some other error */
}
}
}
/*** END ***/
printf("Ended\n");
/*** WRITE IN NEW FILE ***/
int fd, openFlags;
mode_t filePerms;
openFlags = O_CREAT | O_WRONLY | O_EXCL;
filePerms = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP |
S_IROTH | S_IWOTH; /* rw-rw-rw- */
fd = open("clone_test_file.txt", openFlags, filePerms);
if (write(fd, buf, size_to_recv) == -1) {
errExit("write");
}
/*** END ***/
free(buf);
if (close(fd) == -1) {
errExit("close");
}
if (close(sockfd) == -1) {
errExit("close");
}
return 0;
}
“gen_hdr.h”仅包括“标准”库和错误处理函数的声明:
#ifndef GEN_HDR_H
#define GEN_HDR_H
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <stdint.h>
typedef enum {FALSE, TRUE} boolean;
#include "error_functions.h"
#define max(a,b) (((a) > (b)) ? (a) : (b))
#define min(a,b) (((a) < (b)) ? (a) : (b))
#endif /* GEN_HDR_H */
错误函数.c:
#include "gen_hdr.h"
#include "ename.c.inc"
static void outputError(int err, boolean flushStdout, const char* msg) {
#define BUF_SIZE 500
char buf[BUF_SIZE];
snprintf(buf, BUF_SIZE, "ERROR %s: [%s %s]\n", msg, ((err > 0 && err < MAX_ENAME) ? ename[err] : "?UNKNOWN?"), strerror(err));
if (flushStdout)
{
fflush(stdout);
}
fputs(buf, stderr);
fflush(stderr);
}
void errExit(char* msg) {
outputError(errno, TRUE, msg);
exit(EXIT_FAILURE);
}
void errExitEN(int errNum, char* msg) {
outputError(errNum, TRUE, msg);
exit(EXIT_FAILURE);
}
1条答案
按热度按时间4ktjp1zp1#
如果文件位于与windows共享的文件夹中,则
sendfile()
不起作用,尽管'mmap()'起作用。