2012-05-21 14 views
6

Ich versuche TCP-Dateiübertragung unter Linux. Nach dem Verbindungsaufbau sollte der Server "send.txt" an den Client senden und der Client erhält die Datei und speichert sie als "receive.txt". Dann bricht die Verbindung ab.Dateiübertragung mit TCP unter Linux

Die korrekte Eingabe und Ausgabe sollte sein:

Server-Terminal:

$./server & 
[server] obtain socket descriptor successfully. 
[server] bind tcp port 5000 in addr 0.0.0.0 successfully. 
[server] listening the port 5000 successfully. 
[server] server has got connect from 127.0.0.1. 
[server] send send.txt to the client…ok! 
[server] connection closed. 

Client-Terminal:

$./client 
[client] connected to server at port 5000…ok! 
[client] receive file sent by server to receive.txt…ok! 
[client] connection lost. 

Und sowohl der Server als auch Client sollte nach dem Prozess beenden.

Aber was ich jetzt habe gibt

$ ./server & 
[server] obtain socket descriptor successfully. 
[server] bind tcp port 5000 in addr 0.0.0.0 sucessfully. 
[server] listening the port 5000 sucessfully. 
[server] server has got connect from 127.0.0.1. 
[server] send send.txt to the client...ok! 
[server] connection closed. 

/*Here the server doesn't exit*/ 

$ ./client 
[client] connected to server at port 5000...ok! 

/*Here the client doesn't exit*/ 

Auch ein LEER „receive.txt“ erzeugt wird.

Mein Code wurde zuerst geschrieben, um einfache Zeichenfolgen zu übertragen, und es funktionierte korrekt. Also ich schätze das Problem liegt im Dateiübertragungsteil.

Mein Code ist wie folgt:

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> 
#define PORT 5000 // The port which is communicate with server 
#define BACKLOG 10 
#define LENGTH 512 // Buffer length 
int main() 
{ 
    int sockfd; // Socket file descriptor 
    int nsockfd; // New Socket file descriptor 
    int num; 
    int sin_size; // to store struct size 
    struct sockaddr_in addr_local; 
    struct sockaddr_in addr_remote; 
    /* Get the Socket file descriptor */ 
    if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) 
    { 
     printf ("ERROR: Failed to obtain Socket Descriptor.\n"); 
     return (0); 
    } 
    else printf ("[server] obtain socket descriptor successfully.\n"); 
    /* Fill the local 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) 
    { 
     printf ("ERROR: Failed to bind Port %d.\n",PORT); 
     return (0); 
    } 
    else printf("[server] bind tcp port %d in addr 0.0.0.0 sucessfully.\n",PORT); 
    /* Listen remote connect/calling */ 
    if(listen(sockfd,BACKLOG) == -1) 
    { 
     printf ("ERROR: Failed to listen Port %d.\n", PORT); 
     return (0); 
    } 
    else printf ("[server] listening the port %d sucessfully.\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) 
      printf ("ERROR: Obtain new Socket Despcritor error.\n"); 
     else printf ("[server] server has got connect from %s.\n", inet_ntoa(addr_remote.sin_addr)); 
     /* Child process */ 
     if(!fork()) 
     { 
      char* f_name = "send.txt"; 
      char sdbuf[LENGTH]; // Send buffer 
      printf("[server] send %s to the client...", f_name); 
      FILE *fp = fopen(f_name, "r"); 
      if(fp == NULL) 
      { 
       printf("ERROR: File %s not found.\n", f_name); 
       exit(1); 
      } 
      bzero(sdbuf, LENGTH); 
      int f_block_sz; 
      while((f_block_sz = fread(sdbuf, sizeof(char), LENGTH, fp))>0) 
      { 
       if(send(nsockfd, sdbuf, f_block_sz, 0) < 0) 
       { 
        printf("ERROR: Failed to send file %s.\n", f_name); 
        break; 
       } 
       bzero(sdbuf, LENGTH); 
      } 
      printf("ok!\n"); 
      success = 1; 
      close(nsockfd); 
      printf("[server] connection closed.\n"); 
      while(waitpid(-1, NULL, WNOHANG) > 0); 
     } 
    } 
} 

client.c

