Multiples messages non reçus...:((

Signaler
Messages postés
627
Date d'inscription
mercredi 16 juin 2004
Statut
Membre
Dernière intervention
24 juillet 2011
-
Messages postés
1905
Date d'inscription
mercredi 22 janvier 2003
Statut
Membre
Dernière intervention
17 septembre 2012
-
Bonsoir tout le monde!

Je suis actuellement en cours d'apprentissage des Sockets et j'ai crée une application Client/Server pouvant communiquer ensemble! Il n'y a pas de souci lors de la connexion etc...en fait, le client envoie 2 messages ("salut!!!", et "xpldr!!")...mais seul le premier ("salut!!!") est reçu, pas le second! En fait, le server récupère des buffers vides après des appels à recv()....comme si il n'attendais pas l'arrivée de données...:s ... j'spère que vous pourrez m'aider...et que mon code n'est pas trop tiré par les cheveux ;)

/* appli cliente */

#include <windows.h>
#include <winsock2.h>


SOCKET sock;
SOCKADDR_IN addr;


int port = 8554;


int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {

WSADATA wsa;
WSAStartup(MAKEWORD(2,2), &wsa);

addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr("213.44.147.196");
addr.sin_port = htons(port);

sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
connect(sock, (SOCKADDR*) &addr, sizeof(addr));

send(sock, "Salut!!!", 15, 0);
send(sock, "xpldr", 15, 0);
MessageBox(0, "Voila, c'est envoyé!! :)", ":)", 0);
}

/* Appli server */

#include <windows.h>
#include <winsock2.h>


WSANETWORKEVENTS Network;
WSAEVENT Event[1];


SOCKET sock, dasock;
SOCKADDR_IN addr, sin;


int port = 8554;


DWORD WINAPI WaitTCPData(LPVOID pv) {

char buffer[500];
int result = SOCKET_ERROR;

int TimedOut = 0;

while(result == SOCKET_ERROR) {

ZeroMemory(buffer, sizeof(buffer));
result = recv(dasock, buffer, 500, 0);

if(lstrlen(buffer) > 2) {

MessageBox(0, buffer, "Server a intercepé ceci :", 0);
TimedOut = 0;
}

else TimedOut++;

if(TimedOut >= 20000) return 0;
}
}


int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {

WSADATA wsa;
WSAStartup(MAKEWORD(2,2), &wsa);

addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = INADDR_ANY;

sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
bind(sock, (SOCKADDR*) &addr, sizeof(addr));

Event[0] = WSACreateEvent();
listen(sock, 5);

char buffer[500];
int sinsize;

while(1) {

sinsize = sizeof(sin);
if((dasock = accept(sock, (SOCKADDR*) &sin, &sinsize)) != INVALID_SOCKET) {

WSAEventSelect(dasock, Event[0], FD_READ);

ZeroMemory(&Network, sizeof(WSANETWORKEVENTS));
WSAWaitForMultipleEvents(1, Event, 0, WSA_INFINITE, 0);
WSAEnumNetworkEvents(dasock, Event[0], &Network);

switch(Network.lNetworkEvents) {

case FD_READ:

DWORD dwTemp;
CreateThread(0, 0, WaitTCPData, (LPVOID) 0, 0, &dwTemp);
break;
}
}
}
}

Gendal67, Dev-C++ 4.9.9.1, J'adore cppfrance!! :-))

18 réponses

Messages postés
1787
Date d'inscription
lundi 22 novembre 2004
Statut
Membre
Dernière intervention
31 janvier 2009
2
Moi déjà j'mettrai 127.0.0.1 comme IP histoire d'être sur que tu le recevra :)
Mais sinon les socket, je connais strictement rien
Faudrait j'mi mette également
Donc si quelqu'un pouvait répondre à sa question et me filer un lien de tutorial
Je serais votre esclave ;)
mdr
Abusé pas qd mm
Bande de proxenete

By Moi


