PDA

View Full Version : [C] WinSock, creazione semplice chat


Mulder90
31-01-2010, 19:12
Ciao a tutti.
Ultimamente mi sono messo a studiare i socket e ho fatto un client e un server il cui codice è quello sotto.
Il client riesce a scrivere messaggi al server che li riceve correttamente.
Volevo creare però qualcosa di più simile ad una chat dove il programma sia in grado di ricevere e spedire messaggi.
Dritte su come iniziare???:D

CLIENT:
#include <stdio.h>
#include <winsock2.h>
#define close closesocket

int init_winsock(void)
{
WSADATA wsadata;
int err;
err=WSAStartup(MAKEWORD(2,2),&wsadata);
if(err!=0)
return 0;
else
return 1;
}

int main()
{
int sock, port;
char ip[17];
char buffer[256];
struct sockaddr_in saddr;

if(!init_winsock())
{
printf("Errore durante l'inizializzazione di winsock2.\n");
return -1;
}

printf("Server Ip: ");
scanf("%16s", ip);

printf("Server Port: ");
scanf("%d", &port);

if((sock = socket(PF_INET, SOCK_STREAM, 0)) < 0)
{
printf("Errore durante la creazione del socket.\n");
return -1;
}

saddr.sin_family = PF_INET;
saddr.sin_addr.s_addr = inet_addr(ip);
saddr.sin_port = htons(port);

if(connect(sock, (struct sockaddr *) &saddr, sizeof(saddr)) < 0)
{
printf("Errore durante la connessione a %s:%d\n", ip, port);
return -1;
}

printf("Connessione correttamente stabilita con %s:%d\n", ip, port);
printf("Ora e' possibile digitare messaggi da inviare al server\n\n");

do {
printf("> ");
fgets(buffer,256,stdin);
}
while(send(sock, buffer, sizeof(buffer), 0) > 0);

printf("Connessione persa.\n");
close(sock);
WSACleanup();

return 0;
}


SERVER:

#include <stdio.h>
#include <winsock2.h>
#define close closesocket
init_winsock(void)
{
WSADATA wsadata;
int err;
err=WSAStartup(MAKEWORD(2,2),&wsadata);
if(err!=0)
return 0;
else
return 1;
}

int main()
{
int sock, clientsd, port = 5000;
char buffer[256];
struct sockaddr_in saddr;

if(!init_winsock())
{
printf("Errore durante l'inizializzazione di winsock2.\n");
return -1;
}

if((sock = socket(PF_INET, SOCK_STREAM, 0)) < 0)
{
printf("Errore durante la creazione del socket.\n");
return -1;
}

saddr.sin_family = PF_INET;
saddr.sin_addr.s_addr = INADDR_ANY;
saddr.sin_port = htons(port);

if((bind(sock, (struct sockaddr *) &saddr, sizeof(saddr))) < 0)
{
printf("Errore durante il binding del socket.\n");
return -1;
}

if((listen(sock, 1)) < 0)
{
printf("Errore durante il settaggio del socket in listening.\n");
return -1;
}

printf("In attesa che un client si connetta...\n");
clientsd = accept(sock, NULL, NULL);
printf("Si è connesso un client.\n\n");

while(recv(clientsd, buffer, 255, 0) > 0)
{
printf("%s\a\n", buffer);
}

printf("Connessione persa.\n");
close(sock);
WSACleanup();

return 0;
}

fero86
31-01-2010, 19:59
Volevo creare però qualcosa di più simile ad una chat dove il programma sia in grado di ricevere e spedire messaggi.
Dritte su come iniziare???:D creare una chat in C usando un socket é relativamente semplice: una volta impostata la connessione col peer basta che realizzi quella che io chiamo una "pompa di I/O", cioé un loop che legge bytes da un file descriptor e li sbatte su un altro. poi fai partire due threads ciascuno dei quali fa girare una pompa di I/O: un thread legge dal file descriptor di stdin e sbatte sul socket, e l'altro legge dal socket e sbatte su stdout. le syscall per realizzare una pompa di I/O sono read e write. da che so io non é indispensabile usare recv e send sui socket, i socket vengono trattati come normali file descriptors e quindi anche read e write funzionano su di essi.

edit - ah, occhio alle modalitá di flush.