#include <stdio.h> 
#include <stdlib.h> 
#include <errno.h> 
#include <string.h> 
#include <netdb.h> 
#include <sys/types.h> 
#include <netinet/in.h> 
#include <sys/socket.h> 
#define PORT 5000 
#define LENGTH 512 // Buffer length 
int main(int argc, char *argv[]) 
{ 
    int sockfd; // Socket file descriptor 
    char revbuf[LENGTH]; // Receiver buffer 
    struct sockaddr_in remote_addr; 
    /* Get the Socket file descriptor */ 
    if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) 
    { 
     printf("ERROR: Failed to obtain Socket Descriptor!\n"); 
     return (0); 
    } 
    /* 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) 
    { 
     printf ("ERROR: Failed to connect to the host!\n"); 
     return (0); 
    } 
    else printf("[client] connected to server at port %d...ok!\n", PORT); 
    //printf ("OK: Have connected to %s\n",argv[1]); 
    printf("[client] receive file sent by server to receive.txt..."); 
    char* f_name = "receive.txt"; 
    FILE *fp = fopen(f_name, "a"); 
    if(fp == NULL) printf("File %s cannot be opened.\n", f_name); 
    else 
    { 
     bzero(revbuf, LENGTH); 
     int f_block_sz = 0; 
     int success = 0; 
     while(success == 0) 
     { 
      while(f_block_sz = recv(sockfd, revbuf, LENGTH, 0)) 
      { 
       if(f_block_sz < 0) 
       { 
        printf("Receive file error.\n"); 
        break; 
       } 
       int write_sz = fwrite(revbuf, sizeof(char), f_block_sz, fp); 
       if(write_sz < f_block_sz) 
       { 
        printf("File write failed.\n"); 
        break; 
       } 
       bzero(revbuf, LENGTH); 
      } 
      printf("ok!\n"); 
      success = 1; 
      fclose(fp); 
     } 
    } 
    close (sockfd); 
    printf("[client] connection lost.\n"); 
    return (0); 
} 

Vielen Dank!

+2

Mögliches Duplikat [Senden und dann eine Datei in der Socket-Programmierung in Linux Receive mit C/C++ (GCC/G ++)] (http://stackoverflow.com/questions/2014033/send-and-receive-a -file-in-socket-programmierung-in-linux-mit-cc-gcc-g) –

Antwort

4

Sie müssen dem Code f_block_sz Code hinzufügen. recv() hat ein paar posible Rückgabewerte:

  • <0 - Fehler, Fehlernummer in errno (errno.h)
  • 0 - Anschluss
  • >0 geschlossen - Daten lesen, die Anzahl der Bytes

Sie müssen den zweiten Fall behandeln. Dieses else Fall:

else if(f_block_sz) 
{ 
    break; 
} 

Damit die Schleife unterbrochen wird, wenn der Server die Verbindung schließt, und Ihr Code drucken Sie [client] connection lost und beenden.

+0

Vielen Dank. Ich hätte das früher merken sollen! – goldfrapp04

3

Sie haben ein weiteres Problem, dass Ihr Server-Programm Multiprozess ist und Gabeln jedes Mal, wenn es eine eingehende Verbindung erhält. Das Elternelement bleibt aktiv, um neue Verbindungen zu akzeptieren, und das Kind verarbeitet die Verbindung. Das Beenden des untergeordneten Prozesses ist nicht ausreichend, um zu bewirken, dass das übergeordnete Element ebenfalls beendet wird.

Wenn Sie nur eine Verbindung verarbeiten möchten, verwenden Sie nicht Gabel.

Wenn Sie Ihre aktuellen Setup fortsetzen, dann müssen Sie das Kind Prozess ändern, um den übergeordneten Prozess das SIGCHLD Signal (empfangen, wenn ein Kind Prozess beendet) zu handhaben verwenden _exit statt exit und zu erhalten.

dh.

#include <signal.h> 

void terminate(int signal) { 
    // close sockfd -- you will need to make it global 
    // or have terminate alter some global variable that main can monitor to 
    // detect when it is meant to exit 
    exit(0); // don't exit if you choose the second option 
} 

int main() { 

    signal(SIGCHLD, terminate); 

    ... 

} 
+0

Danke. Ich sollte keinen Kindprozess von Anfang an verwenden ... Das ist, weil mein ursprüngliches Programm war, den Server am Leben zu erhalten. – goldfrapp04