Jump to content
msmsms

programação com sockets em c

Recommended Posts

pikax

"quem nao sabe e' como quem nao ve"


Por muito mais que que estude só aprendo uma coisa, que ainda tenho muita coisa para aprender.

A beleza de um código está em decompor problemas complexos em pequenos blocos simples.

"learn how to do it manually first, then use the wizzy tool to save time."

"Kill the baby, don't be afraid of starting all over again. Fail soon, learn fast."

Share this post


Link to post
Share on other sites
msmsms

"quem nao sabe e' como quem nao ve"

eu testei o teu exemplo e realmente fez troca de mensagem

nao ha forma de eu fazer um chat mais basico mesmo tendo de usar select e as coisas como FD_SET e etc

um chat onde teria apenas o fundamental

1- troca de nome+mensagem entre os clientes

2- avisar todos os clienets que um dado cliente entrou ou saiu

3 - permitir a saida de um cliente da ligação atraves da mensagem quit

///////////////////////////////////////////////////////////////////
// CHAT ENTRE 3 CLIENTES //////////////////////////////////////////
///////////////////////////////////////////////////////////////////
// OBRIGAÇÕES DO SERVIDOR:
// 1 - enviar cada nome de utilizador e cada mensagem recebida para todos os clientes
// 2 - avisar cada cliente sobre a chega de um novo cliente
// 3 - informar cada cliente sobre a saida de um cliente do chat
///////////////////////////////////////////////////////////////////
//	 SERVIDOR
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <errno.h>
#include <netdb.h>
#include <unistd.h>
#include <sys/select.h>
#define N_CHAR 400 // numero de caracteres para cada
int main() {
unsigned int len;
char mensagem[N_CHAR];
char nome[N_CHAR];
struct sockaddr_in address;
int socket;
// UTILIZADORES RESGISTADOS
int cliente1;
int cliente2;
int cliente3;
	// SINTAXE DO SERVIDOR
if (argc != 2) {
 printf("servidor <porto>>\n");
 exit(-1);
}

porto = atoi(argv[1]); // definir o porto

// criar o socket (meio de comunicação)
socket =socket(AF_INET,SOCK_STREAM,0);

// avisar em caso de erro ao criar o socket
if (socket==-1)
	perror("Socket");

address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(porto);

if(bind(socket, (struct sockaddr *) &address, sizeof (address))== -1)
{
	printf("ERROR a fazer bind!\n");
	close(DSCR);
	return 1;
}

if(listen(socket, 1) == -1)
{
	printf("ERROR a fazer listen!\n");
	close(DSCR);
	return 1;
}

cliente1=accept(DSCR,NULL, NULL);
if (cliente1<0)
   perror("Accept");
mensagem[0]='b';
write(cliente1,mensagem,TAM);

cliente2=accept(DSCR,NULL, NULL);

if (cliente2<0)
   perror("Accept2");
mensagem[0]='a';
write(cliente2,mensagem,TAM);
cliente3=accept(DSCR,NULL, NULL);

if (cliente3<0)
   perror("Accept2");
mensagem[0]='a';
write(cliente3,mensagem,TAM);
// troca de mensagens
recv(cliente1, mensagem, N_CHAR, 0); // recv(cliente1, nome, N_CHAR, 0);
write(cliente2,mensagem, N_CHAR);	// write(cliente2,nome, N_CHAR)
recv(cliente2, mensagem, N_CHAR, 0); // recv(cliente2, nome, N_CHAR, 0);
write(cliente1,mensagem,N_CHAR);	 // write(cliente1,nome, N_CHAR)

recv(cliente1, mensagem, N_CHAR, 0); // recv(cliente1, nome, N_CHAR, 0)
write(cliente2,mensagem,TAM);  // write(cliente2,nome, N_CHAR)
recv(cliente2, mensagem, N_CHAR, 0); // recv(cliente2, nome, N_CHAR, 0);
write(cliente1,mensagem,N_CHAR);	 // write(cliente1,nome, N_CHAR)
// para cliente 3 como fica ?????????????????



close(socket);
close(cliente1);
close(cliente2);
close(cliente3);
return 0;
}

Edited by msmsms

Share this post


Link to post
Share on other sites
pikax

1- troca de nome+mensagem entre os clientes

2- avisar todos os clienets que um dado cliente entrou ou saiu

3 - permitir a saida de um cliente da ligação atraves da mensagem quit

