- 论坛徽章:
- 0
|
本帖最后由 osmanthusgfy 于 2011-02-24 14:51 编辑
回复 12# xinglp
感谢大哥的回复!
首先指出大哥的一个笔误"pathconf(pipefd[0],xxxx);" 应该是"fpathconf(pipefd[0],xxxx);"
然后指出我之前的一句"splice一次最大能操作的数据的缓冲区的大小为65536byte",
仅测试fpathconf( pipefd[1], _PC_PIPE_BUF )返回的值刚好为65536,所以我这句话不太准确.
经过再次测试,还是得出:
使用splice本机拷贝文件,表现良好;
本机socket CS传输文件,发送端使用sendfile,接收端使用splice,
接收端有时接收不完整,有时,CS都阻塞了(感觉是某一端死了).阻塞的频率很高,感觉极其不稳定.
我测试,若接收端使用read-write方式,则没有这些问题,接收文件也很稳定.
不知大哥在网络环境下使用过splice了没?
贴上CS的代码,若有错误的地方,敬请指正,谢谢!
Server:
- /*
- * ================================================================
- * Name: Serv.c
- * Author:
- * Copyright: BSD
- * ================================================================
- */
- #define _GNU_SOURCE
- #include <arpa/inet.h> //inet_addr
- #include <ctype.h> //isdigit
- #include <errno.h>
- #include <fcntl.h>
- #include <netdb.h> //hostent, gethostbyname
- #include <netinet/in.h> //IPPROTO_TCP, sockaddr_in, htons, INADDR_ANY
- #include <netinet/tcp.h> //TCP_NODELAY
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sys/sendfile.h>
- #include <sys/socket.h> //socket
- #include <sys/types.h>
- #include <unistd.h>
- #define BUF_SIZE 1024
- #define FILE_PATH "a.rmvb"
- #define FILE_SIZE 392822171
- #define PORT 8888
- int Name2Addr( const char* aName, in_addr_t* aAddr )
- {
- struct hostent* host;
- if ( 0 < isdigit( (int)(*aName) ) )
- *aAddr = inet_addr( aName );
- else {
- if( NULL == ( host = gethostbyname( aName ) ) )
- return -1;
- memcpy( (char*)aAddr, host->h_addr_list[0], host->h_length );
- }
- return 0;
- }
- ssize_t splice_recvfile( const char* path, int infd, const size_t count )
- {
- if ( 0 > count ) {
- errno = EINVAL;
- return -1;
- }
- int pipefd[2];
- long max_pipe_buf_size;
- long total_cpcount = 0;
- ssize_t recv_count;
- ssize_t out_cout;
- int i = 0;
- fprintf( stderr, "count=%d\n", count );
- if ( -1 == pipe( pipefd ) ) {
- return -1;
- }
- max_pipe_buf_size = fpathconf( pipefd[1], _PC_PIPE_BUF );
- fprintf( stderr, "max_pipe_buf_size=%ld\n", max_pipe_buf_size );
- if ( -1 == max_pipe_buf_size ) {
- close( pipefd[0] );
- close( pipefd[1] );
- return -1;
- }
- int outfd = open( path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IXUSR );
- if ( -1 == outfd ) {
- close( pipefd[0] );
- close( pipefd[1] );
- return -1;
- }
- while ( count != total_cpcount ) {
- recv_count = splice( infd, NULL, pipefd[1], NULL, max_pipe_buf_size,
- SPLICE_F_MOVE | SPLICE_F_MORE );
- if ( EAGAIN == errno )
- continue;
- if ( -1 == recv_count ) {
- goto do_err_label;
- } else if ( 0 == recv_count ) {
- close( pipefd[0] );
- close( pipefd[1] );
- close( outfd );
- return 0;
- }
- //fprintf( stderr, "recv_count=%d\n", recv_count );
- i = 0;
- do {
- ++i;
- out_cout = splice( pipefd[0], NULL, outfd, NULL, max_pipe_buf_size,
- SPLICE_F_MOVE | SPLICE_F_MORE );
- fprintf( stderr, "i=%d write...\n", i );
- } while ( -1 == out_cout && EAGAIN == errno );
- if ( -1 == out_cout )
- goto do_err_label;
- if ( out_cout != recv_count ) {
- fprintf( stderr, "out_cout != cp_count\n" );
- }
- total_cpcount += out_cout;
- }
- close( pipefd[0] );
- close( pipefd[1] );
- close( outfd );
- fprintf( stderr, "total_cpcount=%ld\n", total_cpcount );
- return total_cpcount;
- do_err_label: {
- close( pipefd[0] );
- close( pipefd[1] );
- close( outfd );
- return -1;
- }
- }
- int main( int argc, char** argv )
- {
- int clientfd;
- int servfd;
- struct sockaddr_in clientaddr;
- socklen_t clientaddrlen = sizeof( clientaddr );
- servfd = socket( AF_INET, SOCK_STREAM, 0 );
- if ( -1 == servfd ) {
- fprintf( stderr, "socket error:%s\n", strerror( errno ) );
- return EXIT_FAILURE;
- }
- int optval = 1;
- if ( -1 == setsockopt( servfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof( optval ) ) ) {
- fprintf( stderr, "setsockopt1 error:%s\n", strerror( errno ) );
- close( servfd );
- return EXIT_FAILURE;
- }
- if ( -1 == setsockopt( servfd, IPPROTO_TCP, TCP_NODELAY, &optval, sizeof( optval ) ) ) {
- fprintf( stderr, "setsockopt2 error:%s\n", strerror( errno ) );
- close( servfd );
- return EXIT_FAILURE;
- }
- struct sockaddr_in localaddr;
- localaddr.sin_family = AF_INET;
- localaddr.sin_port = htons( PORT );
- localaddr.sin_addr.s_addr = INADDR_ANY;
- if ( -1 == bind( servfd, (struct sockaddr*)(&localaddr), sizeof( localaddr ) ) ) {
- fprintf( stderr, "bind error:%s\n", strerror( errno ) );
- close( servfd );
- return EXIT_FAILURE;
- }
- fprintf( stderr, "listening...\n" );
- if ( -1 == listen( servfd, 1024 ) ) {
- fprintf( stderr, "listen error:%s\n", strerror( errno ) );
- close( servfd );
- return EXIT_FAILURE;
- }
- clientfd = accept( servfd, (struct sockaddr*)(&clientaddr), &clientaddrlen );
- if ( -1 == clientfd ) {
- fprintf( stderr, "accept error:%s\n", strerror( errno ) );
- close( servfd );
- return EXIT_FAILURE;
- }
- if ( -1 == splice_recvfile( FILE_PATH, clientfd, FILE_SIZE ) )
- fprintf( stderr, "splice_recvfile error:%s\n", strerror( errno ) );
- close( clientfd );
- close( servfd );
- fprintf( stderr, "Done.\n" );
- return EXIT_SUCCESS;
- }
复制代码 Client:
- /*
- * ================================================================
- * Name: Client.c
- * Author:
- * Copyright: BSD
- * ================================================================
- */
- #include <arpa/inet.h>
- #include <ctype.h>
- #include <errno.h>
- #include <fcntl.h>
- #include <netdb.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sys/sendfile.h>
- #include <sys/socket.h>
- #include <sys/stat.h>
- #include <sys/types.h>
- #include <unistd.h>
- #define SERV_PORT 8888
- #define SERV_ADDR "127.0.0.1"
- #define FILE_PATH "/home/a.rmvb"
- static int Name2Addr( const char* aName, in_addr_t* aAddr )
- {
- struct hostent* host;
- if ( 0 < isdigit( (int)(*aName) ) )
- *aAddr = inet_addr( aName );
- else {
- if( NULL == ( host = gethostbyname( aName ) ) )
- return -1;
- memcpy( (char*)aAddr, host->h_addr_list[0], host->h_length );
- }
- return 0;
- }
- #include <limits.h>
- int main( int argc, char** argv )
- {
- struct sockaddr_in servaddr;
- struct stat statbuf;
- int infd;
- int sockfd = socket( AF_INET, SOCK_STREAM, 0 );
- ssize_t sendsize;
- if ( -1 == sockfd ) {
- fprintf( stderr, "Socket error:%s\n.", strerror( errno ) );
- return EXIT_FAILURE;
- }
- servaddr.sin_family = AF_INET;
- servaddr.sin_port = htons( (short)SERV_PORT );
- if ( -1 == Name2Addr( SERV_ADDR, &servaddr.sin_addr.s_addr ) ) {
- fprintf( stderr, "Name2Addr error:%s\n.", strerror( errno ) );
- close( sockfd );
- return EXIT_FAILURE;
- }
- fprintf( stderr, "connect...\n" );
- if ( -1 == connect( sockfd, (struct sockaddr*)(&servaddr),
- sizeof( struct sockaddr ) ) ) {
- fprintf( stderr, "Connect error:%s\n.", strerror( errno ) );
- close( sockfd );
- return EXIT_FAILURE;
- }
- infd = open( FILE_PATH, O_RDONLY );
- if ( -1 == infd ) {
- fprintf( stderr, "Open error:%s\n", strerror( errno ) );
- close( sockfd );
- return EXIT_FAILURE;
- }
- if ( -1 == fstat( infd, &statbuf ) ) {
- fprintf( stderr, "Fstat error:%s\n", strerror( errno ) );
- close( infd );
- close( sockfd );
- return EXIT_FAILURE;
- }
- fprintf( stderr, "Sendfile...\n" );
- if ( -1 == ( sendsize = sendfile( sockfd, infd, 0, statbuf.st_size ) ) ) {
- fprintf( stderr, "Sendfile error:%s\n", strerror( errno ) );
- close( infd );
- close( sockfd );
- return EXIT_FAILURE;
- }
- fprintf( stderr, "statbuf.st_size=%d\n", statbuf.st_size );
- fprintf( stderr, "sendsize=%d\n", sendsize );
- close( infd );
- close( sockfd );
- fprintf( stderr, "Done.\n" );
- return EXIT_SUCCESS;
- }
复制代码 |
|