2012-06-28 28 views
10

का उपयोग कर फ़ाइल स्थानांतरण सर्वर/क्लाइंट सर्वर और क्लाइंट के बीच फ़ाइल स्थानांतरण करने की कोशिश कर रहा हूं, लेकिन यह बहुत बुरी तरह से काम कर रहा है। असल में क्या होने की आवश्यकता है:
1) क्लाइंट सर्वर पर एक txt फ़ाइल भेजता है (मैंने इसे "quotidiani.txt" कहा है)
2) सर्वर इसे किसी अन्य txt फ़ाइल ("get.txt") में सहेजता है
3) सर्वर उस पर एक स्क्रिप्ट चलाता है जो इसे संशोधित करता है और इसे किसी अन्य नाम ("output.txt") से बचाता है
4) सर्वर फ़ाइल को उस क्लाइंट को वापस भेजता है जो इसे (उसी सॉकेट पर) सहेजता है नाम (अंतिम.txt)सॉकेट

समस्या यह है कि पहली फ़ाइल (quotidiani.txt) केवल थोड़ी सी हिस्से के लिए पढ़ी जाती है, और फिर कुछ त्रुटियां होती हैं। मैं चाहता हूं कि कोई मेरी समझ को समझने और सही करने में मेरी सहायता करे।

यहाँ मेरी कोड है:

client.c:

#include <stdlib.h> 
#include <stdio.h> 
#include <errno.h> 
#include <string.h> 
#include <sys/types.h> 
#include <netinet/in.h> 
#include <sys/wait.h> 
#include <sys/socket.h> 
#include <signal.h> 
#include <ctype.h>   
#include <arpa/inet.h> 
#include <netdb.h> 

#define PORT 20000 
#define LENGTH 512 


void error(const char *msg) 
{ 
    perror(msg); 
    exit(1); 
} 

int main(int argc, char *argv[]) 
{ 
    /* Variable Definition */ 
    int sockfd; 
    int nsockfd; 
    char revbuf[LENGTH]; 
    struct sockaddr_in remote_addr; 

    /* Get the Socket file descriptor */ 
    if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) 
    { 
     fprintf(stderr, "ERROR: Failed to obtain Socket Descriptor! (errno = %d)\n",errno); 
     exit(1); 
    } 

    /* Fill the socket address struct */ 
    remote_addr.sin_family = AF_INET; 
    remote_addr.sin_port = htons(PORT); 
    inet_pton(AF_INET, "127.0.0.1", &remote_addr.sin_addr); 
    bzero(&(remote_addr.sin_zero), 8); 

    /* Try to connect the remote */ 
    if (connect(sockfd, (struct sockaddr *)&remote_addr, sizeof(struct sockaddr)) == -1) 
    { 
     fprintf(stderr, "ERROR: Failed to connect to the host! (errno = %d)\n",errno); 
     exit(1); 
    } 
    else 
     printf("[Client] Connected to server at port %d...ok!\n", PORT); 

    /* Send File to Server */ 
    //if(!fork()) 
    //{ 
     char* fs_name = "/home/aryan/Desktop/quotidiani.txt"; 
     char sdbuf[LENGTH]; 
     printf("[Client] Sending %s to the Server... ", fs_name); 
     FILE *fs = fopen(fs_name, "r"); 
     if(fs == NULL) 
     { 
      printf("ERROR: File %s not found.\n", fs_name); 
      exit(1); 
     } 

     bzero(sdbuf, LENGTH); 
     int fs_block_sz; 
     while((fs_block_sz = fread(sdbuf, sizeof(char), LENGTH, fs)) > 0) 
     { 
      if(send(sockfd, sdbuf, fs_block_sz, 0) < 0) 
      { 
       fprintf(stderr, "ERROR: Failed to send file %s. (errno = %d)\n", fs_name, errno); 
       break; 
      } 
      bzero(sdbuf, LENGTH); 
     } 
     printf("Ok File %s from Client was Sent!\n", fs_name); 
    //} 

    /* Receive File from Server */ 
    printf("[Client] Receiveing file from Server and saving it as final.txt..."); 
    char* fr_name = "/home/aryan/Desktop/progetto/final.txt"; 
    FILE *fr = fopen(fr_name, "a"); 
    if(fr == NULL) 
     printf("File %s Cannot be opened.\n", fr_name); 
    else 
    { 
     bzero(revbuf, LENGTH); 
     int fr_block_sz = 0; 
     while((fr_block_sz = recv(sockfd, revbuf, LENGTH, 0)) > 0) 
     { 
      int write_sz = fwrite(revbuf, sizeof(char), fr_block_sz, fr); 
      if(write_sz < fr_block_sz) 
      { 
       error("File write failed.\n"); 
      } 
      bzero(revbuf, LENGTH); 
      if (fr_block_sz == 0 || fr_block_sz != 512) 
      { 
       break; 
      } 
     } 
     if(fr_block_sz < 0) 
     { 
      if (errno == EAGAIN) 
      { 
       printf("recv() timed out.\n"); 
      } 
      else 
      { 
       fprintf(stderr, "recv() failed due to errno = %d\n", errno); 
      } 
     } 
     printf("Ok received from server!\n"); 
     fclose(fr); 
    } 
    close (sockfd); 
    printf("[Client] Connection lost.\n"); 
    return (0); 
} 