Iras que fazer um sistema multi-threaded para os clientes poderem mandar mensagens 'a vontade entre si.

1- Tens a lista dos clientes, quando receberes uma mensagem do cliente vais 'a lista ver qual e' o nome dele.(server)

2- Quando inserires um socket na list, envias uma mensagem a dizer que ele entrou, quando sair da lista, mandas uma mensagem a dizer que saiu.(server)

3- quando o utilizador inserir "quit", "quebras" a ligacao!(client)

Edited by pikax

Por muito mais que que estude só aprendo uma coisa, que ainda tenho muita coisa para aprender.

A beleza de um código está em decompor problemas complexos em pequenos blocos simples.

"learn how to do it manually first, then use the wizzy tool to save time."

"Kill the baby, don't be afraid of starting all over again. Fail soon, learn fast."

Share this post


Link to post
Share on other sites
msmsms

Iras que fazer um sistema multi-threaded para os clientes poderem mandar mensagens 'a vontade entre si.

1- Tens a lista dos clientes, quando receberes uma mensagem do cliente vais 'a lista ver qual e' o nome dele.(server)

2- Quando inserires um socket na list, envias uma mensagem a dizer que ele entrou, quando sair da lista, mandas uma mensagem a dizer que saiu.(server)

3- quando o utilizador inserir "quit", "quebras" a ligacao!(client)

apesar de me ter dado a maluqueira com a tentativa de resolver o problema desta aplicação chat ainda não consegui e ainda não desisti

pelo qual este tópico ainda não se encontra resolvido e espero que no final fique aqui registado essa aplicação chat para que outros possam encontrar e perceber futuramente

- gostaria bastante de saber se para os objectivos do chat que apresentei anteriormente há forma de existir um servidor com um código muito mais simples (não existindo a necessidade de tanta coisa, de tantas funções).

- gostaria também de saber se ao utilizar-mos a função select no código servidor nos vemos obrigados a trabalhar com a função de tempo?

- gostaria de saber da parte de quem me tentou ajudar inicialmente o que consideram que ainda não sei e tenho de saber para a construção desde chat no que diz respeito à programação com sockets.

(eu apenas conheço aquilo que coloquei na minha versão de cliente)

e sei que um cliente deve levar as funções:

Edited by msmsms

Share this post


Link to post
Share on other sites
apocsantos

Boa tarde,

Existe forma de ter um servidor bastante mais simples. No meu caso, que até tenho um feito, tem 397 linhas (com linhas em branco, comentários, etc...), 6 funções no total, incluindo a main() . Por curiosidade o cliente tem 83 linhas.

Na minha opinião falta-te aprender threads, e aprofundar sockets, para conseguires realizar o projecto.

- gostaria também de saber se ao utilizar-mos a função select no código servidor nos vemos obrigados a trabalhar com a função de tempo?
Não entendi a questão... Também não li todo o teu código.

Cordiais cumprimentos,

Apocsantos


"A paciência é uma das coisas que se aprendeu na era do 48k" O respeito é como a escrita de código, uma vez perdido, dificilmente se retoma o habito"

Share this post


Link to post
Share on other sites
msmsms

Boa tarde,

Existe forma de ter um servidor bastante mais simples. No meu caso, que até tenho um feito, tem 397 linhas (com linhas em branco, comentários, etc...), 6 funções no total, incluindo a main() . Por curiosidade o cliente tem 83 linhas.

Na minha opinião falta-te aprender threads, e aprofundar sockets, para conseguires realizar o projecto.

Não entendi a questão... Também não li todo o teu código.

Cordiais cumprimentos,

Apocsantos

Boa tarde,

Existe forma de ter um servidor bastante mais simples. No meu caso, que até tenho um feito, tem 397 linhas (com linhas em branco, comentários, etc...), 6 funções no total, incluindo a main() . Por curiosidade o cliente tem 83 linhas.

Na minha opinião falta-te aprender threads, e aprofundar sockets, para conseguires realizar o projecto.

Não entendi a questão... Também não li todo o teu código.

Cordiais cumprimentos,

Apocsantos

e não podes partilhar esse feito comigo?

mas 300 e tal linhas é dose

eu estou a ler sobre a função select neste site

http://support.sas.com/documentation/onlinedoc/sasc/doc750/html/lr2/select.htm

parece que é a função select que selecciona os clientes no servidor de alguma maneira através de cada socket

