Jump to content

LRC - Local Relay Chat


cblocks
 Share

Recommended Posts

Boas,

alguem me poderia a comentar este codigo? é que algumas coisas não percebo .. :

Cliente clients[MAX_CLIENTS_NUM];
int currentClient;
char clientToServerFifoActual[MAX_FIFO_LEN];
int nUsers;
int running;
int fdCts;

FILE* logFile;

pthread_mutex_t clientLock = PTHREAD_MUTEX_INITIALIZER;

void parser(int argc, char* argv[])
{
if (argc == 4) //mmodo background
{
	logFile = fopen (argv[3], "w+");
	int nullFd = open ("/dev/null", O_WRONLY);
	dup2 (nullFd, 1);
}
if (argc == 1) //modo foreground
{
	logFile = fopen ("/dev/null", "w+");
}
if (argc != 4 && argc != 1)
{
	printf ("usage: %s [-b] [-l logfile]\n", argv[0]);
	exit (0);
}
}

int main (int argc, char** argv)
{
parser(argc, argv);

pthread_t cThread, sCThread;
currentClient = 0;
nUsers = 0;
running = 1;

int i;
for (i = 0; i < MAXCLIENTS; i++)
{
	clients[i].nome = malloc(MAXCHAR*sizeof(char));
	clients[i].email = malloc(MAXCHAR*sizeof(char));
	clients[i].nickname = malloc(MAXCHAR*sizeof(char));
}

fprintf (logFile, "%s\n", "servidor criado."); //TODO falta hora!

// criar fifo de comandos do cliente para o servidor
if (mkfifo (clientToServerFifo, 0660) != 0)
{
	printf ("erro na criação do fifo %s\n", clientToServerFifo);
	return 1;
}

do
{
	fdCts = open (clientToServerFifo, O_RDONLY );

	if (fdCts == -1)
	{
		sleep (1);
	}
}
while (fdCts == -1);

pthread_create(&cThread, NULL, (void*)inputCmdThread, NULL);
pthread_create(&sCThread, NULL, (void*)serverControlThread, NULL);

pthread_join (sCThread, NULL);

fprintf (logFile, "servidor desligado.\n"); //TODO falta tempo!

//liberta memoria e apagar fifos
for (i = 0; i < currentClient; i++)
{
	close (clients[i].fdIn);
	close (clients[i].fdMsgIn);
	close (clients[i].fdMsgOut);
	sprintf (clientToServerFifoActual, "%s%d%s", clientToServerFifo1, clients[i].pid, clientToServerFifo2);
	unlink (clientToServerFifoActual);
}

close (fdCts);
unlink (clientToServerFifo);

for (i = 0; i < MAXCLIENTS; i++)
{
	free(clients[i].nome);
	free(clients[i].email);
	free(clients[i].nickname);
}

fclose (logFile);

return 0;
}

int readline (int fd, char* str)
{
int n;

do
{
	n = read (fd, str, 1);
}
while (n > 0 && *str++ != '\0');
return (n > 0);
}

int parse(char *line, char** info)
{
char* word;
char* retrieve = line;
int counter = 0;
int i;

for (i = 0; i < MAXARGS; i++)
{
	info[i] = "";
}

word = malloc (sizeof(char)*MAXCHAR);

if (strlen (line) == 0 || line[0] == ' ')
{
	return -1;
}

while ((word = strtok (retrieve, " ")) != NULL)
{
	retrieve = NULL;
	info[counter++] = word;
}

free (word);

return 0;
}

int choose (char* str)
{
if (strcmp (str, "/CONNECT") == 0)
{
	return CONNECT;
}

if (strcmp (str, "/CHAT") == 0)
{
	return CHAT;
}

if (strcmp (str, "/DISCONNECT") == 0)
{
	return DISCONNECT;
}

if (strcmp (str, "/WHOIS") == 0)
{
	return WHOIS;
}

if (strcmp (str, "/NICK") == 0)
{
	return NICK;
}

if (strcmp (str, "/SILENT") == 0)
{
	return SILENT;
}

if (strcmp (str, "/LEAVE") == 0)
{
	return LEAVE;
}

if (strcmp (str, "/MYSTATS") == 0)
{
	return MYSTATS;
}

if (strcmp (str, "/STATS") == 0)
{
	return STATS;
}

if (strcmp (str, "/CREATE") == 0)
{
	return CREATE;
}

if (strcmp (str, "/JOIN") == 0)
{
	return JOIN;
}

if (strcmp (str, "/MEMBERS") == 0)
{
	return MEMBERS;
}

if (strcmp (str, "/LIST") == 0)
{
	return LIST;
}

if (strcmp (str, "/RT") == 0)
{
	return RT;
}

if (strcmp (str, "/EXIT") == 0)
{
	return EXIT;
}

return -1;
}
Link to comment
Share on other sites

