Transfert de fichier client/serveur à l'aide de socket
Je suis en train de faire un transfert de fichiers entre le serveur et le client, mais fonctionne très mal. Fondamentalement, ce qui doit arriver est:
1) Le client d'envoyer un fichier txt sur le serveur (je l'ai appelé "quotidiani.txt")
2) Le serveur enregistre dans un autre fichier txt ("receive.txt")
3) Le serveur exécute un script qui modifie et enregistre sous un autre nom ("output.txt")
4) Le serveur d'envoyer le fichier vers le client qui le sauve (sur le même socket) avec le nom (final.txt)
Le problème est que le premier fichier (quotidiani.txt) lire juste pour une petite partie, et puis il y a quelques erreurs. J'aimerais que quelqu'un m'aide à comprendre et à corriger mes erreurs.
Voici mon code:
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);
}
serveur.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);
//}
}
}
C'est un projet, je dois faire de cette façon.
Double Possible de Envoyer et Recevoir un fichier dans le support de la programmation sous Linux en C/C++ (GCC/G++)
OriginalL'auteur AscaL | 2012-06-28
Vous devez vous connecter pour publier un commentaire.
Certains commentaires dans aucun ordre particulier:
Vous êtes de la laisser passer l'occasion de connaître exactement les erreurs trop souvent:
Ce bloc devrait certainement inclure des
perror("listen")
ou quelque chose de similaire. Toujours inclureperror()
oustrerror()
dans chaque erreur du bloc de gestion lorsque les détails de l'erreur sera signalée parerrno
. Ayant exacte raisons de défaillance, vous économiserez des heures lors de la programmation et de vous sauver, vous et vos utilisateurs heures quand les choses ne fonctionnent pas comme prévu dans l'avenir.Votre erreur besoins de manipulation de certains autres normalisation:
Cela devrait pas
return 0
parce que ce sera le signal de la coquille que le programme est exécuté à la fin sans erreur. Vous devriezreturn 1
(ou utilisezEXIT_SUCCESS
etEXIT_FAILURE
) pour signaler une anomalie de la sortie.Dans ce bloc précédent vous avez obtenu une condition d'erreur, mais de poursuivre l'exécution de toute façon. C'est un moyen rapide d'obtenir de très comportements indésirables. Cela devrait re-démarrer le serveur principal de la boucle ou de quitter le processus de l'enfant ou quelque chose de similaire. (Dépend si vous gardez le multi-processus serveur.)
Le bloc précédent oublié de compte pour
fork()
à défaut.fork()
peut, et ne parviennent pas, en particulier dans les environnements d'hébergement partagés commun dans les universités-de sorte que vous devez être préparé pour le plein, compliqué trois valeurs de retour possibles à partir defork()
: l'échec, enfant, parent.Il semble que vous êtes en utilisant
fork()
sans discernement; votre client et le serveur sont à la fois très simple et la façon dont ils sont conçus pour fonctionner signifie qu'ils ne peut pas être utilisé pour le service de plusieurs clients simultanément. Vous devriez vous cantonner à un seul processus pour chacun d'eux, au moins jusqu'à ce que l'algorithme est parfaitement réglé et vous trouver un moyen pour exécuter plusieurs clients simultanément. Je m'attends c'est la source du problème que vous avez des maintenant.Vous avez besoin d'utiliser des fonctions pour encapsuler les détails; écrire une fonction pour se connecter au serveur, une fonction pour envoyer le fichier, une fonction pour écrire le fichier, etc. Écrire une fonction pour gérer la complexité de la partielle écrit. (Je recommande particulièrement voler la
writen
fonction de la Advanced Programming in the Unix Environment livre du code source. Fichierlib/writen.c
.) Si vous écrivez les fonctions correctement, vous pouvez ré-utiliser à la fois le client et le serveur. (Quelque chose comme les plaçant dansutils.c
et de la compilation des programmes commegcc -o server server.c utils.c
.)Ayant la plus petite des fonctions qui font chacun une chose va vous permettre de vous concentrer sur les petites quantités de code à la fois et écrivez des tests pour chaque que vous aidera à affiner les sections de code doit encore être améliorée.
Pensez à ce que
fork()
t -- il vous donne une copie du programme. Pourquoi est-ce que votre client a besoin d'une copie de lui-même? Pourquoi est-ce que votre serveur besoin d'une copie de lui-même? Vous pourriez probablement supprimer lafork()
entièrement à partir de ces deux programmes, sans effets néfastes. (Il ferait raisonnement sur les programmes beaucoup plus facile.)Je vais commencer par vous rappeler que j'ai trouvé ce code de autour de. je n'ai pas l'écrire et je n'ai pas trop y penser (ceci pour vous dire que ce que je vais dire va probablement être mal), mais comment puis-je obtenir à l'enfant, si je n'utilise pas le fork()? Pour ce que je sais (et je sais, c'est pas beaucoup) quand le serveur d'accepter une connexion, il crée un nouveau socket (donc un nouveau processus) pour gérer le client de connexion donc j'ai utiliser le résultat de la fourchette pour obtenir de qui. Ou peut-être que je suis juste trompée, je ne sais pas vraiment.
Il n'est pas nécessaire de créer un nouveau processus pour chaque socket. Que ni arrive automatiquement, ni est-il souhaitable de lier le cycle de vie du programme pour la mise en réseau. La création d'un nouveau processus pour chaque client soit servi être un bon moyen pour aller lors de la création de petites et simples serveurs, mais vous n'avez pas besoin de complications pour un serveur conçu pour traiter exactement un client. (Le programme de la spécification de l'exécution d'un script avec exactement-nommé en fichiers de l'entretien de plusieurs clients impossible, tel qu'il est.)
Je pense que, en théorie, le serveur est capable de gérer différents clients, le serveur ne puis même pour tout le monde, il lit un fichier et l'envoyer en un autre, est pour le client (utilisateur) pour spécifier le chemin d'accès du fichier. Le script prend en compte le nombre d'occurrence des mots différents dans le fichier, donc je pense que plusieurs personnes pourraient l'utiliser (pas qui est intéressant ou quoi que ce soit, je veux dire l'utiliser pour le but de l'utiliser). A côté de cela, est-il possible que vous pourriez m'indiquer un traitement manuel ou quelque chose pour la manipulation du client sans une fourchette? ou me pointer dans la bonne direction, parce que je n'ai aucune idée de comment je pourrais faire ça.
OriginalL'auteur sarnold
Un point de discussion semble manquer ici, Alors j'ai pensé à le mentionner ici.
Laissez-nous très rapidement comprendre TCP transfert de données. Il y a trois étapes
a)l'Établissement de la Connexion, b)de Transfert de Données, c)de fin de Connexion
Maintenant, ici, un client envoie un fichier sur un serveur, sur un socket TCP.
Le serveur effectue un traitement sur le fichier et l'envoie au client.
Maintenant tous les 3 étapes à faire. L'Établissement de la connexion se fait par l'appel se connecter.
Lecture/écriture des données se fait par recv/envoyer ici et de fin de connexion se fait par fermer.
Le serveur ici est la lecture de données dans une boucle à l'aide de recv.
Maintenant, quand la boucle sera bouclée? Lorsque le recv renvoie 0 ou peut être inférieure à 0 en cas d'erreur.
Quand recv renvoie la valeur 0? -> Quand de l'autre côté a fermé la connexion.
(Lorsque le segment TCP FIN a été recived par ce côté).
Donc dans ce code lorsque le client a fini d'envoyer le fichier,j'ai utilisé une fonction de fermeture, qui envoie la FIN un segment à partir du côté client et du serveur recv pouvez maintenant retourner la valeur 0 et le programme se poursuit.(À mi-chemin près, depuis que le client doit lire les données par la suite).
(Juste pour la compréhension veuillez noter TCP connexion de l'Établissement est un 3 way Handshake et
de fin de connexion est un 4 way handshake.)
De même, si vous oubliez de fermer la connexion de socket sur le serveur du client, de la recv également bloquer pour toujours.
Je pense que c'était la raison pour l'utilisation de ctrl-c pour arrêter parfois, le client qui vous avez mentionné.
Vous pouvez pl. se référer à aucune norme de Réseau du livre ou de la rfc http://www.ietf.org/rfc/rfc793.txt pour apprendre plus au sujet de TCP
J'ai collé le code modifié et aussi peu ajouté quelques commentaires,
Espère que cette explication vous aidera.
Modifié le code de client:
OriginalL'auteur Tanmoy Bandyopadhyay