Le serveur utiliser le même socket pour envoyer la réponse au client? comment?
Je suis en utilisant des sockets de Berkeley (à la fois: domaine de l'Internet et du domaine Unix) et je me demandais si le serveur peut utiliser les mêmes prises pour la lecture de la demande et la rédaction d'une réponse au client. Ou si le client en créer un autre socket attendre pour la relecture et le serveur connecter après le traitement du message reçu.
Par le chemin, je parle de la connexion orientée prises de courant (flux de sockets TCP, ...).
C'est la simplification de code du serveur (j'ai omettre la vérification des erreurs sur le système appelle ici juste pour des raisons de simplicité):
int main() {
int server_socket, connected_socket;
struct sockaddr_in server_addr;
char buf[1024];
char aux[256];
int bytes_read;
server_socket = socket(AF_INET, SOCK_STREAM, 0);
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;
server_addr.sin_port = htons(1234);
bind(server_socket, &server_addr, sizeof(server_addr))
listen(server_socket, 5)
connected_sodket = accept(server_socket, 0, 0);
do {
bzero(buf, sizeof(buf));
bytes_read = read(connected_socket, buf, sizeof(buf));
} while (bytes_read > 0);
/* Here I want to use connected_socket to write the reply, can I? */
close(connected_socket);
close(server_socket);
return (EXIT_SUCCESS);
}
Et c'est la simplification de code client (j'ai omettre la vérification des erreurs sur le système appelle ici juste pour des raisons de simplicité):
int main() {
int client_socket;
struct sockaddr_in server_addr;
client_socket = socket(AF_INET, SOCK_STREAM, 0);
hp = gethostbyname("myhost");
server_addr.sin_family = AF_INET;
memcpy(&server_addr.sin_addr, hp->h_addr_list[0], hp->h_length);
server_addr.sin_port = htons(1234);
connect(client_socket, &server_addr, sizeof(server_addr));
write(client_socket, MSG, sizeof(MSG));
/* Here I want to wait for a response from the server using client_socket, can I? */
close(client_socket);
return (EXIT_SUCCESS);
}
Puis-je utiliser connected_socket
dans le serveur et client_socket
dans le client de transmettre un message de réponse en retour? Ou dois-je utiliser l'adresse du client je reçois dans le serveur quand à "accepter" pour vous connecter à une prise dans le client?
J'ai essayé en utilisant de lecture/wrint dans le client/serveur où le commentaire est affiché mais de cette façon, les deux programmes de maintenir bloqué, il semble être une impasse.
Grâce ins avance!
Ce qui concerne.
OriginalL'auteur mmutilva | 2009-01-21
Vous devez vous connecter pour publier un commentaire.
Vous pouvez utiliser la même prise MAIS votre programme est mis en place pour avoir le serveur de lire TOUT ce que le client envoie avant de tenter de répondre. Donc la boucle dans le serveur ne sera pas complète jusqu'à ce que le client ferme l'écriture, à côté de son support afin que le serveur reçoit une EOF (0 octets lus), et donc le serveur n'enverra jamais de retour à sa réponse.
Il ya un couple de façons dont vous pouvez faire face.
shutdown(client_socket, SHUT_WR)
à demi-fermer le socket. Le serveur va ensuite voir les expressions du FOLKLORE (et la boucle sera fini), mais dans l'autre sens sur le socket seront toujours ouverts pour la réponse.Historiquement, de nombreux protocoles Internet sont "ligne de base" en ce que lorsque le serveur reçoit un retour à la ligne (ou CRLF), il sera procédé à la ligne actuelle de saisir et de transmettre une réponse au client.
Comment puis-je "breack la boucle dans le serveur" comme l'option 1 dit?
Lorsque le serveur voit le délimiteur final de la demande, il pourrait sortir de la boucle et d'envoyer une réponse, plutôt que d'attendre que les expressions du FOLKLORE
OriginalL'auteur
Vous devrait utiliser le même support!
Votre protocole d'application définit sans ambiguïté lorsque le client et le serveur doit attendre de données ou d'envoyer des messages les uns aux autres; en supposant un protocole avec seulement une demande de la part du client et d'une réponse du serveur, celui-ci doit contenir:
OriginalL'auteur
Oui, c'est possible. Look découvrez cette page pour un exemple simple (serveur et client). Notez que le serveur passe généralement la "accepter"ed descripteur de fichier dans un nouveau processus afin qu'il puisse continuer à l'écoute pour plus de connexions entrantes
OriginalL'auteur
Non seulement devez-vous utiliser le même socket (comme Federico dit), vous avez réellement ont pour afin d'obtenir les paquets de retour à travers les pare-feu.
Pare-feu savoir sur les connexions TCP, et autoriser automatiquement les données de retour à passer à travers si une machine à l'intérieur du pare-feu a initié la connexion. Si, au contraire, essayé de créer un nouveau socket TCP à partir de l'extérieur du pare-feu pourrait bloquer à moins que le trafic est expressément autorisée.
OriginalL'auteur
Oui, les sockets SOCK_STREAM sont les deux sens. Vous devriez être en mesure de lire et d'écrire dans/à partir de la même prise sur chaque côté de la connexion. La page de man pour
socket(2)
a plus de détails sur cette.OriginalL'auteur
Oui, vous le pouvez. Les sockets TCP sont bi-directionnels. Utiliser le même read() et write (). Assurez-vous également de vérifier les conditions d'erreur sur tous les appels à connect(), read(), write(), ... que vous ne pouvez pas contrôler ce qui se passe sur le réseau.
OriginalL'auteur
Désolé, je ne voulais pas le dire mais j'ai essayer comme ça
Ce code dans le serveur où le commentaire est:
et ce code dans le client d'où le commentaire est:
À la fois des programmes de maintenir bloqué et quand je tue le client, le serveur affiche les messages qu'il a reçu (j'ai un printf juste après les appels au serveur lire).
Je l'ai essayer avec send et recv (à la fois avec 0 drapeaux) au lieu de lire et d'écrire, et il n'a pas changé.
Si je laisse le code comme le post original (pas de réponse du serveur), le serveur débloque instantanément, et c'est à l'aide d'un tampon aussi grand que celui du client.
wdu est incorrecte alors que "fread()" bloquera jusqu'à ce que le tampon est plein, "lecture" ne sera pas. Sur un socket, il va généralement correspondre à chaque écriture (ou paquet) à lire.
Eh bien, qui correspond à ma description. Lisez toujours inférieur ou égal à celui que vous avez envoyé, et que vos appels ne va pas bloquer. read() attend jusqu'à ce que suffisamment de données est reçu à remplir la mémoire tampon complètement (ou jusqu'à ce que la connexion est fermée ou d'une autre erreur), à moins que la socket est non bloquant.
C'est vrai Alnitak, je viens de re-lire le lire de la page de manuel et il ne dit rien à propos de remplissage de la mémoire tampon. Merci!
OriginalL'auteur
Dans votre configuration actuelle, le serveur tente de lire jusqu'à ce que le client ferme la socket, si le client ne veut pas fermer le socket jusqu'à ce que le serveur a répondu. Donc, vous avez une sorte de "blocage". Le serveur n'est pas l'arrêt de la lecture dans l'espoir que certains plus de données peut arriver et le client n'a aucun moyen de dire au serveur c'est fait.
Vous avez besoin pour le serveur de reconnaître que la demande est complète, alors que la connexion est toujours ouverte. Si vous, par exemple de mettre fin à votre demande par un saut de ligne, le serveur peut vérifier s'il a reçu une ligne complète, puis arrêter de lire et d'envoyer la réponse.
Dire que le client envoie "liste des fichiers\n". Le serveur reçoit la liste des "f" à la première lecture(), ne trouve pas de "\n" et continue de lire()ing. Puis il reçoit le reste des "iles\n" et désormais "à la liste des fichiers\n", c'est de la mémoire tampon. Il voit le "\n", décide que la commande est complète et envoie la réponse.
Btw: dans votre exemple, vous remettre à zéro la mémoire tampon dans chaque itération de la alors en boucle, en laissant le tampon vide une fois que vous atteignez le point où vous avez l'intention d'envoyer la réponse... Vous avez sans doute aussi besoin d'utiliser recv() au lieu de lire().
Merci pour l'exemple et les commentaires. Cependant, j'ai résolu avec le client d'appel de l'arrêt(client_socket, SHUT_WR) après l'envoi de son message comme Chris Dodd suggéré.
OriginalL'auteur
Avez-vous essayé? Il semble que ça devrait fonctionner lorsque vous fait mettre le code à l'endroit indiqué
OriginalL'auteur