2012-08-14 7 views
6

प्राप्त C:भेजने के लिए और इस सर्वर (Sendfile) हिस्सा है फ़ाइल

offset = 0; 
for (size_to_send = fsize; size_to_send > 0;){ 
    rc = sendfile(newsockd, fd, &offset, size_to_send); 
    if (rc <= 0){ 
    perror("sendfile"); 
    onexit(newsockd, sockd, fd, 3); 
    } 
    offset += rc; 
    size_to_send -= rc; 
} 
close(fd); /* la chiusura del file va qui altrimenti rischio loop infinito e scrittura all'interno del file */ 

memset(buffer, 0, sizeof(buffer)); 
strcpy(buffer, "226 File Successfully transfered\n"); 
if(send(newsockd, buffer, strlen(buffer), 0) < 0){ 
    perror("Errore durante l'invio 226"); 
    onexit(newsockd, sockd, 0, 2); 
} 
memset(buffer, 0, sizeof(buffer)); 

और इस ग्राहक (recv फ़ाइल) का हिस्सा हिस्सा है:

fsize_tmp = fsize; 
    sInfo.filebuffer = malloc(fsize); 
    if(sInfo.filebuffer == NULL){ 
    perror("malloc"); 
    onexit(sockd, 0, fd, 4); 
    } 

    while(((uint32_t)total_bytes_read != fsize) && ((nread = read(sockd, sInfo.filebuffer, fsize_tmp)) > 0)){ 
    if(write(fd, sInfo.filebuffer, nread) != nread){ 
      perror("write RETR"); 
      onexit(sockd, 0, 0, 1); 
     } 
     total_bytes_read += nread; 
     fsize_tmp -= nread; 
    } 
    close(fd); /* la chiusura del file va qui altrimenti client entra in loop infinito e si scrive all'interno del file */ 

    memset(buffer, 0, sizeof(buffer)); 
    if(recv(sockd, buffer, 34, 0) < 0){ 
    perror("Errore ricezione 226"); 
    onexit(sockd, 0, 0, 1); 
    } 
    printf("%s", buffer); 
    memset(buffer, 0, sizeof(buffer)); 
    memset(dirpath, 0, sizeof(dirpath)); 
    free(sInfo.filebuffer); 
समस्या

कि है स्ट्रिंग "226 फ़ाइल इत्यादि" के अंदर भेजी गई फ़ाइल के अंदर लिखा गया है।
मैंने एक छोटा डीबग करने की कोशिश की है और इसलिए मैंने लूप (सर्वर sendfile) और printf के बाद लूप (क्लाइंट) के बाद printf जोड़ा है और मैंने देखा है कि फ़ाइल भेजी गई है लेकिन क्लाइंट यह समय से बाहर नहीं निकलता है क्योंकि printf मुद्रित नहीं है ...
मुझे यह अजीब व्यवहार क्यों मिला ??
br>

संपादित करें:

:

fd = open(filename, O_RDONLY); 
    if(fd < 0){ 
    error!! 
    } 

    if(fstat(fd, &fileStat) < 0){ 
     perror("Errore fstat"); 
     onexit(newsockd, sockd, fd, 3); 
    } 
    fsize = fileStat.st_size; 
    if(send(newsockd, &fsize, sizeof(fsize), 0) < 0){ 
     perror("Errore durante l'invio della grandezza del file\n"); 
     onexit(newsockd, sockd, fd, 3); 
    } 

ग्राहक इस कोड के साथ सर्वर से fsize प्राप्त करता है:
सर्वर इस कोड को ग्राहक तिनका करने के लिए फ़ाइल आकार भेज

if(read(sockd, &fsize, sizeof(fsize)) < 0){ 
    perror("Errore durante ricezione grandezza file\n"); 
    onexit(sockd, 0 ,0 ,1); 
} 
fd = open(sInfo.filename, O_CREAT | O_WRONLY, 0644); 
if (fd < 0) { 
    perror("open"); 
    onexit(sockd, 0 ,0 ,1); 
} 
fsize_tmp = fsize; 

