Simulação de controle de fluxo usando sockets
Publicado por Perfil removido (última atualização em 10/08/2010)
[ Hits: 7.606 ]
Segue uma simulação de controle de buffer de servidor e cliente em socket, efetuando transferência de arquivo do servidor para o cliente, controlando o streaming de bytes entre as máquinas.
//CLIENT
#include<sys/socket.h>
#include<sys/types.h>
#include<netinet/in.h>
#include<unistd.h>
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
//Taxa de consumo da aplicação
#define TAXA_CONSUMO 100
//Controle de socket
int sock;
struct sockaddr_in address;
//Controle de buffer
int tamBuf = 0;
char *buffer;
//Controle de fila
int inicio = 0;
int fim = 0;
int numElem = 0;
//Nome do arquivo aberto
char arquivo[100];
/*
Inserção no buffer, baseada na estrutura de fila estática
Recebe:
- Elemento a inserir
Devolve:
- Sucesso da inserção: 0 ou -1
*/
int inserir(char elemento) {
if (numElem == tamBuf) {
return -1;
}
else {
buffer[fim] = elemento;
fim = ((fim + 1) % tamBuf);
numElem ++;
return 0;
}
}
/*
Remoção do buffer, baseada na estrutura de fila estática
Devolve:
- Item removido ou -1 quando vazia
*/
char remover() {
char aux;
if (numElem == 0) {
return -1;
}
aux = buffer[inicio];
inicio = ( (inicio + 1) % tamBuf );
numElem --;
return aux;
}
/*
Faz a conexão com o servidor;
Recebe:
-Endereço de IP ou hostname do servidor
Devolve:
-Sucesso da conexão: 0 ou 1;
*/
int conectar(char *server) {
/* Criação de socket:
- AF_INET : famÃlia de protocolos;
- SOCK_STREAM : TCP;
- 0 : IP;
*/
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) > 0) {
printf("Socket configurado\n");
}
address.sin_family = AF_INET; //AF_INET: Arpa Internet Protocols
address.sin_port = htons(15000); //htons: Host to Network Short;
//cria uma porta para conexão de número 15000
inet_pton(AF_INET,server,&address.sin_addr);
//Estabelecimento de conexão
if (connect(sock,(struct sockaddr *)&address,sizeof(address)) == 0) {
return 1;
}
return 0;
}
/*
Solicita lista de arquivos disponÃveis no servidor
e imprime-a na tela.
*/
void solicitarLista() {
char ask = 'l';
int nbytes, i;
char arquivos[2000];
send(sock, &ask, sizeof(char), 0);
recv(sock, &nbytes, sizeof(int), 0);
recv(sock, arquivos, nbytes, 0);
printf("\n\nPressione ENTER para visualizar lista de arquivos disponÃveis: ");
getchar();
for (i=0; i<nbytes; i++) {
printf("%c", arquivos[i]);
}
}
/*
Solicita um determinado arquivo e verifica se ele existe no servidor;
Recebe:
-Nome do arquivo solicitado;
Devolve:
-Resposta do servidor quanto à existência do arquivo: 0 ou 1;
*/
int solicitarArquivo(char *arquivo) {
int tam;
char c;
tam = strlen(arquivo);
printf("Arquivo solicitado no servidor...");
send(sock, arquivo, tam+1, 0);
recv(sock, &c, 1, 0);
if (c=='s') {
return 1;
}
return 0;
}
/*
Adiciona "quant" bytes contidos em "info" no buffer
da aplicação.
*/
int adicionarNoBuffer(char *info, int quant) {
int i;
for (i=0; i<quant; i++) {
inserir(*info);
info++;
}
}
/*
Consome "quant" bytes do buffer da aplicação, gravando-os
em no arquivo apontado por "file"
Devolve:
- Situação do buffer: 0 (normal), 1 (vazio) ou 2 (cheio);
*/
int consumirDoBuffer(int quant, FILE* file) {
char c;
int i, final;
final = quant;
if (quant>numElem) {
final = numElem;
}
for (i=0; i<final; i++) {
c = remover();
fwrite(&c, sizeof(char), 1, file);
}
if (numElem>=(tamBuf*0.9)) {
return 2;
}
if (numElem<=(tamBuf*0.1)) {
return 1;
}
return 0;
}
/*
Imprime tela do aplicativo e barra de porcentagem de ocupação
do buffer;
Recebe:
- Quantidade ocupada do buffer;
- Tamanho total do buffer;
*/
void imprimirBuffer(int cheio, int tamanho) {
float percentual;
int i, final;
percentual = ((float) cheio) / ((float) tamanho);
final = (int) (percentual*79);
system("clear");
printf("\n\n\
___ ___ \n\
/\\__\\ /\\ \\ \n\
___ /:/ / /::\\ \\ \n\
/\\__\\ /:/ / /:/\\:\\__\\\n\
/:/ / /:/ / ___ /:/ /:/ /\n\
/:/__/ /:/__/ /\\__\\ /:/_/:/ / \n\
/::\\ \\ \\:\\ \\ /:/ / \\:\\/:/ / \n\
/:/\\:\\ \\ \\:\\ /:/ / \\::/__/ \n\
\\/__\\:\\ \\ \\:\\/:/ / \\:\\ \\ \n\
\\:\\__\\ \\::/ / \\:\\__\\ \n\
\\/__/ \\/__/ \\/__/");
printf("\n\n\n\
____ _____ ____ _____ _ __ __ ___ _ _ ____ \n\
/ ___|_ _| _ \\| ____| / \\ | \\/ |_ _| \\ | |/ ___|\n\
\\___ \\ | | | |_) | _| / _ \\ | |\\/| || || \\| | | _ \n\
___) || | | _ <| |___ / ___ \\| | | || || |\\ | |_| |\n\
|____/ |_| |_| \\_\\_____/_/ \\_\\_| |_|___|_| \\_|\\____|\n");
printf("\n\n\nPERCENTUAL OCUPADO DO BUFFER\n");
for (i=0; i<final; i++) {
printf("#");
}
for (i=final; i<79; i++) {
printf("=");
}
printf("\n%.2f \% \n", percentual*100);
}
/*
Salva o recebimento de streaming no arquivo apontado por "file";
Recebe:
- Ponteiro para o arquivo em que deve-se escrever os bytes recebidos;
Devolve:
- Sucesso da operação: 0 ou 1;
*/
int salvarArquivo(FILE *file) {
char bytes[200], md5[33], md5client[100];
char ack = 'a';
int nbytes, statusBuf, fimArq;
FILE *md5file;
if (!file) {
return 0;
}
send(sock, &ack, sizeof(char), 0); //Envia ack
do {
recv(sock, &nbytes, sizeof(int), 0); //Tamanho do Segmento
recv(sock, bytes, nbytes, 0); //Dados do segmento
imprimirBuffer(numElem, tamBuf);
adicionarNoBuffer(bytes, nbytes);
statusBuf = consumirDoBuffer(TAXA_CONSUMO, file);
send(sock, &statusBuf, sizeof(int), 0);
recv(sock, &fimArq, sizeof(int), 0);
} while (fimArq);
while (numElem) {
consumirDoBuffer(TAXA_CONSUMO, file);
imprimirBuffer(numElem, tamBuf);
}
fclose(file);
recv(sock, md5, sizeof(char)*32, 0);
md5[32] = 0;
printf("\n\nO md5sum do arquivo no servidor é %s", md5);
sprintf(md5client, "md5sum %s > %s.md5", arquivo, arquivo);
system(md5client);
sprintf(md5client, "%s.md5", arquivo);
md5file = fopen(md5client, "r");
fread(md5client, sizeof(char), 32, md5file);
md5client[32] = 0;
printf("\nO md5sum do arquivo recebido é %s", md5client);
if (strcmp(md5, md5client)) {
printf("\n\nHouve erros na transferência...");
}
else {
printf("\n\nO arquivo foi transferido de forma consistente...");
}
getchar();
return 1;
}
/*
Rotina principal
*/
int main() {
int consumo = TAXA_CONSUMO;
char serverName[20];
FILE *file;
printf("Digite o IP ou hostname do servidor ao qual deseja de conectar: ");
gets(serverName);
if (conectar(serverName)) {
printf("Conectado ao servidor!\n");
recv(sock, &tamBuf, sizeof(int), 0); //Recebe tamanho do buffer
send(sock, &consumo, sizeof(int), 0);//Envia taxa de consumo
buffer = (char *) malloc(sizeof(char)*tamBuf);
solicitarLista();
printf("Digite um nome de arquivo para solicitar: ");
gets(arquivo);
if (solicitarArquivo(arquivo)) {
printf("\nArquivo encontrado no servidor\n");
printf("\nEscolha o nome para salvar o arquivo: ");
gets(arquivo);
salvarArquivo(fopen(arquivo, "wb"));
}
else {
printf("Arquivo não encontrado no servidor\n");
}
}
close(sock);
}
//SERVER
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<unistd.h>
#include<stdlib.h>
#include<stdio.h>
//Controle de socket
int sockServer, sockClient, addrlen;
struct sockaddr_in address;
//Controle de buffer
int FATOR_BUFFER = 0;
int tamBuf = 0;
char *buffer, *bytes;
//Controle de fila
int inicio = 0;
int fim = 0;
int numElem = 0;
//Nome do arquivo aberto
char arquivo[100];
/*
Inserção no buffer, baseada na estrutura de fila estática
Recebe:
- Elemento a inserir
Devolve:
- Sucesso da inserção: 0 ou -1
*/
int inserir(char elemento) {
if(numElem == tamBuf) {
return -1;
}
else {
buffer[fim] = elemento;
fim = ((fim + 1) % tamBuf);
numElem ++;
return 0;
}
}
/*
Remoção do buffer, baseada na estrutura de fila estática
Devolve:
- Item removido ou -1 quando vazia
*/
char remover() {
char aux;
if (numElem == 0) {
return -1;
}
aux = buffer[inicio];
inicio = ( (inicio + 1) % tamBuf );
numElem --;
return aux;
}
/*
Adiciona "quant" bytes, contidos no arquivo apontado
por "file", no buffer da aplicação.
*/
int adicionarNoBuffer(int quant, FILE* file) {
int i, lidos;
lidos = fread(bytes, sizeof(char), quant, file);
for (i=0; i<lidos; i++) {
inserir(bytes[i]);
}
return lidos;
}
/*
Consome "quant" bytes do buffer da aplicação, gravando-os
na variável global "bytes";
Devolve:
- Situação do buffer: 0 (normal), 1 (vazio) ou 2 (cheio);
*/
int consumirDoBuffer(int *quant) {
int i, final;
if (*quant>numElem) {
*quant = numElem;
}
for (i=0; i<(*quant); i++) {
bytes[i] = remover();
}
if (numElem>=(tamBuf*0.9)) {
return 2;
}
if (numElem<=(tamBuf*0.1)) {
return 1;
}
return 0;
}
/*
Configura o socket, inicia o servidor e espera
pela conexão de cliente;
Devolve:
- 0 : caso em que não houve conexão de clientes;
- 1 : caso em que o cliente efetuou a conexão;
*/
int iniciaServer() {
system("clear");
/* Criação de socket:
- AF_INET : famÃlia de protocolos;
- SOCK_STREAM : TCP;
- 0 : IP;
*/
if ((sockServer = socket(AF_INET, SOCK_STREAM, 0)) > 0) {
printf("Socket criado\n");
}
address.sin_family = AF_INET; //AF_INET: Arpa Internet Protocols
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(15000); //htons: Host to Network Short;
//cria uma porta para conexão de número 15000
//Binding: associação de uma porta a um socket
if (bind(sockServer,(struct sockaddr *)&address,sizeof(address)) == 0) {
printf("Aguardando conexão...\n");
}
//Listening: fica esperando uma conexão;
//3: número de clientes que podem esperar na fila
listen(sockServer, 3);
addrlen = sizeof(struct sockaddr_in);
//Abre mais uma porta para a conexão do cliente
sockClient = accept(sockServer,(struct sockaddr *)&address,&addrlen);
//sockCliente conecta com o cliente, enquanto sockServer espera outras conexões
if (sockClient > 0) {
return 1;
}
return 0;
}
/*
Aguarda pela solicitação de arquivo pelo cliente. Ao receber a solicitação
verifica a existência do arquivo no servidor e devolve o ponteiro para o
arquivo, se o mesmo existir, ou, NULL caso não exista;
*/
FILE* aguardarSolicitacao() {
char c = 's';
char ask, arquivos[2000];
int nbytes;
FILE *lista, *file;
recv(sockClient, &ask, sizeof(char), 0);
if (ask=='l') {
system("ls -x > lista");
lista = fopen("lista", "r");
nbytes = fread(arquivos, sizeof(char), 2000, lista);
send(sockClient, &nbytes, sizeof(int), 0);
send(sockClient, arquivos, nbytes, 0);
}
recv(sockClient, arquivo, 100, 0);
file = fopen(arquivo, "rb");
if (file) {
send(sockClient, &c, 1, 0);
return file;
}
c = 'n';
send(sockClient, &c, 1, 0);
return NULL;
}
/*
Imprime tela do aplicativo e barra de porcentagem de ocupação
do buffer;
Recebe:
- Quantidade ocupada do buffer;
- Tamanho total do buffer;
*/
void imprimirBuffer(int cheio, int tamanho) {
int i, final;
float percentual;
percentual = ((float) cheio) / ((float) tamanho);
final = (int) (percentual*79);
system("clear");
printf("\n\n\
___ ___ \n\
/\\__\\ /\\ \\ \n\
___ /:/ / /::\\ \\ \n\
/\\__\\ /:/ / /:/\\:\\__\\\n\
/:/ / /:/ / ___ /:/ /:/ /\n\
/:/__/ /:/__/ /\\__\\ /:/_/:/ / \n\
/::\\ \\ \\:\\ \\ /:/ / \\:\\/:/ / \n\
/:/\\:\\ \\ \\:\\ /:/ / \\::/__/ \n\
\\/__\\:\\ \\ \\:\\/:/ / \\:\\ \\ \n\
\\:\\__\\ \\::/ / \\:\\__\\ \n\
\\/__/ \\/__/ \\/__/");
printf("\n\n\n\
____ _____ ____ _____ _ __ __ ___ _ _ ____ \n\
/ ___|_ _| _ \\| ____| / \\ | \\/ |_ _| \\ | |/ ___|\n\
\\___ \\ | | | |_) | _| / _ \\ | |\\/| || || \\| | | _ \n\
___) || | | _ <| |___ / ___ \\| | | || || |\\ | |_| |\n\
|____/ |_| |_| \\_\\_____/_/ \\_\\_| |_|___|_| \\_|\\____|\n");
printf("\n\n\nPERCENTUAL OCUPADO DO BUFFER\n");
for (i=0; i<final; i++) {
printf("#");
}
for (i=final; i<79; i++) {
printf("=");
}
printf("\n%.2f \% \n", percentual*100);
}
/*
Envia por um streaming de bytes o arquivo apontado por "file",
efetuando o controle de fluxo através do uso do "buffer" e
das variáveis addBytes e remBytes;
*/
void enviarArquivo(FILE *file) {
char c, md5[100];
int addBytes = FATOR_BUFFER*2;
int remBytes = FATOR_BUFFER;
int statusBufClient = 0;
int statusBuf = 0;
int control = 1;
FILE *md5file;
if (!file) {
return;
}
sprintf(md5, "md5sum %s > %s.md5", arquivo, arquivo);
system(md5);
sprintf(md5, "%s.md5", arquivo);
md5file = fopen(md5, "r");
fread(md5, sizeof(char), 32, md5file);
recv(sockClient, &c, sizeof(char), 0); //Recebe confirmação de inÃcio
do {
if (!(feof(file))) {
adicionarNoBuffer(addBytes, file);
}
statusBuf = consumirDoBuffer(&remBytes);
imprimirBuffer(numElem, tamBuf);
send(sockClient, &remBytes, sizeof(int), 0);
send(sockClient, bytes, remBytes, 0);
recv(sockClient, &statusBufClient, sizeof(int), 0);
if (statusBufClient==1) {
remBytes = FATOR_BUFFER + (rand() % (FATOR_BUFFER/2)) + (FATOR_BUFFER/2);
}
if (statusBufClient==2) {
remBytes = FATOR_BUFFER - (rand() % (FATOR_BUFFER/4)) - (FATOR_BUFFER/3);
}
if (statusBuf==1) {
addBytes = remBytes*2;
}
if (statusBuf==2) {
addBytes = remBytes/2;
}
send(sockClient, &numElem, sizeof(int), 0);
} while (numElem);
send(sockClient, md5, sizeof(char)*32, 0);
return;
}
/*
Rotina principal
*/
int main() {
do {
printf("\nTamanho do buffer do servidor (em bytes) (mÃn.: 2000): ");
scanf("%d", &tamBuf);
}
while (tamBuf<2000);
int tamBufClient = tamBuf/2;
buffer = (char *) malloc(sizeof(char)*tamBuf);
if (iniciaServer()) {
printf("\nConexão estabelecida!");
send(sockClient, &tamBufClient, sizeof(int), 0); //Envia tamanho de buffer
recv(sockClient, &FATOR_BUFFER, sizeof(int), 0); // Recebe taxa de consumo do client
bytes = (char *) malloc(sizeof(char)*FATOR_BUFFER*2);
printf("\nO tamanho do buffer do servidor é: %d", tamBuf);
printf("\nO fator de buffer do cliente é: %d", FATOR_BUFFER);
enviarArquivo(aguardarSolicitacao());
}
else {
printf("\nNão foi possÃvel conectar...");
}
close(sockClient);
close(sockServer);
}
Simples servidor http com concorrência feito em C
Connect - um simples programa para atravessar proxys Socks
Nenhum comentário foi encontrado.
IA Turbina o Desktop Linux enquanto distros renovam forças
Como extrair chaves TOTP 2FA a partir de QRCODE (Google Authenticator)
Linux em 2025: Segurança prática para o usuário
Desktop Linux em alta: novos apps, distros e privacidade marcam o sábado
Atualizando o Fedora 42 para 43
Como saber se o seu e-mail já teve a senha vazada?
Como descobrir se a sua senha já foi vazada na internet?
VOL já não é mais como antes? (6)
É normal não gostar de KDE? (12)
E aí? O Warsaw já está funcionando no Debian 13? [RESOLVIDO] (15)
Secure boot, artigo interessante, nada técnico. (4)
copiar library para diretorio /usr/share/..... su com Falha na a... (1)