server.c

#include <stdlib.h> 
#include <stdio.h> 
#include <errno.h> 
#include <string.h> 
#include <sys/types.h> 
#include <netinet/in.h> 
#include <sys/wait.h> 
#include <sys/socket.h> 
#include <signal.h> 
#include <ctype.h>   
#include <arpa/inet.h> 
#include <netdb.h> 

#define PORT 20000 
#define BACKLOG 5 
#define LENGTH 512 

void error(const char *msg) 
{ 
    perror(msg); 
    exit(1); 
} 

int main() 
{ 
    /* Defining Variables */ 
    int sockfd; 
    int nsockfd; 
    int num; 
    int sin_size; 
    struct sockaddr_in addr_local; /* client addr */ 
    struct sockaddr_in addr_remote; /* server addr */ 
    char revbuf[LENGTH]; // Receiver buffer 

    /* Get the Socket file descriptor */ 
    if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) 
    { 
     fprintf(stderr, "ERROR: Failed to obtain Socket Descriptor. (errno = %d)\n", errno); 
     exit(1); 
    } 
    else 
     printf("[Server] Obtaining socket descriptor successfully.\n"); 

    /* Fill the client socket address struct */ 
    addr_local.sin_family = AF_INET; // Protocol Family 
    addr_local.sin_port = htons(PORT); // Port number 
    addr_local.sin_addr.s_addr = INADDR_ANY; // AutoFill local address 
    bzero(&(addr_local.sin_zero), 8); // Flush the rest of struct 

    /* Bind a special Port */ 
    if(bind(sockfd, (struct sockaddr*)&addr_local, sizeof(struct sockaddr)) == -1) 
    { 
     fprintf(stderr, "ERROR: Failed to bind Port. (errno = %d)\n", errno); 
     exit(1); 
    } 
    else 
     printf("[Server] Binded tcp port %d in addr 127.0.0.1 sucessfully.\n",PORT); 

    /* Listen remote connect/calling */ 
    if(listen(sockfd,BACKLOG) == -1) 
    { 
     fprintf(stderr, "ERROR: Failed to listen Port. (errno = %d)\n", errno); 
     exit(1); 
    } 
    else 
     printf ("[Server] Listening the port %d successfully.\n", PORT); 

    int success = 0; 
    while(success == 0) 
    { 
     sin_size = sizeof(struct sockaddr_in); 

     /* Wait a connection, and obtain a new socket file despriptor for single connection */ 
     if ((nsockfd = accept(sockfd, (struct sockaddr *)&addr_remote, &sin_size)) == -1) 
     { 
      fprintf(stderr, "ERROR: Obtaining new Socket Despcritor. (errno = %d)\n", errno); 
      exit(1); 
     } 
     else 
      printf("[Server] Server has got connected from %s.\n", inet_ntoa(addr_remote.sin_addr)); 

     /*Receive File from Client */ 
     char* fr_name = "/home/aryan/Desktop/receive.txt"; 
     FILE *fr = fopen(fr_name, "a"); 
     if(fr == NULL) 
      printf("File %s Cannot be opened file on server.\n", fr_name); 
     else 
     { 
      bzero(revbuf, LENGTH); 
      int fr_block_sz = 0; 
      while((fr_block_sz = recv(nsockfd, revbuf, LENGTH, 0)) > 0) 
      { 
       int write_sz = fwrite(revbuf, sizeof(char), fr_block_sz, fr); 
       if(write_sz < fr_block_sz) 
       { 
        error("File write failed on server.\n"); 
       } 
       bzero(revbuf, LENGTH); 
       if (fr_block_sz == 0 || fr_block_sz != 512) 
       { 
        break; 
       } 
      } 
      if(fr_block_sz < 0) 
      { 
       if (errno == EAGAIN) 
       { 
        printf("recv() timed out.\n"); 
       } 
       else 
       { 
        fprintf(stderr, "recv() failed due to errno = %d\n", errno); 
        exit(1); 
       } 
      } 
      printf("Ok received from client!\n"); 
      fclose(fr); 
     } 

     /* Call the Script */ 
     system("cd ; chmod +x script.sh ; ./script.sh"); 

     /* Send File to Client */ 
     //if(!fork()) 
     //{ 
      char* fs_name = "/home/aryan/Desktop/output.txt"; 
      char sdbuf[LENGTH]; // Send buffer 
      printf("[Server] Sending %s to the Client...", fs_name); 
      FILE *fs = fopen(fs_name, "r"); 
      if(fs == NULL) 
      { 
       fprintf(stderr, "ERROR: File %s not found on server. (errno = %d)\n", fs_name, errno); 
       exit(1); 
      } 

      bzero(sdbuf, LENGTH); 
      int fs_block_sz; 
      while((fs_block_sz = fread(sdbuf, sizeof(char), LENGTH, fs))>0) 
      { 
       if(send(nsockfd, sdbuf, fs_block_sz, 0) < 0) 
       { 
        fprintf(stderr, "ERROR: Failed to send file %s. (errno = %d)\n", fs_name, errno); 
        exit(1); 
       } 
       bzero(sdbuf, LENGTH); 
      } 
      printf("Ok sent to client!\n"); 
      success = 1; 
      close(nsockfd); 
      printf("[Server] Connection with Client closed. Server will wait now...\n"); 
      while(waitpid(-1, NULL, WNOHANG) > 0); 
     //} 
    } 
} 
+1

