TUTORIAL : LES SOCKETS SOUS WIN (TCP & UDP)

cs_Xs Messages postés 368 Date d'inscription mercredi 14 novembre 2001 Statut Membre Dernière intervention 1 septembre 2008 - 31 déc. 2002 à 16:45
aicouzik Messages postés 1 Date d'inscription jeudi 3 juillet 2008 Statut Membre Dernière intervention 2 décembre 2010 - 2 déc. 2010 à 12:17
Cette discussion concerne un article du site. Pour la consulter dans son contexte d'origine, cliquez sur le lien ci-dessous.

https://codes-sources.commentcamarche.net/source/10246-tutorial-les-sockets-sous-win-tcp-udp

aicouzik Messages postés 1 Date d'inscription jeudi 3 juillet 2008 Statut Membre Dernière intervention 2 décembre 2010
2 déc. 2010 à 12:17
merci, même si j'aurai aimer voir l'utilisation des fonction WSASend() et WSARecv()
Mithfindel Messages postés 1 Date d'inscription vendredi 11 juillet 2008 Statut Membre Dernière intervention 11 juillet 2008
11 juil. 2008 à 14:12
Bon tuto.
Dans UDP_Packet_Sender.cpp, le 4ème paramètre de la fonction sendto(...) permet de spécifier des flags de contrôle de la socket (c.f http://msdn.microsoft.com/en-us/library/ms740148(VS.85).aspx ).

HTH ;)
Utilisateur anonyme
22 juin 2007 à 01:19
j'ai posé ma question sur le forum: http://www.cppfrance.com/infomsg_UDP_968594.aspx
Utilisateur anonyme
21 juin 2007 à 15:48
Bonjours (bonne source merci).
J'ai une question.

En TCP on sait que si l'on doit recevoir par exemple 1024 Octects. On va faire recv() et si avec le premier recv() on recoit pas les 1024 octects on va refaire recv() autant de fois qu'il le faudra pour pouvoir mettre bout à bout les 1024 octects.

Mais en UDP comment cela fonctionnne si on recoit pas les 1024 octects prevu avec recvfrom(), on perd le reste des données ?
Où doit-on refaire recvfrom() tant qu'il le faudra comme en TCP ?

Merci
realic Messages postés 16 Date d'inscription jeudi 16 novembre 2006 Statut Membre Dernière intervention 29 janvier 2016
3 mai 2007 à 15:54
Bonjour,

J'ai trouvé un code qui est très intéressant, mais qui ne me permet pas de recevoir des fichiers.
Je peux recevoir ce que dit le serveur (ce qui est intéressant, mais pas pour le moment).
A partir du moment où je suis sur le point de recevoir un fichier, il me met :
450 Write Error: bad file descriptor.
C'est de l'envoi FTP, pas HTTP (j'ai le même en HTTP, ca marche très bien).
Est-ce que quelqu'un sait ce qu'il me manque pour que ca fonctionne ??
Merci.

voici le code :
#include "stdafx.h"
#include <stdio.h>
#include <winsock.h>
#include "wininet.h"

#ifndef SD_SEND
#define SD_SEND 1
#endif

#define BUFFER_SIZE 5*1024
static HWND hDlg;
static BYTE buff[BUFFER_SIZE], *Buffer;
#define Mes(szTXT) MessageBoxA(hDlg, szTXT,"nvond",MB_OK);
static bool init_winsock(void)
{
WSAData Data;
int Code;
std::ostringstream oss;
if((Code=WSAStartup(MAKEWORD(1, 1),&Data)) != 0)
{
oss<<"erreur dans WSAStartup() : "<<Code;
// printf("erreur dans WSAStartup() : %d\n", Code);
return false;
}
return true;
}

static SOCKET etablir_connexion(u_long adresse_distante, u_short port) {
sockaddr_in sinDistant;
SOCKET sd = socket(AF_INET, SOCK_STREAM, 0);

if(sd!=INVALID_SOCKET) {
sinDistant.sin_family = AF_INET;
sinDistant.sin_addr.s_addr = adresse_distante;
sinDistant.sin_port = port;
if(connect(sd,(sockaddr*)&sinDistant, sizeof(sockaddr_in))==SOCKET_ERROR)
sd = INVALID_SOCKET;
}
return sd;
}

static u_long resoudre_adresse(char* hote) {
hostent* pHE;
u_long adresse_distante = inet_addr(hote);

if(adresse_distante == INADDR_NONE) {
pHE = gethostbyname(hote);
if(pHE == 0) return INADDR_NONE;
adresse_distante = *((u_long*)pHE->h_addr_list[0]);
}
return adresse_distante;
}

static int connectionFtp(HWND hwnd, std::string adr)
{
char *Hote = "anonymous.ftp.ovh.net";//"ftp.free.fr";//"cns.free.fr";
int Port = 21;

init_winsock();

u_long adresse;
SOCKET sd;
char *requete;
char tampon;

// Trouver l'adresse de l'hôte
std::ostringstream oss;
oss<<"Recherche de l'hôte... "<< Hote;
MessageBoxA(hwnd,oss.str().c_str(),"xj",MB_OK);
oss.clear();
adresse = resoudre_adresse(Hote);
if(adresse==INADDR_NONE)
{
MessageBoxA(hwnd,"Echec !","xj",MB_OK);
// printf("Echec !\n");
return 3;
}
MessageBoxA(hwnd,"Connexion en cours !","xj",MB_OK);
//printf("Connexion en cours !\n");
sd = etablir_connexion(adresse, htons(Port));
if(sd!=INVALID_SOCKET) printf("Connecté !\n");

// envoi de la requête
requete="ftp anonymous.ftp.ovh.net\r\nUSER anonymous\r\nPASS a.a@msn.fr\r\nCWD ankamagam\r\nREST 0\r\nRETR Errata.txt\r\nquit\r\n\r\n";//\r\n/*RETR Errata.txt\r\n*/
send(sd, requete, (int)strlen(requete), 0);
std::ostringstream oss1;
// réception de la réponse
DWORD Recu=0;
DWORD Ecrit=0;
int rep;
while(rep=recv(sd,&tampon,1,0)!=0 )
{
regarder(rep);
regarderConnect(rep);
oss1<<tampon;
// Recu++;
// printf("%c", tampon);
}
//oss1<<tampon;
MessageBoxA(hwnd,oss1.str().c_str(),"xj",MB_OK);
/*
if(oss1.str().c_str()[Recu-3]=='1' && oss1.str().c_str()[Recu-2]=='2' && oss1.str().c_str()[Recu-1]=='5')
{
oss1.clear();
std::ostringstream oss2;
Recu=0;
while(recv(sd,tampon,1,0)!=0 && !(oss2.str().c_str()[Recu-2]==')' && oss2.str().c_str()[Recu-1]=='.'))
{
oss2<<tampon;
Recu++;
}
MessageBoxA(hwnd,oss2.str().c_str(),"xj",MB_OK);
}*/
//hOpenFile = ::FtpOpenFileA(hConnect,strFileNameAtServer.c_str(), GENERIC_READ, FTP_TRANSFER_TYPE_BINARY, 1);

FILE* File;
//BYTE* Buffer;
char* buffer=new char[4*1024];
File = (FILE*)CreateFileA("Errata.txt", FILE_ALL_ACCESS, FILE_SHARE_WRITE, 0, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
HANDLE hOpenFile = NULL;
DWORD ToRead=4*1024;
DWORD Size=24017;

// HINTERNET hOpenFile;
HINTERNET hConnect = NULL;
hOpenFile = ::FtpOpenFileA(hConnect,"Errata.txt", GENERIC_READ, FTP_TRANSFER_TYPE_BINARY, 1);
if (!InternetReadFile (hOpenFile, (LPVOID)Buffer, ToRead, &Size) )
{
fclose (File);
//CString strMsg;
//string strReposeFromServer;
//GetLastResponse(strReposeFromServer);
//strMsg.Format(L"Error:%d\nDescription:%s", GetLastError(), strReposeFromServer.c_str());
//AfxMessageBox(strMsg, MB_OK);
return 0;
}
WriteFile(File, Buffer, Recu, &Ecrit, 0);
//MessageBoxA(hwnd,oss1.str().c_str(),"xj",MB_OK);

MessageBoxA(hwnd,"FINI","oxi",MB_OK);
// quitter correctement winsock
send(sd,"quit\r\n\r\n", (int)strlen(requete), 0);
shutdown(sd, SD_SEND);
closesocket(sd);
WSACleanup();
return 0;
}
Renfield Messages postés 17287 Date d'inscription mercredi 2 janvier 2002 Statut Modérateur Dernière intervention 27 septembre 2021 74
27 mars 2007 à 15:18
en voilà une remarque "genre" constructive
undertherises Messages postés 2 Date d'inscription dimanche 25 mars 2007 Statut Membre Dernière intervention 27 mars 2007
27 mars 2007 à 15:14
genre c'est du c++ alors que c'est du c. Wé super
cs_viran Messages postés 104 Date d'inscription jeudi 6 mai 2004 Statut Membre Dernière intervention 31 décembre 2006
14 févr. 2006 à 21:39
Excusez moi j'allais oublier : je suis sous windows XP
cs_viran Messages postés 104 Date d'inscription jeudi 6 mai 2004 Statut Membre Dernière intervention 31 décembre 2006
14 févr. 2006 à 21:38
Bonjour a tous, j'aurais besoin de votre aide, j'ai cherché des tutoriaux de socket sur le net et a chaque fois il me sort la meme erreur, il commence a compiler, ne me sort pas d'erreur dans mon script et a chaque fois, sur compilateurs differents avec ce code simplifier a l'extreme :

"#include<stdio.h> //Fichier d'inclusion pour printf, scanf, system...
#include<winsock2.h>//Pour tout se qui touche aux sockets

#pragma comment(lib,"ws2_32.lib")//tjs pour les sockets

void main()
{
WSADATA wsa;
WSAStartup(MAKEWORD(2,0),&wsa);//MAKEWORD dit qu'on utilise la version 2 de winsock

}"

voici l'erreur :

"collect2: ld returned 1 exit status
Process terminated with status 1 (0 minutes, 0 seconds)
0 errors, 0 warnings"

Merci de m'aider.
NitRic Messages postés 402 Date d'inscription mardi 1 mai 2001 Statut Membre Dernière intervention 15 août 2011
5 avril 2005 à 04:51
Si tu permets, j'aimerais bien ajouter quelques petites choses, alors voilà:

pour initialiser Winsock:

int LoadWinsock( unsigned short wVersion )
{

int ret;
WSADATA wsd;

if ( 0 == wVersion )
wVersion = MAKEWORD(2, 0);

if ( 0 (ret WSAStartup( wVersion, &wsd )) )
{
/* version 2.x(2.0, 2.2, ...) */
if ( LOBYTE(wVersion) == LOBYTE(wsd.wVersion) )
return 0;

WSACleanup();
return WSAVERNOTSUPPORTED;
}

return ret;

}


printf("%s","\nPort : ");
tu pourrais faire simplement ceci: printf("\nPort: ");

Sous Windows, un SOCKET est un entier oui, mais non signé(unsigned int) contrairement sous Linux ou c'est un entier signé(int) ...

Pour tes scanf("%s", buffer); tu devrais plutôt faire:

scanf( "%50s", buffer ); /* pour éviter d'aller écrire trop loin dans `buffer` */
et ensuite, utiliser strlen() lors des envois:

scanf("%50s", buffer);
buffer[sizeof(buffer)] = '\0'; /* s'assure d'avoir un '\0' */

length = strlen( buffer );
error = send( uSocket, buffer, length, 0 );

et de plus, tu évite les memset() ...

Tu pourrais aussi utiliser gets() ou encore fgets() mais bon ...

connect() ne renvoie pas `true` mais -1(SOCKET_ERROR) en cas d'erreur ...

Si connect() renvoie -1(SOCKET_ERROR) tu devrais vérifier que ton socket n'est pas bloquant/en progression:

int ret = connect( ... );
if ( (ret == SOCKET_ERROR) && (WSAEWOULDBLOCK != WSAGetLastError()) )
{
puts("ERROR!!!");
}
else puts("GOOD");

les fonctions htonl(), htons() et compagnie ne convertissent pas les données qu'elles recoivent en nombre _pour Windows_ mais pour ... hummm ... je sais pas comment `bien` le traduire en francais mais voilà en anglais:
"The htons function takes a 16-bit number in host byte order and returns a 16-bit number in network byte order(big-endian) used in TCP/IP networks."

Même chose pour htonl(), sauf que htonl() c'est 32bits et non 16bits ...

big-endian : 4321
little-endian : 1234
middle-endian : 2143/3412

recv() renvoie, soit -1(une erreur), soit 0(connexion fermé `correctement`) ou une valeur positif(des données ont été lus) ...

void main() /* c'est pas bien ca ... */
{
}

int main() /* ca c'est bien */
{
return 0;
}

Au fait, un `port` est un entier 16bits non signé(unsigned short) et non un entier 16/32/64/..bits signé ... il ne faut pas oublier qu'un `int` est dépendant du système, 16, 32, 64, ...

Pour le serveur(tcp) tu as mis `err = scanf(...);`, tu devrais plutôt vérifier send() & recv() ...

char ip[15]; << c'est trop petit
000.000.000.000 == 3*4=12+3=15, l'espace pour le '\0' il est ou???

#define IPV4_LENGTH (17) /* taille raisonable */
char ip[IPV4_LENGTH]; /* la c'est bien & safe ... */

Pour INADDR_ANY faut quand même utiliser htonl() ...

Voilà, je crois que c'est tout ce que j'avais à ajouter ...

@++;



~(.:: NitRic ::.)~
mythic_kruger Messages postés 241 Date d'inscription jeudi 8 janvier 2004 Statut Membre Dernière intervention 10 novembre 2005
20 mars 2005 à 09:39
Un bon code de tutorial. Hyper-commenté. La classe.
CptLuthor Messages postés 25 Date d'inscription dimanche 7 novembre 2004 Statut Membre Dernière intervention 9 décembre 2004
8 nov. 2004 à 10:07
quand on connecter en VPN , c quel protocol : TCP ou UDP ?

il ya aussi le protocol PPTP, est-il du meme genre que TCP ou UDP ou est ce un protocol secondaire ? cest a dire que c'est un protocol encapsuler par TCP ou UDP

Quand je suis connecter avec un pot par VPN, on peut se voir dans les jeux, par exemple quake3, le fait que lon puisse se voir c'est grace a quel protocol ?

merci
Utilisateur anonyme
28 mai 2003 à 13:32
Effectivement, il vaut mieux fermer les sokets avec closesocket et vider les WSA avec WSACleanup, autant faire les 2...
Chez moi tout marche trés bien en local, d'ailleurs je n'ai amais testé en wan :$
Si vous voulez d'autres trucs sur le sockets, mon site commence à etre fourni (http://www.progzone.ht.st)
BlackGoddess Messages postés 338 Date d'inscription jeudi 22 août 2002 Statut Membre Dernière intervention 14 juin 2005
18 avril 2003 à 18:13
ca me parait plus propre de libérer les ressources au fur et a mesure, surtout dans un tutorial : en effet si qq1 reprend ce code avec plusieurs sockets utilisés les uns apres les autres, il ne va faire qu'un WSAStartup/WSACleanup, mais ne va pas libérer les ressources demndées par les sockets au fur et à mesure -> c'est du gaspillage
cs_sena Messages postés 126 Date d'inscription jeudi 9 janvier 2003 Statut Membre Dernière intervention 15 février 2005
18 avril 2003 à 14:11
je me répète, TUTORIAL EXCELLENT.

Par contre j'ai vu d'autre code qui ressemble au tien mais a la fin, ils ont cette ligne en plus:
closesocket(sock);

Pourkoi toi tu ne fermes pas tes sockets?
C'est WSACleanup() qui le fait?
cs_sena Messages postés 126 Date d'inscription jeudi 9 janvier 2003 Statut Membre Dernière intervention 15 février 2005
14 févr. 2003 à 12:00
Très bien le code !
J'utilise 2 postes pour ton client-serveur en UDP.
Ca fonctionne très bien. bravo!
Mais comme je suis un peu barré il faut que ces 2 prog tournent sur la même machine en même temps.
En clair: le client envoi sur le port n°11060 à l'adresse 127.0.0.1 (ou bien l'ip de la machine) et le serveur écoute sur le port n°11060.
Et bien ca ne fonctionne pas ! (pourtant seule l'adresse ip change lorsque l'on utilise 2 postes)

Quelqu'un sait pourquoi on ne peut pas faire tourner ceci sur 1 machine?
Utilisateur anonyme
9 janv. 2003 à 19:17
sa donne l'addr ip distante en server ??
BlackGoddess Messages postés 338 Date d'inscription jeudi 22 août 2002 Statut Membre Dernière intervention 14 juin 2005
6 janv. 2003 à 13:48
oui, l'adresse et le port sont contenus dans SOCKADDR_IN
le port dans sin_port et l'adresse dans sin_addr

pour le port, il faut faire ntohs(sa_in.sin_port) pour l'avoir,
et pour l'ip il faut faire inet_ntoa(sa_in.sin_addr)
Utilisateur anonyme
2 janv. 2003 à 15:32
C cool!
C le genre de tut que je cherche...
Tu vx pas ecrire des tuts pour mon site?
http://underground.blackwizzard.com
repond par msg sur le site ou par mail postmaster@blackwizzard.com
cs_Xs Messages postés 368 Date d'inscription mercredi 14 novembre 2001 Statut Membre Dernière intervention 1 septembre 2008
1 janv. 2003 à 16:17
oui, effectivement : recuperer le destinataire+port, mais ce qui m'interresse c'est la source : ip et port. et ca, je ne sais pas. D'apres toi, c'est possible de dire tout cela depuis l'emmetteur mais de recuperer les infos des packets pour afficher les infos chez le receveur, c'est plus dur ?? je vais chercher de mon coter. merci.
Utilisateur anonyme
1 janv. 2003 à 10:19
Pour le client, c simple de récuperer l'ip destination et le port
Mais pour le server...
Faudrait regarder si c pas stocké dans SOCKADDR_IN
Ou bien faire du RAW(chaque packet contient tt ces infos)
Pour l'UDP c pareil pour le receveur...
cs_Xs Messages postés 368 Date d'inscription mercredi 14 novembre 2001 Statut Membre Dernière intervention 1 septembre 2008
31 déc. 2002 à 16:45
bien. mais tu pourrais "developper" : par exemple, tu pourrrais recuperer l'ip destination, source, port, etc... et les afficher dans le receveur. ca serais cool, parce que je cherche comment faire, lol :)
Rejoignez-nous