se eu consegui-se um exemplo completo cliente e servidor eu poderia tentar fazer uma versão minha através dele e tentar torna-lo mais simples e básico só a fazer o que necessito que faça

Share this post


Link to post
Share on other sites
HappyHippyHippo

feito em 1 hora :

notas de implementação :

- feito com UDP >> muito mais simples ...

- compila em linux

- thread a funcionar (escrever "/quit" para terminar tudo)

- não testado com clientes a ligarem-se

razão porque fiz o código :

- já tens um e não parece que vás mudar por um feito por ti

- apresentação de UDP e exemplificação de porque é mais simples o UDP : 1 só socket para tudo, não é necessário accept

- como vês, nem usei o select ...

observações :

- é necessário linkar á biblioteca pthread : -lpthread

- número total de linha >> 264

- Número total de variáveis globais : ZERO

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/times.h>
#include <sys/select.h>
#include <unistd.h>

#include <pthread.h>

#define MAX_CLIENTS 100
#define BUFFER_SIZE 256

typedef struct AppInfo {
   int on;

   struct {
       int port;
       int socket;
   } server;

   int client_count;
   struct {
       int on;
       struct sockaddr_in address;
   } clients[MAX_CLIENTS];

   pthread_t thread;
} AppInfo;

void app_help();
int app_init(int argc, char ** argv, AppInfo * info);
int app_start(AppInfo * info);
int app_clean(AppInfo * info);

int socket_listen(AppInfo * info);
int socket_send(AppInfo * info, struct sockaddr_in source, const char * buffer);

int client_search(AppInfo * info, struct sockaddr_in address);
int client_add(AppInfo * info, struct sockaddr_in address);
int client_remove(AppInfo * info, struct sockaddr_in address);

void * input_thread(void * info);

int main(int argc, char ** argv) {
   AppInfo info;

   /* read arguments */
   if (app_init(argc, argv, &info) != 0) { app_help(); return -1; }

   /* start server */
   if (app_start(&info) != 0) { app_help(); return -2; }

   /* socket read cicle */
   while (info.on) socket_listen(&info);

   /* cleaning */
   app_clean(&info);

   return 0;
}

void app_help() {
   printf("command: udpserver <port> (default: 10100, min: 1024)\n");
}

int app_init(int argc, char ** argv, AppInfo * info) {
   /* reset app info */
   memset(info, 0, sizeof(AppInfo));
   info->server.port = 10100;

   /* store server port */
   if (argc > 1) {
       info->server.port = strtol(argv[2], NULL, 10);
       if (info->server.port < 1024) {
           printf("Invalid port\n");
           app_help();
           return -1;
       }
   }

   return 0;
}