fsize दोनों uint32_t के रूप में घोषित किए गए हैं ...

+0

संभावित डुप्लिकेट [सी/सी ++ (जीसीसी/जी ++) के साथ लिनक्स में सॉकेट प्रोग्रामिंग में फ़ाइल भेजें और प्राप्त करें] (https://stackoverflow.com/questions/2014033/send-and-receive-a- फ़ाइल-इन-सॉकेट-प्रोग्रामिंग-इन-लिनक्स-साथ-सीसी-जीसीसी-जी) –

उत्तर

8

इस कोड का प्रयास करें:

क्लाइंट साइड:

/* Client code */ 
/* TODO : Modify to meet your need */ 
#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_NUMBER  5000 
#define SERVER_ADDRESS "192.168.1.7" 
#define FILENAME  "/home/toc/foo.c" 

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; 

     /* Zeroing remote_addr struct */ 
     memset(&remote_addr, 0, sizeof(remote_addr)); 

     /* Construct remote_addr struct */ 
     remote_addr.sin_family = AF_INET; 
     inet_pton(AF_INET, SERVER_ADDRESS, &(remote_addr.sin_addr)); 
     remote_addr.sin_port = htons(PORT_NUMBER); 

     /* Create client socket */ 
     client_socket = socket(AF_INET, SOCK_STREAM, 0); 
     if (client_socket == -1) 
     { 
       fprintf(stderr, "Error creating socket --> %s\n", strerror(errno)); 

       exit(EXIT_FAILURE); 
     } 

     /* Connect to the server */ 
     if (connect(client_socket, (struct sockaddr *)&remote_addr, sizeof(struct sockaddr)) == -1) 
     { 
       fprintf(stderr, "Error on connect --> %s\n", strerror(errno)); 

       exit(EXIT_FAILURE); 
     } 

     /* Receiving file size */ 
     recv(client_socket, buffer, BUFSIZ, 0); 
     file_size = atoi(buffer); 
     //fprintf(stdout, "\nFile size : %d\n", file_size); 

     received_file = fopen(FILENAME, "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", len, remain_data); 
     } 
     fclose(received_file); 

     close(client_socket); 

     return 0; 
} 

सर्वर साइड:

/* Server code */ 
/* TODO : Modify to meet your need */ 
#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> 

#define PORT_NUMBER  5000 
#define SERVER_ADDRESS "192.168.1.7" 
#define FILE_TO_SEND "hello.c" 

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[256]; 
     struct stat file_stat; 
     int offset; 
     int remain_data; 

     /* Create server socket */ 
     server_socket = socket(AF_INET, SOCK_STREAM, 0); 
     if (server_socket == -1) 
     { 
       fprintf(stderr, "Error creating socket --> %s", strerror(errno)); 

       exit(EXIT_FAILURE); 
     } 

     /* Zeroing server_addr struct */ 
     memset(&server_addr, 0, sizeof(server_addr)); 
     /* Construct server_addr struct */ 
     server_addr.sin_family = AF_INET; 
     inet_pton(AF_INET, SERVER_ADDRESS, &(server_addr.sin_addr)); 
     server_addr.sin_port = htons(PORT_NUMBER); 

     /* Bind */ 
     if ((bind(server_socket, (struct sockaddr *)&server_addr, sizeof(struct sockaddr))) == -1) 
     { 
       fprintf(stderr, "Error on bind --> %s", strerror(errno)); 

       exit(EXIT_FAILURE); 
     } 

     /* Listening to incoming connections */ 
     if ((listen(server_socket, 5)) == -1) 
     { 
       fprintf(stderr, "Error on listen --> %s", strerror(errno)); 

       exit(EXIT_FAILURE); 
     } 

     fd = open(FILE_TO_SEND, O_RDONLY); 
     if (fd == -1) 
     { 
       fprintf(stderr, "Error opening file --> %s", strerror(errno)); 

       exit(EXIT_FAILURE); 
     } 

     /* Get file stats */ 
     if (fstat(fd, &file_stat) < 0) 
     { 
       fprintf(stderr, "Error fstat --> %s", strerror(errno)); 

       exit(EXIT_FAILURE); 
     } 

     fprintf(stdout, "File Size: \n%d bytes\n", file_stat.st_size); 

     sock_len = sizeof(struct sockaddr_in); 
     /* Accepting incoming peers */ 
     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", file_stat.st_size); 

     /* Sending file 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", len); 

     offset = 0; 
     remain_data = file_stat.st_size; 
     /* Sending file data */ 
     while (((sent_bytes = sendfile(peer_socket, fd, &offset, BUFSIZ)) > 0) && (remain_data > 0)) 
     { 
       fprintf(stdout, "1. Server sent %d bytes from file's data, offset is now : %d and remaining data = %d\n", sent_bytes, offset, remain_data); 
       remain_data -= sent_bytes; 
       fprintf(stdout, "2. Server sent %d bytes from file's data, offset is now : %d and remaining data = %d\n", sent_bytes, offset, remain_data); 
     } 

     close(peer_socket); 
     close(server_socket); 

     return 0; 
} 