Quer dizer, pões aqui um código e estás à espera que alguma alma caridosa te leia o código e te faça um post de 1 página só para te explicar o que cada função faz?

Sim, custama-se dizer que quando não se percebe pergunta.se certo? Então foi o que eu fiz 😛

Link to comment
Share on other sites

O código está bastante explícito:

parser: abre-te um logfile consoante o número de argumentos que é passado no main (número de conexões do chat talvez?)

main: aloca-te um array de estruturas para os clientes, cria-te um fifo para os comandos de chat, cria-te as threads do servidor e mete-as a correr e depois de as correr (provavelmente quando escreves "/DISCONNECT") limpa tudo.

O resto é demasiado óbvio.

Umas alterações que te aconselhava:

- O array de configurações de clientes, deveria de ser dinâmico. Quando o servidor recebe uma conexão nova, deveria de alocar mais um "espaço" no array.

- Os comandos não deviam de ser case-sensitive. Podias usar regexes para validar os comandos ou implementar umas wildcards assim mais simples.

- As alocações, criações de fifos e limpezas, deveriam de estar em funções à parte, para organizar melhor o main.

Como não tens ai o código do servidor (nem do cliente) não te posso dizer mais nada, mas acho que chega para o que queres.

Link to comment
Share on other sites

- O array de configurações de clientes, deveria de ser dinâmico. Quando o servidor recebe uma conexão nova, deveria de alocar mais um "espaço" no array.

Ou então um tipo de dados decente. Se bem que para um exemplo como este o YAGNI também se aplica, mas aprender novos algoritmos é sempre útil.

- Os comandos não deviam de ser case-sensitive. Podias usar regexes para validar os comandos ou implementar umas wildcards assim mais simples.

Bem, isso é questão de gosto. Os comandos duma shell (bash, por exemplo) são case sensitive e ninguém se queixa 😛

Mas um solução mais leve e rápida que full-blown regexes é uma versão case-insensitive do strncmp: http://www.koders.com/c/fid741C3520C9BDE4E9D773E3D3E63185D649285A9C.aspx

Já agora, aqueles "free()", apesar de serem Boas Práticas ™, é inútil mesmo antes do fim do programa, que eu saiba.

❝The idea that I can be presented with a problem, set out to logically solve it with the tools at hand, and wind up with a program that could not be legally used because someone else followed the same logical steps some years ago and filed for a patent on it is horrifying.❞- John Carmack on software patents

A list  of command line apps

Link to comment
Share on other sites

Obrigadão Pessoal a serio...

já agora se não se importarem façam o mesmo para este código...

#include "client.h"

//VARIAVEIS GLOBAIS

int running;
int connected;
int fdStc;
int fdMstc;
int fdMcts;
int fd;
char info[MAX_CMD_LEN];
char serverToClientFifo[MAX_FIFO_LEN];
char msgServerToClientFifo[MAX_FIFO_LEN];
char clientToServerFifoActual[MAX_FIFO_LEN];
char nome[MAX_NAME_LEN];
char email[MAX_EMAIL_LEN];
char nickname[MAX_NICK_LEN];
pthread_t iMsgThread, iCmdThread, oThread;

pthread_mutex_t clientLock = PTHREAD_MUTEX_INITIALIZER;

WINDOW *subwin1;

void parser(int argc, char* argv[])
{
switch (argc)
{

case 1:
	wprintw(subwin1,"nome: ");
	wgetnstr(subwin1, nome, MAX_STR_LEN);

	wprintw(subwin1,"email: ");
	wgetnstr(subwin1,email, MAX_STR_LEN);

	wprintw(subwin1,"nickname: ");
	wgetnstr(subwin1,nickname, MAX_STR_LEN);
	break;

case 2:
	strncpy (nome, argv[1], strlen(argv[1]));
	wprintw(subwin1,"email: ");
	wgetnstr(subwin1,email, MAX_STR_LEN);

	wprintw(subwin1,"nickname: ");
	wgetnstr(subwin1,nickname, MAX_STR_LEN);
	break;

case 3:
	strncpy (nome, argv[1], strlen(argv[1]));
	strncpy (email, argv[2], strlen(argv[2]));

	wprintw(subwin1,"nickname: ");
	wgetnstr(subwin1,nickname, MAX_STR_LEN);
	break;

default:
	strncpy (nome, argv[1], strlen(argv[1]));
	strncpy (email, argv[2], strlen(argv[2]));
	strncpy (nickname, argv[3], strlen(argv[3]));
	break;
}
}