आप अपने खुद के फ़ाइल स्थानांतरण डेमॉन क्यों लिख रहे हैं? आप एसएसएच प्रोटोकॉल, या शायद यहां तक ​​कि एफ़टीपी का उपयोग क्यों नहीं करते? – steveha

+4

यह एक प्रोजेक्ट है, मुझे इसे इस तरह से करना है। – AscaL

+0

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

उत्तर

7

किसी विशेष क्रम में कुछ टिप्पणियां:

  • तुम जानने का मौका गुजर रहा है भी अक्सर सटीक त्रुटियों:

    if(listen(sockfd,BACKLOG) == -1) 
    { 
        printf("ERROR: Failed to listen Port %d.\n", PORT); 
        return (0); 
    } 
    

    यह ब्लॉक निश्चित रूप से एक perror("listen") या कुछ इसी तरह शामिल होना चाहिए। प्रत्येक त्रुटि हैंडलिंग ब्लॉक में हमेशा perror() या strerror() शामिल करें जब त्रुटि विवरण errno के माध्यम से रिपोर्ट की जाएगी। सटीक विफलता के कारण होने से प्रोग्रामिंग के दौरान आपको घंटे बचाएंगे और भविष्य में अपेक्षित काम नहीं होने पर आपको और आपके उपयोगकर्ताओं को घंटे बचाएंगे।

  • आपका त्रुटि हैंडलिंग कुछ आगे मानकीकरण की आवश्यकता है:

    if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) 
    { 
        printf("ERROR: Failed to obtain Socket Descriptor.\n"); 
        return (0); 
    } 
    

    यह चाहिए नहींreturn 0 क्योंकि उस खोल कि कार्यक्रम बिना किसी त्रुटि के पूरा होने से भाग गया करने के लिए संकेत देंगे। असामान्य निकास को सिग्नल करने के लिए आपको return 1 (या EXIT_SUCCESS और EXIT_FAILURE का उपयोग करना चाहिए)।

    else 
        printf("[Server] Server has got connected from %s.\n", inet_ntoa(addr_remote.sin_addr)); 
    
    /*Receive File from Client */ 
    

    इस पिछले ब्लॉक में आपको एक त्रुटि स्थिति मिली है लेकिन वैसे भी निष्पादन जारी है। यह बहुत अवांछित व्यवहार पाने का एक त्वरित तरीका है। इसे या तो मुख्य सर्वर लूप को फिर से शुरू करना चाहिए या बच्चे की प्रक्रिया या कुछ इसी तरह से बाहर निकलना चाहिए। (निर्भर करता है अगर आप मल्टी-प्रोसेस सर्वर रहते हैं।)

    if(!fork()) 
    { 
    

    पूर्ववर्ती ब्लॉक fork()में नाकाम रहने के के लिए खाते में भूल गया। fork(), और विशेष रूप से साझा होस्टिंग वातावरण में विश्वविद्यालयों में आम हो सकता है - इसलिए आपको पूर्ण, जटिल तीनfork() से संभावित वापसी मानों के लिए तैयार होना चाहिए: विफलता, बच्चे, माता-पिता।

  • ऐसा प्रतीत होता है कि आप fork() अंधाधुंध रूप से उपयोग कर रहे हैं; आपका ग्राहक और सर्वर दोनों बहुत ही सरल हैं और जिस तरह से उन्हें चलाने के लिए डिज़ाइन किया गया है, उनका मतलब है कि एक साथ कई क्लाइंट की सेवा के लिए उपयोग नहीं किया जा सकता है। आपको शायद प्रत्येक के लिए बिल्कुल एक प्रक्रिया के साथ रहना चाहिए, कम से कम जब तक एल्गोरिदम पूरी तरह से डीबग नहीं हो जाता है और आप एक साथ कई क्लाइंट चलाने के लिए कुछ तरीका समझते हैं। मुझे उम्मीद है कि यह अब आप जिस समस्या का सामना कर रहे हैं उसका स्रोत है।

  • आपको विवरणों को समाहित करने के लिए फ़ंक्शंस का उपयोग करने की आवश्यकता है; सर्वर से कनेक्ट करने के लिए एक फ़ंक्शन लिखें, फ़ाइल भेजने के लिए एक फ़ंक्शन, फ़ाइल लिखने के लिए एक फ़ंक्शन इत्यादि। जटिल आंशिक लेखन को संभालने के लिए एक फ़ंक्शन लिखें। (मैं विशेष रूप से पुस्तक के स्रोत कोड से writen फ़ंक्शन को चोरी करने की अनुशंसा करता हूं। फ़ाइल lib/writen.c।) यदि आप सही ढंग से फ़ंक्शन लिखते हैं तो आप उन्हें क्लाइंट और सर्वर दोनों में दोबारा उपयोग कर सकते हैं। (उन्हें utils.c में रखने और gcc -o server server.c utils.c जैसे कार्यक्रमों के संकलन की तरह।)

    छोटे कार्यों कि हर एक बात आप एक समय और प्रत्येक कि होगा के लिए थोड़ा परीक्षण लिखने में कोड की कम मात्रा पर ध्यान केंद्रित करने की अनुमति देगा कर के बाद कोड के किन वर्गों को अभी भी सुधार की आवश्यकता है, इसे कम करने में आपकी सहायता करें।

+0

अरे, सुझावों के लिए धन्यवाद। मुझे प्रोग्रामिंग पसंद नहीं है, शायद यही कारण है कि मैं इसमें बहुत अच्छा नहीं हूं। वैसे भी मैं बेहतर होना चाहता हूं इसलिए मैं आपकी युक्तियों का पालन करने की कोशिश करूंगा। यदि आपको कोई फर्क नहीं पड़ता है तो क्या आप "ऐसा प्रतीत होता है कि आप कांटा() अनजाने में उपयोग कर रहे हैं ...."? मुझे नहीं लगता कि मैं कई क्लाइंट्स की सेवा कर रहा हूं, मैं सिर्फ एक बार कॉल करता हूं और इसे स्वयं ही चलाना चाहिए। और मैं एक प्रक्रिया में कैसे रह सकता हूं? फिर से धन्यवाद! पीएस: सुबह 4 बजे है, इसलिए यदि आप उत्तर देते हैं तो मैं जवाब नहीं दूंगा, इसे व्यक्तिगत रूप से न लें! – AscaL

+0

'फोर्क() 'क्या करता है इसके बारे में सोचें - यह आपको प्रोग्राम की एक प्रति देता है। आपके क्लाइंट को अपनी प्रति की आवश्यकता क्यों है? आपके सर्वर को खुद की एक प्रति की आवश्यकता क्यों है? आप शायद बिना किसी दुष्प्रभाव के दोनों कार्यक्रमों से 'कांटा()' हटा सकते हैं। (यह कार्यक्रमों के बारे में _reasoning_ को अधिक आसान बना देगा।) – sarnold

+0

मैं आपको याद दिलाना शुरू कर दूंगा कि मुझे यह कोड चारों ओर मिला है। मैंने इसे नहीं लिखा और मैंने इसके बारे में बहुत कुछ नहीं सोचा (यह कहने के लिए कि मैं जो कह रहा हूं वह शायद गलत होगा), लेकिन अगर मैं कांटा का उपयोग नहीं करता तो मैं बच्चे को कैसे प्राप्त कर सकता हूं ()? जब मैं सर्वर कनेक्शन को स्वीकार करता हूं, तो मुझे पता है (और मुझे पता नहीं है) क्लाइंट कनेक्शन प्रबंधित करने के लिए यह एक नई सॉकेट (इसलिए एक नई प्रक्रिया) बनाता है, इसलिए मैं उस पर पहुंचने के लिए कांटा के परिणाम का उपयोग करता हूं। या शायद मैं गलत हूँ, मैं वास्तव में नहीं जानता। – AscaL

6

एक चर्चा बिंदु यहां गायब था, इसलिए मैंने इसका उल्लेख यहां सोचा।

हमें टीसीपी के डाटा ट्रांसफर को बहुत जल्दी समझने दें। तीन चरण ए) कनेक्शन स्थापना, बी) डाटा ट्रांसफर, सी) कनेक्शन टर्मिनेशन