संपादित: offset

आदमी के बारे में आदमी से स्पष्टीकरण जोड़ा जा रहा है फ़ाइल भेजने का पृष्ठ ने कहा:

हैं ऑफसेट है शून्य नहीं है, तो यह एक चर फ़ाइल जो Sendfile से ऑफसेट() पकड़े in_fd से डाटा पढ़ने शुरू कर देंगे के लिए अंक।
जब sendfile() रिटर्न देता है, तो यह चर अंतिम बाइट के बाद बाइट के ऑफसेट पर सेट किया जाएगा जो पढ़ा गया था।

+0

के साथ काम कर रहा हूं, मैंने अपनी समस्या हल कर दी है: डी बहुत बहुत धन्यवाद! मेरी त्रुटि यह थी कि मैंने फ़ाइल के आकार को प्राप्त करने के लिए एक चार सरणी के बजाय "& fsize" का उपयोग किया है :) – polslinux

+0

@ पोल्सलिनक्स: आपका स्वागत है: -। ठीक है। सर्वर की ओर ऑफसेट को बढ़ाने के बारे में भी एक समस्या थी। – TOC

+0

वास्तव में ?? क्यूं कर?? क्या आप कृपया मुझे समझा सकते हैं ??? धन्यवाद :) – polslinux

0

ग्राहक नहीं जानता कि फ़ाइल कब समाप्त होती है। यह तब तक पढ़ता है जब तक इसे fsize बाइट प्राप्त नहीं हुआ है। आपके वर्तमान कार्यान्वयन में क्लाइंट केवल उन फ़ाइलों के लिए काम करेगा जो fsize बाइट्स हैं।

मेरा सुझाव है कि आप अपना प्रोटोकॉल बदल दें और फ़ाइल आकार वाले हेडर को जोड़ें। http प्रोटोकॉल का उपयोग क्यों नहीं करें?

+0

मुझे नहीं पता कि http xD – polslinux

+0

का उपयोग करने के लिए मुझे क्या करना है, मैंने आपका अपडेट पढ़ लिया है। ऐसा लगता है कि फ़ाइल आकार के लिए वास्तविक 'प्रेषण' कमांड एकमात्र चीज है। –

+0

