You are not logged in.
Pages: 1
I am currently doing r&D as how to use splice to write and receive files from the socket .
Here is my code to send data from a file to socket
#include <iostream>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <errno.h>
struct MyFds
{
int fdin;
int fdout;
int readpipe;
int writepipe;
loff_t size;
MyFds(int p_fdin, int p_fdout, int p_readpipe, int p_writepipe,
loff_t p_size) :
fdin(p_fdin), fdout(p_fdout), readpipe(p_readpipe),
writepipe(p_writepipe), size(p_size)
{
};
};
static void * splicecopywriter(void * threadparam)
{
const MyFds * fds = (const MyFds *) threadparam;
std::cout << "In writer thread " << std::endl;
loff_t offset = 0;
size_t bytesleft = fds->size;
int splices=0;
while (bytesleft > 0) {
splices ++;
ssize_t bytes = splice(fds->readpipe, (loff_t *) 0,
fds->fdout, & offset,
bytesleft, 0 /* flags */ );
if (bytes == -1) {
break;
}
bytesleft -= bytes;
}
int spliceerr = errno;
std::cout << "writer:splices= " << splices << " errno=" <<
spliceerr << std::endl;
std::cout << "still in writer thread " << std::endl;
return (void *) 0;
}
static int splicecopyreader(const MyFds *fds)
{
loff_t offset = 0;
size_t bytesleft = fds->size;
int splices = 0;
while (bytesleft > 0) {
splices ++;
ssize_t bytes = splice(fds->fdin, &offset, fds->writepipe,
(loff_t *) 0,
(size_t) fds->size, 0 /* flags */ );
if (bytes == -1) {
break;
}
bytesleft -= bytes;
}
int spliceerr = errno;
std::cout << "reader: splices=" << splices << " errno=" <<
spliceerr << std::endl;
close(fds->writepipe);
}
static int splicecopypipes(const MyFds *fds)
{
// Main thread reads from disc and into pipe;
// writerthread reads from pipe and on to disc.
pthread_t writerthread;
int res = pthread_create(&writerthread,
(const pthread_attr_t *) 0,
splicecopywriter,
(void *) fds);
std::cout << "In main thread" << std::endl;
splicecopyreader(fds);
int threadres;
pthread_join(writerthread, (void **) (& threadres) );
std::cout << "Joined" << std::endl;
return threadres;
}
static int splicecopyfd(int fdin, int fdout)
{
// Work out how big it is
struct stat st;
if (fstat(fdin, &st) != 0) {
std::cerr << "Stat failed" << std::endl;
return 3;
}
int pipes[2];
if (pipe(pipes) != 0) {
std::cerr << "Pipe failed" << std::endl;
return 4;
}
int readpipe = pipes[0];
int writepipe = pipes[1];
MyFds fds(fdin, fdout, readpipe, writepipe, st.st_size);
int res = splicecopypipes(&fds);
close(pipes[0]);
close(pipes[1]);
return res;
}
static int splicecopy(const char *srcfile)
{
int fdin = open(srcfile, O_RDONLY);
if (-1 == fdin) {
std::cerr << "Failed to open src file" << std::endl;
return 1;
}
struct sockaddr_in lstServerAddr.
inet_aton("172.20.101.38", &(lstServerAddr.sin_addr));
lstServerAddr.sin_port = htons(8000);
lstServerAddr.sin_family = AF_INET;
int fdout = socket(AF_INET, SOCK_STREAM, 0);
if (fdout == -1)
{
printf("failed due to %s", strerror(errno));
return 1;
}
if (connect(fdout, (struct sockaddr*)&lstServerAddr, sizeof(sockaddr_in)) == -1)
{
printf("connect failed due to %s", strerror(errno));
return 1;
}
int res = splicecopyfd(fdin, fdout);
close(fdin);
close(fdout);
return res;
}
int main(int argc, const char * argv[])
{
if (argc < 2) {
std::cerr << "Source required" << std::endl;
return 1;
}
const char *srcfile = argv[1];
return splicecopy(srcfile);
}
while writing to the socket it gives error as Invalid argument ie in the writer thread it give error Invalid Argument (EINVAL).
I have also tried setting both the offset to null while sending that doesn't work.
Please suggest as what os wrong exactly.
Thanks
Pankaj
Offline
You've really tried using NULL for all offsets? Because, that would be my guess as to your problem... Specifically, trying to specify an offset for the socket, which is non-seekable...
Also, I found when using splice(), it was wise to limit single calls to no more than about 60K at a time, due to the pipe buffer size... And, when copying to a socket, performance is greatly improved by using the SPLICE_F_MORE flag when you know you have more to write still to come... And, when doing a double-splice() with your own pipe (to copy between non-pipe FDs) as you're doing, you'd also be well-advised to add SPLICE_F_MOVE in the second splice() (the one copying from the pipe to the socket)...
Offline
Hi Robseace,
you were right i rechecked the code and it worked fine.
and as per your advise i have set the flag to SPLICE_F_MORE | SPLICE_F_MOVE in the second splice (coping from pipe to socket).
Thank you for the reply.
Regards,
Nithesh
Offline
I have sucessfully send data from a file to a socket using splice. Now while receiving / writing data from a socket to file using socket it
gives me EWOULDBLOCK error.
here is the Sample code.
int ReadData(int nSocketFD, int FileFd, int readpipe, int writepipe)
{
int lnRetValue = 0;
loff_t lSocketOffSet = 0;
loff_t lFileOffSet = 0;
while(true)
{
lnRetValue = splice(lnFd, &lSocketOffSet/*NULL*/, writepipe, (loff_t*)0, 1024, 0) ;
if (lnRetValue > 0)
{
if (lnRetValue == 1024)
{
break;
}
else
{
lnRetValue += lnRetValue;
}
}
else if (lnRetValue == -1)
{
printf("Splice failed due to %s", strerror(errno));
return 1;
}
}
lnRetValue = splice(readpipe, (loff_t*)0, lnFileFd, &lFileOffSet, 1024, 0);
if (lnRetValue < 0)
{
printf("splice 1 failed due to %s", strerror(errno));
return 1;
}
return 0;
}
pipe used are non blocking. tried setting the socketoffset to NULL.
Please advise as what am i doing wrong.
Regards,
Pankaj
Offline
Unless I can see the real code (and all of it), there's not really any way I can know what you're doing wrong... If you're getting EINVAL and truly are passing NULL for both offsets, then I'd have to guess your write pipe isn't really a pipe, or has been closed, or something like that... *shrug* All I can do is guess randomly without seeing all the real code which is actually producing the problem...
Offline
Pages: 1