अब यहां एक क्लाइंट एक टीसीपी सॉकेट पर सर्वर पर एक फाइल भेज रहा है।

सर्वर फ़ाइल पर कुछ प्रोसेसिंग करता है और इसे वापस क्लाइंट को भेजता है।

अब सभी 3 चरणों को करने की आवश्यकता है। कनेक्शन स्थापित करके कनेक्शन स्थापना की जाती है। डेटा रीडिंग/लेखन आरईवी द्वारा किया जाता है/यहां भेजता है और कनेक्शन समाप्त होने पर कनेक्शन समाप्त होता है।

यहां सर्वर रिकॉ का उपयोग कर लूप में डेटा पढ़ रहा है। अब जब लूप समाप्त हो जाएगा? जब आरईवी 0 देता है या त्रुटि पर 0 से कम हो सकता है। जब आरईवी 0 देता है? -> जब दूसरी तरफ कनेक्शन बंद कर दिया है। (जब टीसीपी एफआईएन सीमेंट को इस तरफ से प्राप्त किया गया है)।

तो इस कोड में जब ग्राहक ने फ़ाइल भेजना समाप्त कर दिया है, तो मैंने शट डाउन फ़ंक्शन का उपयोग किया है, जो क्लाइंट पक्ष से FIN सेगमेंट भेजता है और सर्वर का रिकव अब 0 लौटा सकता है और प्रोग्राम जारी रहता है। (आधा रास्ता बंद , क्योंकि क्लाइंट को बाद में डेटा पढ़ने की भी आवश्यकता है)।

