2009-05-19 8 views
2

J'essaie de conceptuellement travailler à travers un modèle pour une application de socket client-serveur J'écris en C# (client et serveur). Mon serveur devra gérer de nombreux clients à la fois, et de préférence plusieurs demandes provenant d'un client à la fois. J'ai élaboré un conteneur pour ma communication où je vais envoyer un en-tête de longueur fixe au début de chaque message qui contiendra (entre autres choses) la longueur du message. J'ai de l'expérience avec la programmation socket en C#, donc je suis à l'aise avec les sockets asynchrones. La principale difficulté que j'ai avec le concept, c'est que j'ai besoin à la fois du client et du serveur pour pouvoir recevoir des messages à n'importe quel moment. Le client va établir une connexion, et rester "connecté" (comme un client de messagerie instantanée), et il devra à la fois recevoir des données à des moments arbitraires et faire des requêtes à des heures arbitraires. J'avais aussi voulu, dans le cadre de mon protocole, recevoir une réponse à chaque requête faite (que ce soit du serveur au client, ou du client au serveur).C# client-serveur protocole/question de modèle

Je voudrais pouvoir utiliser une seule prise si possible. Je crois que je pourrais faire ce travail en utilisant deux sockets, l'un pour faire des demandes serveur-> client et un pour client-> demandes de serveur, mais je ne veux pas les complications supplémentaires de traiter avec deux ports/connexions. Cependant, en utilisant une seule socket, je ne suis pas sûr de savoir comment gérer les demandes d'envoi et obtenir des réponses quand elles pourraient être entrelacées.

Je ne trouve aucun exemple de serveur ou de client similaire dans ma recherche. Merci à tous ceux qui offrent des idées.

Répondre

2

Si vous utilisez TCP, vous devrez nécessairement avoir un socket par client côté serveur, ainsi que le socket pour écouter les connexions. Pour UDP, vous pouvez faire tout cela avec un socket. Peu importe, procédez comme suit soit pour votre une prise UDP, ou pour chaque socket client TCP:

Avoir un BeginReceive aller à tout moment et BeginWrite lorsque vous l'événement nécessaire se produit (l'utilisateur appuie sur un bouton ou un message est venu que vous devez faire quelque chose).

EDIT: En réponse à votre commentaire, la façon dont je le traiterais serait d'inclure un ID de demande dans votre en-tête. Chaque fois que l'envoi d'une requête (à partir de chaque extrémité) inclut une valeur unique pour ce message. Utilisez un Dictionary<RequestId, RequestState> (avec des substitutions appropriées pour les types) et vérifiez si un message entrant se rapporte à une demande préexistante. De plus, vous pouvez spécifier que tous les ID avec l'ensemble binaire élevé sont des demandes provenant du client et ID avec le bit effacé sont du serveur pour éviter les collisions:

Server      Client 
Request 0x00 -------------> Starts processing 

Starts processing <------- (unrelated) Request 0x80 

Request 0x00 complete <---- Sends response to 0x00 

Sends response to 0x80 ---> Request 0x80 complete 

Ce système est que le protocole OSCAR d'AOL les utilisations pour les demandes avec état (éventuellement lent).

EDIT2: Hm, ok ... vous voulez vraiment bloquer dessus? Quelque chose que vous pourriez faire est d'avoir un thread distinct gérer les appels Send/Receive. Ce thread communiquerait avec le thread principal via une file d'attente "send message" sécurisée pour les threads et une file d'attente "file received" similaire. La raison pour laquelle j'appelle cette dernière une pseudo-file d'attente est que vous voudriez avoir la possibilité de retirer des messages de la file d'attente. Le thread principal mettra un message sur la file d'attente d'envoi, puis bloquera sur la file d'attente de réception. Chaque fois que le thread socket met à jour la file d'attente de réception, le thread principal se réveille et vérifie si le message qu'il souhaite est encore là. Si c'est le cas, il le prendrait (hors service) et terminerait l'opération désirée. Si le message n'est pas encore là, il bloque à nouveau la file d'attente. Lorsque l'opération est finalement terminée, elle reprend simplement son fonctionnement normal et récupère les messages dans la file d'attente de réception et les traite ou fait tout ce qu'elle fait.

Cela a-t-il un sens? Je suis désolé si c'est un peu confus ...

+0

Oui. Mais supposons que le serveur demande quelque chose au client, ce qui prend un certain temps. Pendant ce temps, le client demande au serveur quelque chose. Dans BeginReceive de mon serveur, comment puis-je savoir que les données entrantes sont la requête du client ou la réponse à la requête du serveur? C'est ce que je suis aux prises avec. J'ai les bases de l'async. Merci. – Jarrod

+0

Désolé, tout le discours des douilles m'a fait penser que votre problème était à ce niveau; comment est cette mise à jour? –

+0

Désolé, j'ai eu du mal à cadrer ma question ... mais c'est exactement le genre de chose que j'ai essayé de faire. J'avais pensé à utiliser les ID de requête et le dictionnaire, mais je me demandais comment implémenter une méthode pour faire une requête et bloquer jusqu'à ce que le résultat arrive (et le renvoie) sans utiliser quelque chose comme ResetEvent dans mon objet état de requête. Cela serait mauvais de créer ceux pour chaque demande non? Merci. – Jarrod

3

Les prises sont bidirectionnelles. Vous n'avez besoin que d'une socket pour envoyer des données entre deux points de terminaison. Mais sur le client, vous aurez probablement besoin d'avoir un thread qui lit constamment le socket et notifier un composant ou mettre en file d'attente les données qu'il reçoit afin qu'il soit traité ailleurs, tandis qu'un autre thread envoie des données via le même socket. De cette façon, vous avez une communication asynchrone. Mais du côté du serveur, vous devez ouvrir un ServerSocket qui va se lier à un port TCP et accepter les connexions sur ce port; chaque connexion que vous acceptez est un nouveau Socket. Vous avez donc une socket par client, et vous aurez probablement besoin d'un thread par client.

Vous devez établir un protocole pour les messages que vous passerez dans le socket. Vous pouvez soit brasser votre propre protocole ou en chercher un, en fonction de ce que vous voulez faire. Habituellement, vous enverrez d'abord deux ou quatre octets avec la longueur pour le reste du message, donc l'autre côté sait lire autant d'octets du flux; c'est un message. Le début du message est généralement le type de message; dans un scénario très simple, vous pouvez dire qu'un "1" est une requête client, un "2" est une réponse serveur, un "3" est un écho client, "4" est une réponse écho serveur, "5" est serveur echo, "6" est la réponse d'écho du client, etc. De cette façon, vous recevez un message, vous l'analysez et ensuite vous savez qu'il s'agit d'une requête d'un client ou d'une réponse à un message envoyé par le serveur, par exemple.

Questions connexes