int main (int argc, char** argv)
{
initscr();

subwin1 = subwin(stdscr,W1_NUM_LINES,W1_NUM_COLS,W1_START_LINE,W1_START_COL);

sprintf (clientToServerFifoActual, "%s%d%s", clientToServerFifo1, getpid(), clientToServerFifo2);

connected = 0;

parser(argc, argv);

sprintf (serverToClientFifo, "%s%d", serverToClientFifoIni, getpid());
sprintf (msgServerToClientFifo, "%s%d", msgServerToClientFifoIni, getpid());

do
{
	fd = open (clientToServerFifo, O_WRONLY);

	if (fd == -1)
	{
		sleep (1);
	}
}
while (fd == -1);

//criar fifos
if (mkfifo (serverToClientFifo, 0660) != 0)
{
	wprintw(subwin1,"erro ao criar fifo\n");
	return 1;
}

if (mkfifo (msgServerToClientFifo, 0660) != 0)
{
	wprintw(subwin1,"erro ao criar fifo\n");
	return 1;
}

running = 1;
pthread_create(&oThread, NULL, (void*)outputThread, (void *)subwin1);

pthread_join (oThread, NULL);

delwin(subwin1);
refresh();
clear();
refresh();

endwin();

//apagar fifos
close (fd);
close (fdStc);
close (fdMstc);
close (fdMcts);

unlink (serverToClientFifo);
unlink (msgServerToClientFifo);

return 0;
}

int readline (int fd, char* str)
{
int n;

do
{
	n = read (fd, str, 1);
}
while (n > 0 && *str++ != '\0');
return (n > 0);
}