आप सही हैं! मैंने अपना प्रश्न अपडेट कर लिया है! मुझे समस्या भी मिली है: सर्वर सही fsize भेजता है लेकिन क्लाइंट को एक बहुत बड़ा fsize प्राप्त होता है :(:(उदाहरण के लिए यदि सर्वर पर fsize 1048 है, तो क्लाइंट 20209320 ओओ – polslinux

0

मुझे लगता है कि आपको कम से कम उपयोग किए गए चर घोषणाओं और प्रारंभिकरण के साथ एक और विस्तृत कोड प्रदान करना चाहिए।

क्लाइंट भाग को fsize मान कैसे प्राप्त होता है?

आप भी इस तरह, जबकि हालत की जांच होनी चाहिए: क्योंकि अगर (किसी अज्ञात कारण से)

while(((uint32_t)total_bytes_read < fsize) && (..... 

का प्रयोग न करें "! =", total_bytes_read fsize से अधिक हो जाते हैं, आप हो जाएगा सॉकेट कनेक्शन बंद होने तक एक अनंत लूप में फंस गया (और पढ़ना एक त्रुटि देता है)।

मैं भी लगता है (लेकिन यकीन नहीं) आप recvके बजाय अपने ग्राहक भाग में पढ़ा उपयोग करना चाहिए।

+0

के बीच कोई अंतर नहीं है इस मामले में 'recv (2)' और 'पढ़ें (2) '। –

+0

'fstat (fd, और fileStat); fsize = fileStat.st_size; 'एक और सरल उदाहरण प्राप्त करने के लिए मैं त्रुटि – polslinux

0

आपको प्रोटोकॉल के हिस्से के रूप में जो फ़ाइल भेज रहे हैं उसका आकार हमेशा निर्धारित करना चाहिए, उदाहरण के लिए, आप फ़ाइल आकार को पहले 4 (या अधिक, फाइल आकारों के आधार पर जिन्हें आप संभालने की उम्मीद करते हैं) बाइट्स के रूप में भेज सकते हैं, वास्तविक धारा से पहले।

यदि आप निरंतर आकार फ़ाइलों के साथ काम करना चाहते हैं, तो आपके कार्यान्वयन को काम करना चाहिए, इस मामले में कृपया fsize और total_bytes_read के लिए प्रिंट जोड़ें।

0

आप sendfile API गलत तरीके से उपयोग कर रहे हैं। चूंकि आप तीसरे पैरामीटर में गैर-शून्य मान में गुजर रहे हैं, sendfile आपके लिए ऑफ़सेट अपडेट करेगा। लेकिन चूंकि आपका प्रेषण लूप ऑफसेट को भी अपडेट कर रहा है, इसलिए आप इस स्थिति में कुछ बाइट्स छोड़ देंगे कि sendfile पूरी फ़ाइल को एक ही कॉल में भेजने में सक्षम नहीं था।

man page से:

तो offset शून्य नहीं है, तो यह एक चर है जहाँ से sendfile()in_fd से डाटा पढ़ने शुरू कर देंगे फ़ाइल ऑफसेट पकड़े के लिए अंक। जब sendfile() लौटाता है, तो यह चर अंतिम बाइट पढ़ने के बाद बाइट के ऑफसेट पर सेट किया जाएगा।

आप अपने भेजने पाश से इस लाइन को दूर करना चाहिए:

offset += rc; 

संपादित करें: अपने अद्यतन में, आप fpl का उपयोग अपनी फ़ाइल से fstat जानकारी पाने के लिए, लेकिन अपने sendfile कोड में, आप fd का उपयोग करते हैं। मैं यह सुनिश्चित कर दूंगा कि ये वही हैं जो आप उन्हें होने की उम्मीद करते हैं। (यह अभी तक एक और अद्यतन में तय किया गया था।) किसी भी मामले में, मैंने test program using the code you provided (with my suggested fix) लिखा है, और यह 2KB फ़ाइल से कम और 3 एमबी फ़ाइल के साथ ठीक काम करता प्रतीत होता है।

+0

काम नहीं कर रहा हूं ... स्ट्रिंग "226 इत्यादि" फ़ाइल के अंदर मुद्रित है :( – polslinux

+0

भी मुझे लगता है कि एक var सही है क्योंकि 'मैन sendfile' रिपोर्ट: _ अगर ऑफ़सेट शून्य नहीं है, तो यह फ़ाइल ऑफ़सेट धारण करने वाले चर के लिए इंगित करता है, जिससे sendfile() in_fd._ – polslinux

+0

@polslinux से डेटा पढ़ना शुरू कर देगा: मैंने पूर्ण उत्तर को अपडेट किया मैन पेज से उद्धरण। – jxh