(बस को समझने के लिए कृपया टीसीपी के कनेक्शन ध्यान दें establisment एक 3 रास्ता सहभागिता और कनेक्शन समाप्ति एक 4 रास्ता हाथ मिलाना है।)

इसी

यदि आप सर्वर साइड पर कनेक्शन सॉकेट बंद करने भूल जाते हैं, ग्राहक की recv होगा हमेशा के लिए ब्लॉक भी। मुझे लगता है कि क्लाइंट को रोकने के लिए ctrl c का उपयोग करने का कारण कभी-कभी आपने उल्लेख किया है।

आप pl।अधिक टीसीपी

के बारे में मैं संशोधित कोड चिपकाया है और यह भी थोड़ा कुछ टिप्पणियां जोड़ी सीखने के लिए किसी भी मानक नेटवर्किंग किताब या आरएफसी http://www.ietf.org/rfc/rfc793.txt देखें,

आशा इस व्याख्या में मदद मिलेगी।

संशोधित ग्राहक कोड:

while((fs_block_sz = fread(sdbuf, sizeof(char), LENGTH, fs)) > 0) 
    { 
     if(send(sockfd, sdbuf, fs_block_sz, 0) < 0) 
     { 
      fprintf(stderr, "ERROR: Failed to send file %s. (errno = %d)\n", fs_name, errno); 
      exit(1); 
     } 
     bzero(sdbuf, LENGTH); 
    } 

/*Now we have sent the File's data, what about server's recv? 
Recv is blocked and waiting for data to arrive or if the protocol 
stack receives a TCP FIN segment ..then the recv will return 0 and 
the server code can continue */ 
/*Sending the TCP FIN segment by shutdown and this is half way 
close, since the client also needs to read data subsequently*/ 

shutdown(sockfd, SHUT_WR); 
printf("Ok File %s from Client was Sent!\n", fs_name); 
+0

मदद करने के लिए बहुत बहुत धन्यवाद! मैं इसे अपने ग्राहक पक्ष में जोड़ूंगा और देख सकता हूं कि यह कैसे काम करता है। – AscaL