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

Gendal67 Messages postés 627 Date d'inscription mercredi 16 juin 2004 Statut Membre Dernière intervention 24 juillet 2011 - 14 janv. 2005 à 21:37
cs_aardman Messages postés 1905 Date d'inscription mercredi 22 janvier 2003 Statut Membre Dernière intervention 17 septembre 2012 - 17 janv. 2005 à 14:47
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

cs_Joky Messages postés 1787 Date d'inscription lundi 22 novembre 2004 Statut Membre Dernière intervention 31 janvier 2009 2
14 janv. 2005 à 21:50
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
0
Gendal67 Messages postés 627 Date d'inscription mercredi 16 juin 2004 Statut Membre Dernière intervention 24 juillet 2011 2
14 janv. 2005 à 23:31
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!! :-))
0
cs_aardman Messages postés 1905 Date d'inscription mercredi 22 janvier 2003 Statut Membre Dernière intervention 17 septembre 2012 4
14 janv. 2005 à 23:36
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.
0
Gendal67 Messages postés 627 Date d'inscription mercredi 16 juin 2004 Statut Membre Dernière intervention 24 juillet 2011 2
15 janv. 2005 à 00:05
: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!! :-))
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
Gendal67 Messages postés 627 Date d'inscription mercredi 16 juin 2004 Statut Membre Dernière intervention 24 juillet 2011 2
15 janv. 2005 à 00:12
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!! :-))
0
cs_aardman Messages postés 1905 Date d'inscription mercredi 22 janvier 2003 Statut Membre Dernière intervention 17 septembre 2012 4
15 janv. 2005 à 00:19
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
0
Gendal67 Messages postés 627 Date d'inscription mercredi 16 juin 2004 Statut Membre Dernière intervention 24 juillet 2011 2
15 janv. 2005 à 09:18
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!! :-))
0
Gendal67 Messages postés 627 Date d'inscription mercredi 16 juin 2004 Statut Membre Dernière intervention 24 juillet 2011 2
15 janv. 2005 à 10:28
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!! :-))
0
cs_aardman Messages postés 1905 Date d'inscription mercredi 22 janvier 2003 Statut Membre Dernière intervention 17 septembre 2012 4
15 janv. 2005 à 12:47
Salut,
FD_READ, FD_CLOSE etc. sont des flags, donc pour les tester ont fait:
if(Network.lNetworkEvent & FD_READ)
{ ... }
0
Gendal67 Messages postés 627 Date d'inscription mercredi 16 juin 2004 Statut Membre Dernière intervention 24 juillet 2011 2
15 janv. 2005 à 12:54
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!! :-))
0
cs_aardman Messages postés 1905 Date d'inscription mercredi 22 janvier 2003 Statut Membre Dernière intervention 17 septembre 2012 4
15 janv. 2005 à 13:17
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).
0
Gendal67 Messages postés 627 Date d'inscription mercredi 16 juin 2004 Statut Membre Dernière intervention 24 juillet 2011 2
15 janv. 2005 à 13:29
ç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!! :-))
0
cs_aardman Messages postés 1905 Date d'inscription mercredi 22 janvier 2003 Statut Membre Dernière intervention 17 septembre 2012 4
15 janv. 2005 à 13:41
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.
0
cs_Nashua Messages postés 48 Date d'inscription lundi 29 novembre 2004 Statut Membre Dernière intervention 16 mars 2005
16 janv. 2005 à 06:53
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
0
Gendal67 Messages postés 627 Date d'inscription mercredi 16 juin 2004 Statut Membre Dernière intervention 24 juillet 2011 2
16 janv. 2005 à 12:28
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!! :-))
0
cs_aardman Messages postés 1905 Date d'inscription mercredi 22 janvier 2003 Statut Membre Dernière intervention 17 septembre 2012 4
16 janv. 2005 à 12:50
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.
0
cs_Nashua Messages postés 48 Date d'inscription lundi 29 novembre 2004 Statut Membre Dernière intervention 16 mars 2005
17 janv. 2005 à 06:51
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
0
cs_aardman Messages postés 1905 Date d'inscription mercredi 22 janvier 2003 Statut Membre Dernière intervention 17 septembre 2012 4
17 janv. 2005 à 14:47
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.
0