int app_start(AppInfo * info) {
   struct sockaddr_in address;
   struct timeval tv;

   /* create socket */
   if ((info->server.socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == 0) {
       printf("Socket creation error\n");
       return -1;
   }

   /* bind created socket */
   memset(&address, 0, sizeof(struct sockaddr_in));
   address.sin_family = AF_INET;
   address.sin_port = htons(info->server.port);
   address.sin_addr.s_addr = htonl(INADDR_ANY);
   if (bind(info->server.socket, (struct sockaddr *)&address, sizeof(address)) != 0) {
       printf("Socket binding error\n");
       close(info->server.socket);
       return -1;
   }

   /* set socket timeouts */
   tv.tv_sec = 0;
   tv.tv_usec = 100000000;
   setsockopt(info->server.socket, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(struct timeval));
   setsockopt(info->server.socket, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(struct timeval));

   /* create input thread */
   if (pthread_create(&info->thread, NULL, input_thread, info) != 0) {
       printf("Thread creation error\n");
       close(info->server.socket);
       return -2;
   }

   return 0;
}

int app_clean(AppInfo * info) {
   /* wait for the input thread to stop/terminate */
   pthread_join(info->thread, NULL);

   /* close the opened socket */
   close(info->server.socket);
}

int socket_listen(AppInfo * info) {
   char buffer[bUFFER_SIZE];
   struct sockaddr_in address;
   int address_size, id;

   /* read data from socket */
   if (recvfrom(info->server.socket, buffer, BUFFER_SIZE, 0, (struct sockaddr *)&address, &address_size) == 0) {
       /* check for a join message */
       if (strncmp(buffer, "/join", 5)) {
           /* try to add client to list */
           if (client_add(info, address) == 0)
               /* broadcast /join */
               socket_send(info, address, buffer);
       /* check for a leave message */
       } else if (strncmp(buffer, "/quit", 5)) {
           /* remove client from list */
           if (client_remove(info, address) == 0)
               /* broadcast /quit */
               socket_send(info, address, buffer);
       } else
           /* simple message to broadcast */
           socket_send(info, address, buffer);
   }

   return 0;
}

int socket_send(AppInfo * info, struct sockaddr_in source, const char * buffer) {
   int id;

   /* registed clients cicle */
   for (id = 0; id < MAX_CLIENTS; id++) {
       /* check if the client is on and is not the sender */
       if (info->clients[id].on &&
           memcmp(&info->clients[id].address, &source, sizeof(struct sockaddr_in)) != 0) {
           /* send message */
           sendto(info->server.socket, buffer, strlen(buffer) + 1, 0, (struct sockaddr *)&info->clients[id].address, sizeof(struct sockaddr_in));
       }
   }

   return 0;
}

int client_search(AppInfo * info, struct sockaddr_in address) {
   int id;

   /* registed clients cicle */
   for (id = 0; id < MAX_CLIENTS; id++) {
       /* check if the client is on and is the searched one */
       if (info->clients[id].on &&
           memcmp(&info->clients[id].address, &address, sizeof(struct sockaddr_in)) != 0) {
           /* return id */
           return id;
       }
   }

   return -1;
}

int client_add(AppInfo * info, struct sockaddr_in address) {
   int id;

   /* check if the list if full */
   if (info->client_count == MAX_CLIENTS) {
       /* message client that the server is full */
       sendto(info->server.socket, "/full", 5, 0, (struct sockaddr *)&address, sizeof(struct sockaddr_in));
       return -1;
   }

   /* registed clients cicle */
   for (id = 0; id < MAX_CLIENTS; id++) {
       /* check if the client is on and is the inserting one */
       if (info->clients[id].on &&
           memcmp(&info->clients[id].address, &address, sizeof(struct sockaddr_in)) == 0) {
           /* ignore a join from a registed client */
           return -2;
       }
   }

   /* registed clients cicle */
   for (id = 0; id < MAX_CLIENTS; id++) {
       /* check if the client is not on */
       if (!info->clients[id].on) {
           /* register the client in the available slot */
           memcpy(&info->clients[id].address, &address, sizeof(struct sockaddr_in));
           info->clients[id].on = 1;
       }
   }
   /* increment the registered client count */
   info->client_count++;

   return 0;
}

int client_remove(AppInfo * info, struct sockaddr_in address) {
   int id;

   /* registed clients cicle */
   for (id = 0; id < MAX_CLIENTS; id++) {
       /* check if the client is on and is the removinf one */
       if (info->clients[id].on &&
           memcmp(&info->clients[id].address, &address, sizeof(struct sockaddr_in)) == 0) {
           /* mark the client as off */
           info->clients[id].on = 0;
           return 0;
       }
   }

   return -1;
}

void * input_thread(void * info) {
   AppInfo * aux = (AppInfo *)info;
   char buffer[bUFFER_SIZE];
   int run = 1;

   /* input cicle */
   while (run) {
       /* read input */
       fgets(buffer, BUFFER_SIZE, stdin);

       /* check for quit command */
       if (strncmp(buffer, "/quit", 5) == 0) {
           /* mark the app and thread to terminate */
           aux->on = 0;
           run = 0;
       }
   }

   return NULL;
}

Edited by HappyHippyHippo

IRC : sim, é algo que ainda existe >> #p@p

Share this post


Link to post
Share on other sites
pikax

Ainda ninguem te sugeriu o Beej's Guide to Network Programming?

Da uma espreitadela ...

O @apocsantos disse +3vezes e eu disse 1 ou 2


Por muito mais que que estude só aprendo uma coisa, que ainda tenho muita coisa para aprender.

A beleza de um código está em decompor problemas complexos em pequenos blocos simples.

"learn how to do it manually first, then use the wizzy tool to save time."

"Kill the baby, don't be afraid of starting all over again. Fail soon, learn fast."

Share this post


Link to post
Share on other sites
msmsms

- o trabalho que estou a fazer deixa claro que a comunicação entre clientes e servidor devem utilizar ligações TCP (dai eu ter iniciado em TCP)

por esse motivo uma versão UDP não é válida

- não consegui perceber o site http://beej.us/guide/bgnet/

quando entro em links vou dar a páginas com emails

Edited by msmsms

Share this post


Link to post
Share on other sites
HappyHippyHippo

- o trabalho que estou a fazer deixa claro que a comunicação entre clientes e servidor devem utilizar ligações TCP (dai eu ter iniciado em TCP)

por esse motivo uma versão UDP não é válida

existe alguma referência a esse promenor em algum dos teus post anteriores ???


IRC : sim, é algo que ainda existe >> #p@p

Share this post


Link to post
Share on other sites
msmsms

no trabalho também são dados alguns conselhos que são os seguintes:

fcntl - configurar um socket como não bloqueante

select - esperar ligações ou mensagens de varios sockets em simultanio

FD_ZERO, FD_SET,FD_ISSET - operações de suporte necessarias á utilização do select para gerir varios sockets

Share this post


Link to post
Share on other sites
apocsantos

Boa noite,

@pmg: como disse o Pikax, o Beej's Guide to Network Programming foi sugerido pelo menos umas 3 vezes por mim, mais uma ou duas por ele. Ainda lhe foi sugerido o tuturial de sockets que está na wiki.

Cordiais cumprimentos,

Apocsantos


"A paciência é uma das coisas que se aprendeu na era do 48k" O respeito é como a escrita de código, uma vez perdido, dificilmente se retoma o habito"

Share this post


Link to post
Share on other sites
msmsms

existe alguma referência a esse promenor em algum dos teus post anteriores ???

existe alguma referência a esse promenor em algum dos teus post anteriores ???

eu agradeço a tua ajuda mas de facto é necessário ser TCP

sei que as ligações UDP se dão de forma diferente já dei o UDP antes

nunca falei em UDP neste tópico

criar em TCP é que é mesmo o objectivo se é mais complicado ou não eu não sei ainda

Share this post


Link to post
Share on other sites
HappyHippyHippo

eu agradeço a tua ajuda mas de facto é necessário ser TCP

sei que as ligações UDP se dão de forma diferente já dei o UDP antes

nunca falei em UDP neste tópico

criar em TCP é que é mesmo o objectivo se é mais complicado ou não eu não sei ainda

pois, mas também não falaste de threads e no entanto se queres uma responsive application bem que os terás de usar.

e que tal de em vez de descartar o código na sua totalidade, dás uma olhada e tentas perceber pelo menos estes conceitos:

- threads

- socket timeout

- registo de cliente

com este conceitos consegues criar o teu servidor com TCP e sem usar select

basta criares uma thread por cada cliente quando recebes uma nova ligação, e teres uma área de gestão de mensagens (sincronização de threads)

e se o professor começar a reclamar que não fizeste como ele diz, dá estes argumentos:

- os métodos apresentados no enunciado são aconselhados e não obrigatórios:

no trabalho também são dados alguns conselhos que são os seguintes:

- o método select é considerado um dos métodos mais lentos de fazer o que pretendes :

http://beej.us/guide/bgnet/output/html/singlepage/bgnet.html#select

This being said, in modern times select(), though very portable, is one of the slowest methods for monitoring sockets. One possible alternative is libevent, or something similar, that encapsulates all the system-dependent stuff involved with getting socket notifications.

- (se o código final estiver bem feito) o servidor funciona e só por si, a aplicação de outros métodos revela conhecimentos aplicados dentro dos parâmetros delineados no enunciado


IRC : sim, é algo que ainda existe >> #p@p

Share this post


Link to post
Share on other sites
msmsms

é dito que posso utilizar ou nao o select

penso que as ferramentas são tantas que eu perco-me por estar num grau inferior ao vosso e não poder acompanhar

eu queria resolver da forma mais simples que pode existir

nem que para isso já existessem os clientes: cliente1, cliente2, cliente3 registados no servidor

ou seja já existerem lugares para os clientes, eu vou dar uma olhada no tal pdf do site que me deixaram

tem de existir uma maneira mais basica de servidor e cliente que faça essas etapas que disse

uma maneira mais bébé.

Edited by msmsms

Share this post


Link to post
Share on other sites
HappyHippyHippo

fork é para criar processos, eu falei de threads.

olha para o exemplo que te dei (acima) e vê como é simples criar threads com o pthread:

- pthread_create

- pthread_join


IRC : sim, é algo que ainda existe >> #p@p

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×
×
  • Create New...

Important Information

By using this site you accept our Terms of Use and Privacy Policy. We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.