void Aurevoir( void ); //Bonne journée
Messages postés
627
Date d'inscription
mercredi 16 juin 2004
Statut
Membre
Dernière intervention
24 juillet 2011
2
Non Joky, pas 127.0.0.1....le message marche avec la vraie IP, donc pas de pb...le seul souci c'est l'envoie de plusieurs messages (= +d'un appel à send())

Gendal67, Dev-C++ 4.9.9.1, J'adore cppfrance!! :-))
Messages postés
1905
Date d'inscription
mercredi 22 janvier 2003
Statut
Membre
Dernière intervention
17 septembre 2012
3
Salut,
a quoi sert le thread WaitTCPData ?
La fonction WSAEventSelect() met automatiquement le socket dasock en mode non bloquant, donc lors du traitement du FD_READ, tu peux directement appeler recv().

Ensuite, ta boucle principale se compose comme ca:

while(1)
{
if(dasock = accept(...))
{
// traitement
}
}

A la premiere iteration, la connexion est acceptée et le traitement effectué, et dans la seconde iteration, le accept() bloque tout car sock est bloquant.
Messages postés
627
Date d'inscription
mercredi 16 juin 2004
Statut
Membre
Dernière intervention
24 juillet 2011
2
:s oki oki..mais comment faire alors pour recevoir +d'un message FD_READ sans que ça déconne ??

Gendal67, Dev-C++ 4.9.9.1, J'adore cppfrance!! :-))
Messages postés
627
Date d'inscription
mercredi 16 juin 2004
Statut
Membre
Dernière intervention
24 juillet 2011
2
euh, et ça, c'est mieux ?

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {

WSADATA wsa;
WSAStartup(MAKEWORD(2,2), &wsa);

addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = INADDR_ANY;

sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
bind(sock, (SOCKADDR*) &addr, sizeof(addr));

Event[0] = WSACreateEvent();
listen(sock, 0);

char buffer[500];
int sinsize;

while(1) {

sinsize = sizeof(sin);
if((dasock = accept(sock, (SOCKADDR*) &sin, &sinsize)) != INVALID_SOCKET) {

WSAEventSelect(dasock, Event[0], FD_READ);

ZeroMemory(&Network, sizeof(WSANETWORKEVENTS));

WSAWaitForMultipleEvents(1, Event, 0, WSA_INFINITE, 0);
WSAEnumNetworkEvents(dasock, Event[0], &Network);

switch(Network.lNetworkEvents) {

case FD_READ:

ZeroMemory(buffer, sizeof(buffer));
recv(dasock, buffer, 500, 0);
break;
}

}

closesocket(dasock);
}
}

Gendal67, Dev-C++ 4.9.9.1, J'adore cppfrance!! :-))
Messages postés
1905
Date d'inscription
mercredi 22 janvier 2003
Statut
Membre
Dernière intervention
17 septembre 2012
3
Salut,
Faudrait revoir la structure complete du prog, la tu as fait un mélange entre le modele WSAEventSelect, et le modele avec les sockets bloquants + threads.

Pour utiliser le modele WSAEventSelect seul, il faut appeler WSAEventSelect sur le socket sock apres l'avoir bindé, et dans ta boucle principale on doit trouver dans l'ordre: WSAWaitForMultipleEvents pour attendre qu'un event passe a l'état signalé,
puis pour chaque event signalé:
WSAEnumNetworkEvents pour savoir le type d'event (FD_READ, FD_CONNECT, etc..) et ensuite il faut traiter ces events.

Tout cela est bien mieux expliqué dans ce bouquin:
http://betouchi.free.fr/doc_et_ebook/prog_reseau/network2.chm
Messages postés
627
Date d'inscription
mercredi 16 juin 2004
Statut
Membre
Dernière intervention
24 juillet 2011
2
Je l'ai déja ce livre aardman, c'est un ebook que tu m'a déja conseillé et j'en ai déja lu un pti bout....mais bon, surtout parce que c'est entièrement en anglais, je n'ai pas passé des heures à raser tout au peigne fin....nan sérieux, tu pourrais pas m'expliquer toi ? Je ne te demande pas de tout me dire ni de tout me faire mais m'expliquer certains trucs....là j'ai fait ceci, et je ne comprend pas pourquoi ça ne marche pas :

while(1) {

sinsize = sizeof(sin);
if((dasock = accept(sock, (SOCKADDR*) &sin, &sinsize)) != INVALID_SOCKET) {

do {

Event[0] = WSACreateEvent();
WSAEventSelect(dasock, Event[0], FD_READ);

ZeroMemory(&Network, sizeof(WSANETWORKEVENTS));

WSAWaitForMultipleEvents(1, Event, 0, WSA_INFINITE, 0);
WSAEnumNetworkEvents(dasock, Event[0], &Network);

switch(Network.lNetworkEvents) {

case FD_READ:

ZeroMemory(buffer, sizeof(buffer));
recv(dasock, buffer, 500, 0);

MessageBox(0, buffer, "Message reçu sur le server :", 0);
break;
}

} while(1); // c'est juste pour tester avec plusieurs messages...

closesocket(dasock);
}

Gendal67, Dev-C++ 4.9.9.1, J'adore cppfrance!! :-))
Messages postés
627
Date d'inscription
mercredi 16 juin 2004
Statut
Membre
Dernière intervention
24 juillet 2011
2
Re-salut! J'ai regardé le book et j'ai trouvé et cru comprendre certaines choses même si le programme ne marchent toujours pas...que dis tu de ça :

#include <windows.h>
#include <winsock2.h>


#include <stdio.h>


WSANETWORKEVENTS Network;
WSAEVENT Event[5];
SOCKET sockarray[5];


SOCKET sock, dasock;
SOCKADDR_IN addr, sin;
WSAEVENT hEvent;


int port = 8554;
int wsa_connection_cnt = 0;
int index = 0;


int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {

WSADATA wsa;
WSAStartup(MAKEWORD(2,2), &wsa);

addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = INADDR_ANY;

sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
bind(sock, (SOCKADDR*) &addr, sizeof(addr));

hEvent = WSACreateEvent();
WSAEventSelect(sock, hEvent, FD_ACCEPT | FD_CLOSE);

listen(sock, 5);

sockarray[wsa_connection_cnt] = sock;
Event[wsa_connection_cnt] = hEvent;
wsa_connection_cnt++;

char buffer[500];
int sizesin = sizeof(sin);

while(1) {

index = WSAWaitForMultipleEvents(wsa_connection_cnt, Event, FALSE, WSA_INFINITE, FALSE);
index = index - WSA_WAIT_EVENT_0;

WSAEnumNetworkEvents(sockarray[index], Event[index], &Network);

switch(Network.lNetworkEvents) {

case FD_ACCEPT:

dasock = accept(sockarray[index], (SOCKADDR*) &sin, &sizesin);

hEvent = WSACreateEvent();
WSAEventSelect(dasock, hEvent, FD_READ | FD_WRITE | FD_CLOSE);

sockarray[wsa_connection_cnt] = dasock;
Event[wsa_connection_cnt] = hEvent;
wsa_connection_cnt++;

printf("Connexion interceptee et acceptee no: %d\n", wsa_connection_cnt);
break;

case FD_READ:

ZeroMemory(buffer, sizeof(buffer));
recv(sockarray[index], buffer, 500, 0);

hEvent = WSACreateEvent();
WSAEventSelect(sockarray[index], hEvent, FD_READ | FD_WRITE | FD_CLOSE);

MessageBox(0, buffer, "Server a reçu ceci :", 0);
break;

case FD_CLOSE:

closesocket(sockarray[index]);
// CompressArrays(Event, sockarray, &wsa_connection_cnt);
break;
}
}
}

Gendal67, Dev-C++ 4.9.9.1, J'adore cppfrance!! :-))
Messages postés
1905
Date d'inscription
mercredi 22 janvier 2003
Statut
Membre
Dernière intervention
17 septembre 2012
3
Salut,
FD_READ, FD_CLOSE etc. sont des flags, donc pour les tester ont fait:
if(Network.lNetworkEvent & FD_READ)
{ ... }
Messages postés
627
Date d'inscription
mercredi 16 juin 2004
Statut
Membre
Dernière intervention
24 juillet 2011
2
ah vi mince...merci du tuyau, sinon, y a til qqch d'autre d'erroné ou de manquant ?
Merci :)

Gendal67, Dev-C++ 4.9.9.1, J'adore cppfrance!! :-))
Messages postés
1905
Date d'inscription
mercredi 22 janvier 2003
Statut
Membre
Dernière intervention
17 septembre 2012
3
Salut,
Ben pour le FD_ACCEPT ca a l'air d'aller, pour le FD_READ tu dois simplement appeler recv() sur le bon socket (pas besoin de créer d'event ni d'appeler WSAEventSelect, et pour FD_CLOSE il faut fermer l'event, fermer le socket, et enlever les cases vides du tableau (CompressArrays).
Messages postés
627
Date d'inscription
mercredi 16 juin 2004
Statut
Membre
Dernière intervention
24 juillet 2011
2
ça ne marche pas...quand j'enlève les 2fct qui redéclare l'event dans le FD_READ, j'obtiens une première MessageBox() correcte, puis une suite infinie de boites vides! (donc pas le message "xpldr!!" reçu....) ... s je les laisse, je n'ai juste pas de boites vides interminables succesives mais le pb d u 2e message n'est tjs pas résolu...
Voici mon nouvo code :

while(1) {

index = WSAWaitForMultipleEvents(wsa_connection_cnt, Event, FALSE, WSA_INFINITE, FALSE);
index = index - WSA_WAIT_EVENT_0;

WSAEnumNetworkEvents(sockarray[index], Event[index], &Network);

if(Network.lNetworkEvents & FD_ACCEPT) {

dasock = accept(sockarray[index], (SOCKADDR*) &sin, &sizesin);

hEvent = WSACreateEvent();
WSAEventSelect(dasock, hEvent, FD_READ | FD_WRITE | FD_CLOSE);

sockarray[wsa_connection_cnt] = dasock;
Event[wsa_connection_cnt] = hEvent;
wsa_connection_cnt++;

printf("Connexion interceptee et acceptee no: %d\n", wsa_connection_cnt);
}

if(Network.lNetworkEvents & FD_READ) {

ZeroMemory(buffer, sizeof(buffer));
recv(sockarray[index], buffer, 500, 0);

/* hEvent = WSACreateEvent();
WSAEventSelect(sockarray[index], hEvent, FD_READ | FD_WRITE | FD_CLOSE); */

MessageBox(0, buffer, "Server a reçu ceci :", 0);
}

if(Network.lNetworkEvents & FD_CLOSE) {

WSACloseEvent(Event[index]);
closesocket(sockarray[index]);
// CompressArrays(Event, sockarray, &wsa_connection_cnt);
}
}

Gendal67, Dev-C++ 4.9.9.1, J'adore cppfrance!! :-))
Messages postés
1905
Date d'inscription
mercredi 22 janvier 2003
Statut
Membre
Dernière intervention
17 septembre 2012
3
Salut,
S'il y a un bug, aussi bete soit il, tu aura du mal a le trouver avec un code comme ca, il faut traiter systematiquement les erreurs de chaques fonctions, les afficher (printf ou écriture de logs dans un fichier, mais pas MessageBox qui bloque tout). le but est d'avoir un max d'info a l'écran lors de l'execution du prog pour savoir la ou ca fonctionne pas, et donc la ou il faut chercher.
Messages postés
48
Date d'inscription
lundi 29 novembre 2004
Statut
Membre
Dernière intervention
16 mars 2005

Je ne voudrais pas trop en rajouter, mais lorsque tu ouvre une socket
TCP tu fais un bind, ensuite tu "listen " pour une connexion entrante .
Lorsque une connexion est entrante listen () delivre un fd et a ce
moment tu fais un accept(). Apres cela tu pars dans to while recvfrom()
sans jamis plus repasser en accept(). Essaie de grouper open socket,
bind,listen, accept avant de partir dans le while.


Yves
Messages postés
627
Date d'inscription
mercredi 16 juin 2004
Statut
Membre
Dernière intervention
24 juillet 2011
2
Nashua> Merci du conseil....pourtant mon code ressemble presque à un code trouvé dans un manuel best-seller sur les sockets....donc voila, j'ai relativement suivi son plan....il s'est peut-etre gourré, c'est possible! Mais toi, comment aurais-tu fais concretement (code) ?

Gendal67, Dev-C++ 4.9.9.1, J'adore cppfrance!! :-))
Messages postés
1905
Date d'inscription
mercredi 22 janvier 2003
Statut
Membre
Dernière intervention
17 septembre 2012
3
Salut,
Pourquoi mettre accept avant le while ? Il ne sera executé qu'une fois, alors que le prog est un serveur donc on pourrait supposer qu'il faudra accepter d'autres connexions.
Messages postés
48
Date d'inscription
lundi 29 novembre 2004
Statut
Membre
Dernière intervention
16 mars 2005

Si tu veux accepter plusieur connection l'accept() doit etre dans un
while (1) . Dans la derniere mouture du code de Gendal67 le recv
() et l'accept() sont dans une seule bopucle. Ce que je ferait :



While(1) { // mon serveur accepte plusieurs connections au plus maxconnection donne a listen()

listen( sock, maxconnection);

accept();

// Je start un thread pour traiter cette connexion.

}



my_receive_thread(){

while ( recvfrom () > 0 ){

je print le buffer recu

}

}

Desole je n'ai pas un exemple simple sous la main .

.




Yves
Messages postés
1905
Date d'inscription
mercredi 22 janvier 2003
Statut
Membre
Dernière intervention
17 septembre 2012
3
Salut,
Nashua: ce que tu décris c'est le modele de base, c'est a dire socket bloquant + thread pour chaque connexion.
Sous windows on dispose de modeles plus évolués comme WSAAsyncSelect ou WSAEventSelect (entre autres), et il m'a semblé que Gendal67 souhaitait utiliser l'un de ces modeles.