lire et écrire sur le même socket (TCP) en utilisant select
Nous sommes en train d'écrire un client et un serveur pour le faire (ce que je croyais) assez simple réseau de communications. Plusieurs clients se connectent au serveur, qui puis est censé envoyer les données en arrière pour tous les autres clients.
Le serveur se trouve juste en bloquant select
boucle d'attente pour le trafic, et quand il vient, envoie les données pour les autres clients. Cela semble très bien fonctionner.
Le problème, c'est le client. En réponse à une lecture, il sera parfois amené à faire une écriture.
Cependant, j'ai trouvé que si j'utilise:
rv = select(fdmax + 1, &master_list, NULL, NULL, NULL);
Mon code bloque jusqu'à ce qu'il y a de nouvelles données à lire. Mais parfois (de manière asynchrone, à partir d'un autre thread) je vais avoir des nouvelles données à écrire sur le réseau de communication thread. Donc, je veux que mon sélectionnez réveiller périodiquement et laissez-moi vérifier si il y a des données à écrire, comme:
if (select(....) != -1)
{
if (FD_SET(sockfd, &master_list))
//handle data or disconnect
else
//look for data to write and write() /send() those.
}
J'ai essayé le réglage de la sélectionner pour interroger le mode (ou ridiculement court délais d'attente) avec:
//master list contains the sockfd from the getaddrinfo/socket/connect seq
struct timeval t;
memset(&t, 0, sizeof t);
rv = select(fdmax + 1, &master_list, NULL, NULL, &t);
mais ont trouvé que puis ensuite le client ne reçoit jamais de données entrantes.
J'ai aussi essayé le réglage de la prise fd non-blocage, comme:
fcntl(sockfd, F_SETFL, O_NONBLOCK);
mais qui ne résout pas le problème:
- si mon client
select()
n'a pas destruct timeval
la lecture des données fonctionne, mais il n'a jamais débloque à me regarder pour l'écriture de données. - si mon client
select()
a untimeval
de l'obtenir pour un sondage, puis il n'a jamais signaux qu'il existe des données entrantes à lire, et mon application se fige la pensée il n'y a pas de connexion au réseau fait (malgré le fait que tous les autres appels de fonction ont réussi)
Tous les pointeurs du tout à ce que je pouvais faire de mal? N'est-il pas possible de faire de la lecture-écriture sur le même socket (je ne peux pas croire que c'est vrai).
(EDIT: La réponse correcte, et chose que je me suis rappelé sur le serveur mais pas sur le client, c'est d'avoir un deuxième fd_set, et copie master_list avant chaque appel à select():
//declare and FD_ZERO read_fds:
//put sockfd in master_list
while (1)
{
read_fds = master_list;
select(...);
if (FD_ISSET(read_fds))
....
else
//sleep or otherwise don't hog cpu resources
}
)
source d'informationauteur MarcWan
Vous devez vous connecter pour publier un commentaire.
Tout semble parfait, à l'exception de la ligne, où vous faire
if (FD_SET(sockfd, &master_list))
. J'ai très semblable à la structure du code et j'ai utiliséFD_ISSET
. Vous êtes censé pour tester si la liste est définie, ne pas fixer de nouveau. Autre que cela, je ne vois rien d'autre.Modifier. Aussi, j'ai le texte suivant pour le délai:
peut-être il y a un problème si vous le réglez à 0 (comme vous semblez le faire?)
Edit2. Je me suis souvenu que j'avais un problème étrange quand je n'étais pas de compensation de la lecture définie après l'sélectionnez quitté et avant que j'entre à nouveau. J'ai dû faire quelque chose comme:
avant j'était à l'entrée de
select
. Je ne me souviens pas pourquoi.Je crois me souvenir d'un truc à propos de la création et de partage en lecture/écriture filedescriptor entre le réseau de fil et le thread principal qui est ajouté à l'descripteurs dans l'sélectionnez appeler.
Cette fd a un octet écrit par le thread principal quand il a quelque chose à envoyer. L'écriture se réveille réseau de fil de la sélection d'appel et le réseau fil est ensuite saisit les données dans une mémoire tampon partagée et l'écrit dans le réseau, puis aller de nouveau au sommeil dans le select.
Désolé si c'est un peu vague et manque de code ... et ma mémoire est peut-être incorrect.. alors que d'autres peuvent avoir de vous guider plus loin.
Je ne vois rien de mal avec votre code, donc, il faut travailler. Si vous ne pouvez pas obtenir ce travail, une façon de contourner ce serait créer une pipe à être utilisé par votre thread de lecture et le fil qui prépare des choses pour l'écriture, et ajouter de la canalisation de la lecture de la fin de votre
select
ensemble. Puis, quand l'autre thread a préparé les données à écrire, il envoie juste quelque chose sur la conduite, votre lecture fil est réveillé de laselect
et elle peut alors faire l'écriture. Selon la façon dont souvent il y a des données à lire ou à écrire, ce qui pourrait aussi être plus efficace.2 fils doivent être en mesure de travailler avec le même socket à un moment, de sorte que votre thread principal doit être en mesure d'écrire à un client, tandis que l'autre dort en sélectionner d'attente pour l'entrée de données. Cela suppose bien sûr que les deux threads ont accès à la liste des clients.