Mulder90
31-01-2010, 21:55
creare una chat in C usando un socket é relativamente semplice: una volta impostata la connessione col peer basta che realizzi quella che io chiamo una "pompa di I/O", cioé un loop che legge bytes da un file descriptor e li sbatte su un altro. poi fai partire due threads ciascuno dei quali fa girare una pompa di I/O: un thread legge dal file descriptor di stdin e sbatte sul socket, e l'altro legge dal socket e sbatte su stdout. le syscall per realizzare una pompa di I/O sono read e write. da che so io non é indispensabile usare recv e send sui socket, i socket vengono trattati come normali file descriptors e quindi anche read e write funzionano su di essi.

edit - ah, occhio alle modalitá di flush.

potresti essere un po più chiaro? non ho capito molto bene il metodo

clockover
31-01-2010, 23:42
Altrimenti potresti far creare al server due thread (o più dipende da quanti client insieme vuoi far chattare)! Ogni thread riceverà un messaggio dal client e lo manderà in output sull'altro client!

fero86
01-02-2010, 00:22
potresti essere un po più chiaro? non ho capito molto bene il metodo questa é quella che io chiamo "pompa di I/O" (scritta or ora, codice non testato, spero renda l'idea):

void IoPump(int fdSource, int fdSink) {
const size_t cbBuffer = 0x1000;
char pBuffer[cbBuffer];
while (1) {
ssize_t nResult = read(fdSource, pBuffer, cbBuffer);
if (nResult < 0) {
return;
}
size_t cbRead = (size_t)nResult;

size_t cbWritten = 0;
while (cbWritten < cbRead) {
nResult = write(fdSink, pBuffer + cbWritten, cbRead - cbWritten);
if (nResult < 0) {
return;
}
cbWritten += (size_t)nResult;
}
}
}


ora immaginati di avere un socket descriptor in una variabile di nome "s" ed immaginati di far partire due thread; uno dei due thread invoca:
IoPump(0, s);
e l'altro invoca:
IoPump(s, 1);

fine; hai fatto la chat.

Mulder90
01-02-2010, 12:43
Altrimenti potresti far creare al server due thread (o più dipende da quanti client insieme vuoi far chattare)! Ogni thread riceverà un messaggio dal client e lo manderà in output sull'altro client!

su linux la funzione è fork() giusto?su windows?

Mulder90
01-02-2010, 12:45
questa é quella che io chiamo "pompa di I/O" (scritta or ora, codice non testato, spero renda l'idea):

void IoPump(int fdSource, int fdSink) {
const size_t cbBuffer = 0x1000;
char pBuffer[cbBuffer];
while (1) {
ssize_t nResult = read(fdSource, pBuffer, cbBuffer);
if (nResult < 0) {
return;
}
size_t cbRead = (size_t)nResult;

size_t cbWritten = 0;
while (cbWritten < cbRead) {
nResult = write(fdSink, pBuffer + cbWritten, cbRead - cbWritten);
if (nResult < 0) {
return;
}
cbWritten += (size_t)nResult;
}
}
}


ora immaginati di avere un socket descriptor in una variabile di nome "s" ed immaginati di far partire due thread; uno dei due thread invoca:
IoPump(0, s);
e l'altro invoca:
IoPump(s, 1);

fine; hai fatto la chat.

Grazie mille per la spiegazione...appena ho un po di tempo cerco di mettere in pratica ;)

fero86
01-02-2010, 14:39
su linux la funzione è fork() giusto?su windows? lo standard del C non prevede il multitasking; lo standard POSIX invece si, ma su Windows non é del tutto implementato (la fork ad esempio, per l'appunto, manca perché non é implementabile). se devi fare programmazione concorrente in C non puoi programmare cross-platform, il meglio che puoi fare é usare delle compilazioni condizionali; un'alternativa migliore secondo me é usare la select: non appena uno dei due file descriptors tra 0 e il socket é pronto per la lettura pompi bytes da esso. a quel punto peró non so se puoi usare la IoPump che ti ho scritto sopra, quella l'avevo scritta nell'ipotesi che tu programmassi per un solo sistema.

fero86
01-02-2010, 14:40
su linux la funzione è fork() giusto?su windows? comunque, per farla breve: http://msdn.microsoft.com/en-us/library/ms682453(VS.85).aspx

:D