2012-05-21 20 views
6

Estoy intentando la transferencia de archivos TCP en Linux. Después de establecer la conexión, el servidor debe enviar "send.txt" al cliente, y el cliente recibe el archivo y lo guarda como "receive.txt". Entonces la conexión se rompe.Transferencia de archivos usando TCP en Linux

La entrada y la salida correcta debe ser:

Terminal Server:

$./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. 

terminal de cliente:

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

Y tanto el servidor como el cliente deben salir después del proceso.

Pero lo que tengo ahora da

$ ./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*/ 

Además, un VACÍO "receive.txt" se genera.

Mi código se escribió primero para transferir cadenas simples, y funcionó correctamente. Así que supongo que el problema radica en la parte de transferencia de archivos.

Mi código es el siguiente:

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); 
} 

Muchas gracias!

+2

duplicado posible de [Enviar y recibir un archivo en la programación del zócalo en Linux con C/C++ (GCC/G ++)] (http://stackoverflow.com/questions/2014033/send-and-receive-a -file-in-socket-programming-in-linux-with-cc-gcc-g) –

Respuesta

4

Necesita agregar el código al código f_block_sz. recv() tiene unos valores de retorno: Posible

  • <0 - error, número de error en errno (errno.h)
  • 0 - Conexión cerrada
  • >0 - leer los datos, el número de bytes

Necesita manejar la segunda caja. Añadir este caso else:

else if(f_block_sz) 
{ 
    break; 
} 

modo que el lazo se rompió cuando el servidor cierra la conexión, y el código que se imprimirá [client] connection lost y salida.

+0

Gracias. ¡Debería haberme dado cuenta de esto antes! – goldfrapp04

3

Tiene otro problema ya que su programa de servidor es multiproceso y se bifurca cada vez que recibe una conexión entrante. El padre se mantiene con vida para aceptar nuevas conexiones y el niño procesa la conexión. La salida del proceso secundario no es suficiente para hacer que el padre también salga.

Si solo desea procesar una conexión, no utilice la horquilla.

Si desea continuar su configuración actual, entonces tendrá que cambiar el proceso hijo a usar _exit en lugar de exit y obtener el proceso padre para manejar la señal SIGCHLD (recibida cuando un proceso hijo salidas).

es decir.

#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

Gracias. No debería usar un proceso secundario desde el principio ... Eso es porque mi programa original era mantener vivo el servidor. – goldfrapp04

Cuestiones relacionadas