void *outputThread (void* arg)
{
char message[MAXCHAR];
WINDOW *subwin2;
subwin2 = subwin(stdscr, W2_NUM_LINES, W2_NUM_COLS, W2_START_LINE, W2_START_COL);

WINDOW * subwin = (WINDOW *) arg;

scrollok(subwin, 1);
wclear(subwin); wrefresh(subwin);

scrollok(subwin2,1);
wclear(subwin2); wrefresh(subwin2);

char helpMessage[] = "lista de comandos suportados:\n/CONNECT: ligar ao servidor\n/DISCONNECT: desligar do servidor\n/WHOIS nickname: informacoes sobre nickname\n/NICK nickname: alterar nickname\n/SILENT: nao receber notificacoes de entrada de utilizadores\n/LIST USERS: mostra lista de users\n/CHAT nickname: entra em modo unicast com nickname\n/LEAVE: entrar em modo broadcast\n/EXIT: sair do chat\n";

while (running)
{
	wgetnstr(subwin, message, MAX_STR_LEN);

	if (!connected) // esperar que o utilizador se ligue ao servidor
	{
		while (strcmp (message, "/CONNECT") != 0 && strcmp (message, "/HELP") != 0 && strcmp (message, "/EXIT") != 0)
		{
			wgetnstr(subwin, message, MAX_STR_LEN);
		}
	}
	if (strcmp (message, "/CONNECT") == 0)
	{
		sprintf (info, "%s %s %s %s %s %s %d", message, nome, email, nickname, serverToClientFifo, msgServerToClientFifo, getpid());
		write (fd, info, strlen(info) + 1);

		do
		{
			fdStc = open (serverToClientFifo, O_RDONLY | O_NONBLOCK);

			if (fdStc == -1)
			{
				sleep (1);
			}
		}
		while (fdStc == -1);
		do
		{
			fdMstc = open (msgServerToClientFifo, O_RDONLY | O_NONBLOCK);

			if (fdMstc == -1)
			{
				sleep (1);
			}
		}
		while (fdMstc == -1);

		do
		{
			fdMcts = open (clientToServerFifoActual, O_WRONLY | O_NONBLOCK);

			if (fdMcts == -1)
			{
				sleep (1);
			}
		}
		while (fdMcts == -1);

		connected = 1;
		pthread_create(&iMsgThread, NULL, (void*)inputMsgThread, (void *)subwin2);
		pthread_create(&iCmdThread, NULL, (void*)inputCmdThread, (void *)subwin2);

		continue;
	}

	if (strcmp (message, "/HELP") == 0)
	{
		wprintw(subwin2,"%s", helpMessage);
		wrefresh(subwin2);
		continue;
	}

	if (strncmp (message, "/CHAT", 5) == 0)
	{
		sprintf (info, "%s %d", message, getpid());
		write (fd, info, strlen(info) + 1);
		continue;
	}

	if (strncmp (message, "/WHOIS", 6) == 0)
	{
		sprintf (info, "%s %d", message, getpid());
		write (fd, info, strlen(info) + 1);
		continue;
	}

	if (strcmp (message, "/LEAVE") == 0)
	{
		sprintf (info, "%s %d", message, getpid());
		write (fd, info, strlen(info) + 1);
		continue;
	}

	if (strcmp (message, "/MYSTATS") == 0)
	{
		sprintf (info, "%s %d", message, getpid());
		write (fd, info, strlen(info) + 1);
		continue;
	}

	if (strcmp (message, "/DISCONNECT") == 0)
	{
		sprintf (info, "%s %d", message, getpid());
		write (fd, info, strlen(info) + 1);
		connected = 0;
		close (fdStc);
		close (fdMstc);
		close (fdMcts);

		continue;
	}

	if (strcmp (message, "/SILENT") == 0)
	{
		sprintf (info, "%s %d", message, getpid());
		write (fd, info, strlen(info) + 1);
		continue;
	}

	if (strcmp (message, "/STATS") == 0)
	{
		sprintf (info, "%s %d", message, getpid());
		write (fd, info, strlen(info) + 1);
		continue;
	}

	if (strncmp (message, "/NICK", 5) == 0)
	{
		sprintf (info, "%s %d", message, getpid());
		write (fd, info, strlen(info) + 1);
		continue;
	}

	if (strncmp (message, "/CREATE", 7) == 0)
	{
		sprintf (info, "%s %d", message, getpid());
		write (fd, info, strlen(info) + 1);
		continue;
	}

	if (strncmp (message, "/JOIN", 5) == 0)
	{
		sprintf (info, "%s %d", message, getpid());
		write (fd, info, strlen(info) + 1);
		continue;
	}

	if (strcmp (message, "/MEMBERS") == 0)
	{
		sprintf (info, "%s %d", message, getpid());
		write (fd, info, strlen(info) + 1);
		continue;
	}

	if (strncmp (message, "/LIST", 5) == 0)
	{
		sprintf (info, "%s %d", message, getpid());
		write (fd, info, strlen(info) + 1);
		continue;
	}

	if (strncmp (message, "/RT", 3) == 0)
	{
		sprintf (info, "%s %d", message, getpid());
		write (fd, info, strlen(info) + 1);
		continue;
	}

	if (strcmp (message, "/EXIT") == 0)
	{
		sprintf (info, "%s %d", message, getpid());
		write (fd, info, strlen(info) + 1);
		running = 0;
		break;
	}

	//se chegou aqui, é mensagem. nesse caso, enviar ao servidor
	write (fdMcts, message, strlen(message) + 1);
}
delwin(subwin2);
refresh();
pthread_exit(NULL);
}

void *inputMsgThread (void* arg)
{
char messageR[MAXCHAR];

WINDOW * subwin = (WINDOW *) arg;

while (connected)
{
	if (readline (fdMstc, messageR))
	{
		wprintw(subwin,"%s\n",messageR);
		wrefresh(subwin);
	}
}
pthread_exit(NULL);
}

void *inputCmdThread (void* arg)
{
char messageR[MAXCHAR];

WINDOW * subwin = (WINDOW *) arg;

while (connected)
{
	if (readline (fdStc, messageR))
	{
		wprintw(subwin, "%s\n", messageR);
		wrefresh(subwin);
	}
}
pthread_exit(NULL);
}

desde já obrigado..

Cumps

Link to comment
Share on other sites

mais uma vez, se seguires a lógica do primeiro, esse não vai muito além... A única diferença é que este mostra as funções de input, mas elas são bastantes explícitas. Baseia-te no que foi dito sobre a parte do servidor e tira as tuas próprias conclusões. Vais ver que não é assim tão complicado 😄

Link to comment
Share on other sites

mais uma vez, se seguires a lógica do primeiro, esse não vai muito além... A única diferença é que este mostra as funções de input, mas elas são bastantes explícitas. Baseia-te no que foi dito sobre a parte do servidor e tira as tuas próprias conclusões. Vais ver que não é assim tão complicado 😄

ok, obrigado

Link to comment
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
 Share

×
×
  • 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.