Skip to content

Instantly share code, notes, and snippets.

@daltheman
Created July 21, 2014 15:30
Show Gist options
  • Save daltheman/1e8df7d10fc0ac7183fe to your computer and use it in GitHub Desktop.
Save daltheman/1e8df7d10fc0ac7183fe to your computer and use it in GitHub Desktop.
Simple BSD Socket
//
// main.m
// simple_echo_server
//
// Created by Danilo Altheman on 14/07/14.
// Copyright (c) 2014 Quaddro (http://www.quaddro.com.br). All rights reserved.
//
/************
Must READ!!!
http://pic.dhe.ibm.com/infocenter/tpfhelp/current/index.jsp?topic=%2Fcom.ibm.ztpf-ztpfdf.doc_put.cur%2Fgtps5%2Fs5tcpcf.html
http://beej.us/guide/bgnet/output/html/singlepage/bgnet.html#closedown
*************/
#import <stdio.h> // Se você não sabe o que significa esta primeira linha, para de ler agora!
#import <unistd.h> // para usar a função close.
#import <string.h> // para usar o memset.
#import <stdlib.h> // para a função exit
#import <sys/socket.h> // para o socket
#import <sys/types.h> // contem os tipos que iremos utilizar.
#import <netinet/in.h> // header do IP
#import <arpa/inet.h> // contém as rotinas de manipulacao de end. de IP
#import <errno.h> // para gerar erros no Unix.
#import <signal.h> // para interceptar o sinal SIGINT control+c
int server_fd;
void signal_handler() {
printf("\nEncerrado pelo usuário\n");
// fecha o socket do servidor.
close(server_fd);
// Sai com sucesso!
exit(0);
}
int main(int argc, const char * argv[]) {
// Descritor de arquivo do socket
int client_fd;
// Struct que conterá inf. do socket
struct sockaddr_in server_addr, client_addr;
// Para pegar o tamanho do socket do cliente (veja explicação byte order abaixo), que não sabemos se é little ou big endian
socklen_t client_sock_len;
// Aqui falamos que o IP utilizará o TCP como transporte. Sintaxe da função: socket(familia, proto_transp, protocolo_enderecamento)
// Você pode encontrar a lista de protolocos em: /etc/protocols. Repare que o IP = 0
// Se o retorno da função for igual a zero, é porque deu certo. Qualquer número negativo, deu pau. Veja a manpage para os numeros.
if((server_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_IP)) < 0) {
perror("Socket");
exit(1);
}
// Garante que a variável que contera inform. do end. do socket estará limpa (zerada).
// Esta função serve para limpar e alocar uma variavel na memoria!
memset(&server_addr, 0 , sizeof(server_addr));
// Criando o Socket:
// Aqui definimos o tipo de protocolo de endereçamento. INET é abreviação de Internet.
server_addr.sin_family = AF_INET;
// A constante INADDR_ANY indica que iremos utilizar o IP definido na máquina. htonl = host to network long.
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
// Define a porta do socket. htons = host to network short.
// Para usar portas abaixo da 1024, você deverá executar o programa com sudo. A lista de portas pode ser encontrada em:
// /etc/services
server_addr.sin_port = htons(60080);
/*
Os computadores utilizam duas formas de armazenar dados em memória, o little endian e o big endian.
A arquitetura X86 é little endian, porém PowerPC e outras utilizam Big Endian. Para que o programa seja multiplataforma
utilizamos as funções de byte order para poder compilar em ambas as arquiteturas. Por isso utilizamos as funções
htons e htonl. Veja mais em:
http://pt.wikipedia.org/wiki/Extremidade_(ordena%C3%A7%C3%A3o)
http://support.microsoft.com/kb/102025/pt-br
*/
// A função bind dá um nome a um socket. Quando um socket é criado, ele é associado à familia de endereços, porém não possui um nome.
// bind solicita ao kernel que o endereço (IP por exemplo) seja associado ao socket.
if ((bind(server_fd, (struct sockaddr *)&server_addr, sizeof(server_addr))) == -1) {
perror("Bind");
exit(1);
}
printf("Aguardando conexões na porta: %d\n", ntohs(server_addr.sin_port));
// Listen diz para o socket começar a "ouvir" ou seja, fica aguardando por conexões. Sintaxe: listen(socket, quant_conexoes_simult)
listen(server_fd, 5);
// Fica aguardando o usuário digitar ctrl+c, e então chama a função de encerramento do programa.
signal(SIGINT, signal_handler);
// Entra em loop aguardando e gravando no socket do cliente
while (1) {
client_sock_len = sizeof(client_addr);
// aceita a conexão do cliente e associa as inf. do socket dele a uma variavel. utilizaremos ela para enviar/gravar dados.
if((client_fd = accept(server_fd, (struct sockaddr *)&client_addr, &client_sock_len)) < 0) {
perror("Accept");
}
else {
printf("Conexão recebida de: %s\n", inet_ntoa(client_addr.sin_addr));
char data[] = "Mussum ipsum cacilds, vidis litro abertis. Consetis adipiscings elitis. Pra lá , depois divoltis porris, paradis. Paisis, filhis, espiritis santis. Mé faiz elementum girarzis, nisi eros vermeio, in elementis mé pra quem é amistosis quis leo. Manduma pindureta quium dia nois paga. Sapien in monti palavris qui num significa nadis i pareci latim. Interessantiss quisso pudia ce receita de bolis, mais bolis eu num gostis.\n";
// Envia dados no socket
send(client_fd, data, sizeof(data), 0);
printf("Enviando %i bytes de dados: %s\n", (int)sizeof(data), data);
// fecha o socket do cliente.
close(client_fd);
}
// inet_ntoa = internet network to address -> IP
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment