PDA

Visualizza la versione completa : [C] Ricezione dati con Winsock


XWolverineX
17-10-2008, 15:36
Il mio ultimo pallino è realizzare in C un minimale sistema di Chat tra 2 semplici persone.
Sembra inizialmente funzionare, ma ho un piccolo problema.

Dunque in primis il client chiede ip, porta e nickname da usare. Quindi chiamo socket, connect e poi send per inviare i dati.

Il server, d'altra parte, viene inizializzato con socket, bind, listen accept e poi recv per ricevere i dati.
Bind l'ho fatto su 127.0.0.1 e funziona, ma va bene sempre o dovrò poi mettere l'ip esterno pubblico?

Comunque fortunamtanete i dati a recv arrivano.
Ho quindi deciso che la stringa che identifica il nickname del client deve essere del tipo
nickname|N

Arriva la stringa, la tratto e quindi stabilisco la connessione.
A questo punto, il server, dalla sua parte, fa un send di avvenuta connessione con il nick dell'applicazione server.

Dunque, subit dopo il send nickname del client, ho fatto


int bytes = recv(sock,buf,100,0);

Il problema che si pone è che la funzione non ritorna mai. Si impalla li aspettando un pacchetto che non arriva mai evidentemente.

Domanda: devo fare bind e listen anche sul socket client che deve ricevere?
Devo fare un connect con il socket del server sul client?
Devo creare un altro socket adibito alla ricezione?
C'è un timeout in cui recv e send dicono basta e ritornano errore?

XWolverineX
17-10-2008, 15:50
Ho provato a creare un altro socket: accept non ritorna mai.
Allo stesso socket ho fatto bind, listen accept e poi recv: quest'ultima nemmeno ritorna.
Sbaglio qualcosa?

XWolverineX
17-10-2008, 15:59
Forse il codice parlerà meglio di me


#include <iostream>
#include <WinSock2.h>

#pragma comment(lib,"Ws2_32.lib")


using namespace std;

int mode;
DWORD __stdcall StartServer(void *p);
DWORD __stdcall StartClient(void *p);

int main()
{

tryagain:
system("CLS");
cout <<"SimpleChat by Vinz\n";
cout <<"Inserire 1 per modalita' Server, 0 per modalita' Client\n";
cin >> mode;

WSADATA data;

WSAStartup(MAKEWORD(2,2),&data);

switch (mode)
{
case 0:
StartClient(NULL);
break;
case 1:
StartServer(NULL);
break;
case 3:
{
HANDLE h = CreateThread(NULL,NULL,StartServer,0,0,0);
StartClient(NULL);
WaitForSingleObject(h,INFINITE);
CloseHandle(h);
}
break;
default:
cout <<"Scelta non valida.";
cout.flush();
goto tryagain;
break;
}

return 0;
}

DWORD __stdcall StartServer(void *p)
{
/*
char ip[13];
unsigned short porta;
cout <<"Inserire IP pubblico su cui ascoltare. \n";
cin >> ip;
cout <<"Inserire porta su cui ascoltare \n";
cin >> porta;
*/

char *nickname = "SERVERNICK";

sockaddr_in data;
data.sin_port = htons(1234);
data.sin_family = AF_INET;
data.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");

SOCKET sock = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);

bind(sock,(const sockaddr*)&data,sizeof(data));
listen(sock,SOMAXCONN);

SOCKET ClientSocket = accept(sock,NULL,NULL);

closesocket(sock);
char buffer[100];
int bytes = recv(ClientSocket,buffer,100,0);
buffer[bytes] = 0;

char *tmp = strtok(buffer,"|");
tmp = strtok(NULL,"|");
if ((*tmp) != 'N')
{
cout <<"Il client non ha mandato la richiesta adeguata \n";

closesocket(ClientSocket);
WSACleanup();

return 1;
}
cout <<"Connessione stabilita con " << buffer <<endl;

send(sock,nickname,strlen(nickname),0);

bytes = recv(sock,buffer,100,0);

while (bytes != 0)
{
;
}

return 0;
}

DWORD __stdcall StartClient(void *p)
{
char ip[13];
char NickName[10];
char buf[100];
unsigned short porta;

cout <<"Inserire IP a cui connettersi \n";
cin >> ip;
cout <<"Inserire porta a cui connettersi \n";
cin >> porta;
cout <<"Inserire nickname per la chat \n";
cin >> NickName;

strcat(NickName,"|N");

sockaddr_in data;
data.sin_port = htons(porta);
data.sin_family = AF_INET;
data.sin_addr.S_un.S_addr = inet_addr(ip);


SOCKET sock = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
connect(sock,(const sockaddr*)&data,sizeof(data));
send(sock,NickName,strlen(NickName),0);

listen(sock,SOMAXCONN);
accept(sock,NULL,NULL);

int bytes = recv(sock,buf,100,0);
while (bytes == -1)
bytes = recv(sock,buf,100,0);

buf[bytes] = 0;

cout <<"Connessione stabilita con " << buf <<endl;


return 0;
}


Lasciate stare l'orrida progettazione...sono costretto a usare un thread separato per far partire server e client insieme :D

MacApp
17-10-2008, 16:04
yup erano anni che non vedevo un "goto" ;-)

Caiodark
17-10-2008, 16:39
Il socket che hai aperto è bidirezionale, una volta che il thread del server arriva all'accept si blocca in attesa di una connessione. Il client si connette al socket e il thread server avanza alle istruzioni successive.
Essendo il socket bidirezionale recv e send saranno disponibili sia sul server che sul client, la regola è che se il client spedisce il server dev'essere in ricezione e viceversa altrimenti il pacchetto che viene spedito va in timeout.

Esempio:

TEMPO SERVER CLIENT
1 accept connect
2 recv send
3 send recv
... ....

XWolverineX
18-10-2008, 00:30
Originariamente inviato da MacApp
yup erano anni che non vedevo un "goto" ;-)

Si, lo so, e chiedo perdono.


Riguardo l'altra risposta...e dunque??

XWolverineX
18-10-2008, 12:33
Niente??

XWolverineX
18-10-2008, 19:03
Non avete proprio idea??

XWolverineX
19-10-2008, 12:30
Davvero nessuno sa aiutarmi??

XWolverineX
29-10-2008, 10:13
Ho trovato un primo errore: facevo closesocket sul socket con cui poi inviavo i dat dal server
Ma davvero nessuno sa aiutarmi?

Loading