Programar em Socket

1. Programar em Socket

Perfil removido
removido

(usa Nenhuma)

Enviado em 15/02/2006 - 20:13h

Alguém poderia me recomendar algum tutorial de como programar em Socket no C?


  


2. Re: Programar em Socket

Diego Rodrigo Machado
bestlinux

(usa Ubuntu)

Enviado em 16/02/2006 - 09:50h

Ola,

Da uma olhada neste aqui:

http://www.mhowto.com.br/programming/programacao.html

Falow !


3. Re: Programar em Socket

Perfil removido
removido

(usa Nenhuma)

Enviado em 18/02/2006 - 09:18h

Eu só achei uma apostila fraquíssima, eu preciso de algo que me ensine a programar em Socket, pois eu realmente não sei de NADA.


4. Re: Programar em Socket

Alex Nunes
allex777

(usa Ubuntu)

Enviado em 15/05/2008 - 12:42h

Também não encontrei quase nada de sockets na internet.


5. Re: Programar em Socket

Alex Nunes
allex777

(usa Ubuntu)

Enviado em 15/05/2008 - 12:43h

Esse link ai de cima não funciona.


6. cara

João Marcos Menezes
stremer

(usa Arch Linux)

Enviado em 15/05/2008 - 12:53h

como um código fala mais que mil palavras, tenho um código aqui que implementei um robo http, ja mandei aqui no vol e ja mandei pra seção de scripts (mas não foi liberado). Ele é um robo http basico usando sockets. Com certeza da pra entender bastante coisa com ele. Sockets é até facil, bem parecido com manipulação de arquivos.
Segue abaixo o código, ele compila tanto em win qto linux:
--------------- rankvol.c -----------
/**
* rankvol.c
*
* Neste programa iremos conectar com um servidor web,
* obter o cookie e entao com este cookie obter novos
* dados do servidor.
*
* Iremos utilizar o VOL como exemplo.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>

#ifdef WIN32
#include <windows.h>
#include <winsock.h>
#include <conio.h>
#else
#include <netdb.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <termios.h>
#endif

#ifdef WIN32
#define FILE_SEPARATOR ''
#define MSG_WAITALL 0
#define CHAR_ENTER 13
#else
#define FILE_SEPARATOR '/'
#define CHAR_ENTER 10
#endif

#ifndef TCP_NODELAY
#define TCP_NODELAY 1
#endif

/* Aqui iremos declarar algumas variaveis globais */
static char servidor[] = "www.vivaolinux.com.br";
static char scriptLogin[] = "/testarLogin.php";
static char scriptHome[] = "/index.php";

/* Porta HTTP do servidor */
static int portaServidor = 80;

/* Iremos armazenar aqui o login e a senha */
char login[17];
char senha[101];

/* Vamos lidar com buffer de 1Kb (1024 bytes) e mais
um byte para o armazenamento do null */
char buffer[1025];

/* Vamos utilizar buffer de 32Kb para o pacote de subida */
#define BUF_32KB 32768
#define BUF_32KB_WORK 32767
char bufEnvio[BUF_32KB];

/* Prototipos */
int abrirConexao(char * servidorConexao, int portaConexao);
char * obterHeaderHttp(char * servidorConexao, char * cookie);
void enviarDados(int socket, char * buffer);
char * receberDados(int socket);
char * obterPagina(char * script, char * dadosForm, char * cookie);
char * obterCookie();
int efetuarLogin(char * login, char * senha, char * cookie);
long obterRanking(char * cookie);

/* Esta funcao le um caractere. Veio de uma dica na net,
mas fiz algumas modificacoes :P
Para evitar o uso de ncurses esse e o jeito de usar algo tipo o getch
No windows deveremos usar o famoso conio.he o proprio getch */
int lerCarac() {
int chLido;
#ifdef WIN32
chLido = getch();
#else
struct termios oldt, newt;
tcgetattr(STDIN_FILENO, &oldt);
newt = oldt;
newt.c_lflag &= ~( ICANON | ECHO );
tcsetattr(STDIN_FILENO, TCSANOW, &newt);
chLido = getchar();
tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
#endif
return chLido;
}

/* Entrada do programa */
main(int argc, char *argv[])
{
/* Entrada de dados */
printf("\nHTTP-Robot - Exemplo de Robo HTTP - Mostra ranking no VOL:\n\n");
printf("Entre com o login do VOL: ");

/* O fgets ja coloca um null na ultima posicao automaticamente */
/* Assim tambem evitamos buffer overflow :P */
fgets(login, 17, stdin);

/* Remover o enter, aproveitamos e colocamos um final de string */
if (login[strlen(login) - 1] == CHAR_ENTER) {
login[strlen(login)-1] = 0;
} else {
login[strlen(login)] = 0;
}

/* Agora vamos ler a senha */
printf("Entre com a senha do VOL: ");
char chLido = 0;
while (chLido != CHAR_ENTER && strlen(senha) < 101) {
chLido = lerCarac();
if (chLido > 27) {
/* Caracter lido e asterisco na tela */
putchar(42);
fflush(stdout);
senha[strlen(senha)] = chLido;
}
}

/* Forca finalizacao da string da senha */
senha[strlen(senha)] = 0;
printf("\n");

/* Precisamos obter o cookie */
char * cookie = obterCookie();
printf("Cookie de sessao obtido: [%s]\n", cookie);

/* Vamos enviar os dados do login */
if (!efetuarLogin(login, senha, cookie)) {
printf("Nao foi possivel efetuar o login.\n");
printf("Verifique se o login e senha estao corretos.\n");
exit(-1);
} else {
printf("Login efetuado com sucesso.\n");
}

/* Agora vamos obter o ranking */
long ranking = obterRanking(cookie);
if (ranking == 0) {
printf("Ranking nao localizado. \n");
printf("Verifique se o layout da home do vol foi modificado.\n");
} else {
printf("Seu ranking no VOL e: %d\n", ranking);
}

/* E nao podemos esquecer de liberar da memoria */
if (cookie != NULL) {
free(cookie);
}

/* Se chegar aqui e pq tudo deu certo */
printf("Programa finalizado com sucesso.\n");
return 0;
}

/* Rotina para obter o cookie da sessao */
char * obterCookie() {

/*
Primeiro precisamos do cookie
Vamos obte-lo chamando a index.php e pegando o Set-Cookie
*/
printf("\nAcessando home e obtendo cookie de sessao ...\n");
char * dadosHome = obterPagina(scriptHome, NULL, NULL);
char * posCookieIni = strstr(dadosHome, "Set-Cookie: ");
if (posCookieIni == NULL) {
printf("Erro ao obter o cookie. Pode ser problema de conexao.\n");
exit(-1);
}
char * posCookieFim = strstr(posCookieIni + 12, ";");
if (posCookieFim == NULL) {
printf("Erro ao obter o cookie. Pode ser problema de conexao.\n");
exit(-1);
}
char * cookie = (char *) malloc(sizeof(char) * 2048);
if (cookie == NULL) {
printf("Falta de memoria.\n");
exit(-1);
}
int tamanho = strlen(posCookieIni) - strlen(posCookieFim) - 12;
strncpy(cookie, posCookieIni + 12, tamanho);
cookie[tamanho] = 0;

/* Nao precisamos mais dos dados da home */
/* Automaticamente estaremos limpando posCookieIni e posCokieFim */
if (dadosHome != NULL) {
free(dadosHome);
}
return cookie;

}

/* Para efetuar login no VOL */
int efetuarLogin(char * login, char * senha, char * cookie) {

printf("Efetuando login no VOL ...\n");
int resLogin = 0;

/* 2Kb sao suficientes para os dados do form */
char * dadosForm = (char *) malloc(sizeof(char) * 2048);
if (dadosForm == NULL) {
printf("Falta de memoria.");
exit(-1);
}

if ((strlen(login) + strlen(senha) + 87) > BUF_32KB_WORK) {
printf("Erro de estouro de buffer.\n");
exit(-1);
}
sprintf(dadosForm, "referer=index.php&formLogin=%s&formSenha=%s",
login, senha);

/* Botoes do form */
strcat(dadosForm, "&imageField2.x=0&imageField2.y=0&Submit=Entrar\n");
char * dadosRecebidos = obterPagina(scriptLogin, dadosForm, cookie);

/* Vamos tentar identificar o login atraves de 2 informacoes:
1-O vol retorna um HTTP/1.1 302 Found para redirecionar
para a home quando o login esta ok
2-Ele retorna um Location: no header
3-Verificamos ainda o acesso negado (pagina login) */
char * tmpBufHttp = strstr(dadosRecebidos, "302 Found");
if (tmpBufHttp != NULL) {
char * tmpBufLocation = strstr(dadosRecebidos, "Location:");
if (tmpBufLocation != NULL) {
/* Se ele encontrar as 2 strings vamos considerar que houve
autenticacao com sucesso */
if ((strlen(tmpBufHttp) < strlen(dadosRecebidos))
&& (strlen(tmpBufLocation) < strlen(dadosRecebidos))) {
/* Mas antes vamos procurar por acesso restrito para verificar
se nao mudaram a regra */
char * tmpBufAcesso = strstr(dadosRecebidos, "acesso restrito");
if (tmpBufAcesso == NULL) {
resLogin = 1;
}
}
}
}

/* Vamos limpar da memoria */
if (dadosForm != NULL) {
free(dadosForm);
}
if (dadosRecebidos != NULL) {
/* Ao limpar dadosRecebidos estaremos limpando tmpBufHttp
e tmpBufLocation */
free(dadosRecebidos);
}
return resLogin;

}

/* Apos autenticado, obtem o ranking mostrado na home do VOL */
long obterRanking(char * cookie) {

/* Vamos obter a home */
printf("Obtendo ranking a partir da home ...\n");
long ranking = 0;
char * dadosHome = obterPagina(scriptHome, NULL, cookie);

char * posRank = strstr(dadosHome, "Ranking: <b>");
if (posRank != NULL) {
char * posFimRank = strstr(posRank, "</b>");
if (posFimRank != NULL) {
// Temos de tirar o ranking e o deg
int tamRank = strlen(posRank) - strlen(posFimRank) - 17;
if (tamRank > 0) {
char * tmpRank = (char *) malloc(sizeof(char) * (tamRank + 1));
if (tmpRank == NULL) {
printf("Falta de memoria.\n");
exit(-1);
}
strncpy(tmpRank, posRank + 12, tamRank);
tmpRank[tamRank] = 0;

/* Agora devemos converter para long
e depois limpar da memoria */
ranking = strtol(tmpRank, NULL, 10);
if (tmpRank != NULL) {
free(tmpRank);
}
}
}
}

/* Nao precisamos mais dos dados da home */
/* Automaticamente estaremos limpando posRank e posFimRank */
if (dadosHome != NULL) {
free(dadosHome);
}
return ranking;
}

/* Funcao para conectar no host */
int abrirConexao(char * servidorConexao, int portaConexao) {
#ifdef WIN32
WSADATA wsaData;
WORD wVersionRequested;
int err;

wVersionRequested = MAKEWORD(2, 0);
err = WSAStartup(wVersionRequested, &wsaData);
if (err != 0) {
fprintf(stderr, "Nao achou WinSock DLL.\n");
exit(-1);
}
#endif

int meuSocket;
struct sockaddr_in sockAddr;
struct hostent *hEnt;

/* Vamos obter os dados do host */
hEnt = gethostbyname(servidorConexao);
if (hEnt == NULL) {
printf("Erro ao obter os dados do host.\n");
exit(-1);
}

/* Agora vamos obter o socket */
meuSocket = socket(AF_INET, SOCK_STREAM, getprotobyname("tcp")->p_proto);
if (meuSocket == -1) {
printf("Erro ao obter socket tcp.\n");
exit(-1);
}

/* Vamos definir o TCP_NODELAY (usado para comunicacoes de ida e
volta para melhorar a performance) */
int flagTcpNoDelay = 1;
int resTcpNoDelay = setsockopt(meuSocket, IPPROTO_TCP, TCP_NODELAY,
(char *) &flagTcpNoDelay, sizeof(int));
if (resTcpNoDelay < 0) {
printf("Erro ao setar tcp_nodelay.\n");
exit(-1);
}

/* Vamos definir tambem o timeout do socket
(Voce pode precisar mudar em redes lentas) */
struct timeval tv;
int timeouts = 0;
tv.tv_sec = 3;
tv.tv_usec = 0;
if (setsockopt(meuSocket, SOL_SOCKET, SO_RCVTIMEO,
(char *) &tv, sizeof tv)) {
printf("Erro ao definir timeout.");
exit(-1);
}

/* Entao conectamos */
memcpy(&sockAddr.sin_addr, hEnt->h_addr, hEnt->h_length);
sockAddr.sin_family = AF_INET;
sockAddr.sin_port = htons(portaConexao);
if (connect(meuSocket, (struct sockaddr *) &sockAddr,
sizeof(sockAddr)) < 0) {
printf("Erro ao conectar no servidor.\n");
exit(-1);
}

/* E voltamos o socket conectado */
return meuSocket;
}

/* Esta funcao obtem um header http */
char * obterHeaderHttp(char * servidorConexao, char * cookie) {

/* Vamos usar um buffer grande (2kb nao tem perigo de estourar) */
char * headerHttp = (char *) malloc(sizeof(char) * 2048);
if (headerHttp == NULL) {
printf("Falta de memoria.\n");
exit(-1);
}
strcpy(headerHttp, "Host: ");
strcat(headerHttp, servidorConexao);
strcat(headerHttp, "\n");
strcat(headerHttp, "User-Agent: Mozilla/5.0 ");
strcat(headerHttp, "X11; U; Linux i686; en-US; rv:1.8.1.14)\n");
strcat(headerHttp, "Accept: text/xml,text/html;q=0.9,text/plain;");
strcat(headerHttp, "q=0.8,image/png,*/*;q=0.5\n");
strcat(headerHttp, "Accept-Language: en-us,en;q=0.5\n");
strcat(headerHttp, "Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7\n");
strcat(headerHttp, "Keep-Alive: 300\n");
if (cookie != NULL) {
strcat(headerHttp, "Cookie: ");
strcat(headerHttp, cookie);
strcat(headerHttp, ";\n");
}
strcat(headerHttp, "Connection: keep-alive\n");
headerHttp[strlen(headerHttp)] = 0;
return headerHttp;
}

/* Funcao para enviar dados via socket */
void enviarDados(int socket, char * buffer) {
int envio = send(socket, buffer, strlen(buffer), 0);
if (envio < 1) {
printf("Erro no envio dos dados: [%d].\n", envio);
exit(-1);
}
}

/* Funcao para receber dados via socket.
Vamos trabalhar com alocacao dinamica.
Esta funcao retorna um ponteiro para os dados recebidos
*/
char * receberDados(int socket) {
char * dados = (char *) malloc(sizeof(char) * 1025);
if (dados == NULL) {
printf("Falta de memoria.\n");
exit(-1);
}
int contBuf = 0;
while ((contBuf = recv(socket, buffer, 1024, 0)) > 0) {
/* Para mostrar que esta recebendo alguma coisa */
putchar(42);
fflush(stdout);

/* Adiciona ao buffer se possivel */
buffer[contBuf] = 0;

if (dados == NULL) {
strcpy(dados, buffer);
} else {
/* Realocamos mais 1kb */
dados = realloc(dados, strlen(dados) + 1025);
if (dados == NULL) {
printf("Erro na realocacao dinamica.\n");
exit(-1);
}
strcat(dados, buffer);
}

/* Limpar buffer */
int n = 0;
for(n = 0; n <= 1024; n++) {
buffer[n] = 0;
}
}
dados[strlen(dados)] = 0;
return dados;
}

/* Obtem os dados de uma pagina html */
char * obterPagina(char * script, char * dadosForm, char * cookie) {

int meuSocket;
printf("Conectando: (%s) ... \n", servidor);
meuSocket = abrirConexao(servidor, portaServidor);
if (meuSocket == -1) {
printf("Erro ao conectar no servidor.\n");
exit(-1);
}

/* Vamos obter o header */
char * headerHttp = obterHeaderHttp(servidor, cookie);

/* Vamos gerar o post de envio */
if (dadosForm == NULL) {
sprintf(bufEnvio, "GET %s HTTP/1.1\n", script);
} else {
sprintf(bufEnvio, "POST %s HTTP/1.1\n", script);
}
if ((strlen(bufEnvio) + strlen(headerHttp)) > BUF_32KB_WORK) {
printf("Erro de estouro de buffer.\n");
exit(-1);
}
strcat(bufEnvio, headerHttp);

/* Vamos limpar da memoria */
if (headerHttp != NULL) {
free(headerHttp);
}

/* Temos de adicionar algumas informacoes para mandar o form */
if (dadosForm != NULL) {
if ((strlen(bufEnvio) + 64) > BUF_32KB_WORK) {
printf("Erro de estouro de buffer.\n");
exit(-1);
}
strcat(bufEnvio, "Content-Type: application/x-www-form-urlencoded\n");

strcat(bufEnvio, "Content-Length: ");
char * tmpBuf = (char *) malloc(sizeof(char) * 1024);
if (tmpBuf == NULL) {
printf("Falta de memoria.\n");
exit(-1);
}
sprintf(tmpBuf, "%d", strlen(dadosForm));
if ((strlen(bufEnvio) + strlen(tmpBuf) + 2) > BUF_32KB_WORK) {
printf("Erro de estouro de buffer.\n");
exit(-1);
}
strcat(bufEnvio, tmpBuf);
strcat(bufEnvio, "\n");
if (tmpBuf != NULL) {
free(tmpBuf);
}
}
strcat(bufEnvio, "\n");

/* Armazena os dados do form */
if (dadosForm != NULL) {
if ((strlen(bufEnvio) + strlen(dadosForm)) > BUF_32KB_WORK) {
printf("Erro de estouro de buffer.\n");
exit(-1);
}
strcat(bufEnvio, dadosForm);
}

/* Envia os dados */
enviarDados(meuSocket, bufEnvio);
printf("Dados foram enviados, recebendo dados ...\n");
char * dadosRecebidos = receberDados(meuSocket);
#ifdef WIN32
closesocket(meuSocket);
WSACleanup();
#else
close(meuSocket);
#endif
printf("\n");

return dadosRecebidos;
}




7. Duvida

Alex Nunes
allex777

(usa Ubuntu)

Enviado em 15/05/2008 - 13:13h

Como faço para enviar uma aplicação (arquivo) do cliente para o servidor com sockets.
Por exemplo:
A comnicação do cliente/servidor já esta estabelecida, blz. Tenho que enviar uma mensagem para o servidor. Por exemplo a palavra CASA, mas ela estará criptografada dai o servidor recebe esta palavra "criptografada" e descriptografa mesma e quarda num arquivo. Tenho este script da criptografia pronto, mas não sei como faço acontecer em conjunto com sockets.



8. protocolo

João Marcos Menezes
stremer

(usa Arch Linux)

Enviado em 15/05/2008 - 15:30h

cara, para transmitir alguma coisa que não seja uma "conversa de dados", é necessário definir um protocolo ou utilizar algum pronto, por ex. o http.
Você pode definir seu protocolo, por exemplo você manda uma identificação do arquivo, de alguma coisa da criptografia que esta sendo usada e o tamanho de bytes dos dados, depois da 2 enters por exemplo e manda o arquivo. O cara do outro lado precisa ler este cabeçalho para saber a quantidade de dados que terá de ler do outro lado para depois abrir a criptografia e gravar o arquivo.
Você pode dar uma modificada no http ou ftp tbem, procure no google sobre eles e sobre protocolos e leia mais a respeito.

abs


9. ah

João Marcos Menezes
stremer

(usa Arch Linux)

Enviado em 15/05/2008 - 15:33h

uma dica.
Eu gosto de usar uuencode pois ai trafego somente "texto" ao inves de bytes que podem confundir o cliente por algum motivo. Para isto deve ser feito o encode do binário original do arquivo, este ainda pode antes ser compactado, depois transmitido, feito o uudecode e depois descompactado. No header, no maximo o nome do arquivo e tamanho de bytes já são suficientes. O e-mail utiliza uuencode e/ou base 64 geralmente já que muito cliente de e-mail é "modo texto".


10. Duvida cruel!

Alex Nunes
allex777

(usa Ubuntu)

Enviado em 19/05/2008 - 12:12h

Tenho os arquivos do cliente e servidor que estou usando. Posso te mandar para vc me dar umas dicas.


11. cliente.c

Alex Nunes
allex777

(usa Ubuntu)

Enviado em 19/05/2008 - 12:14h

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdlib.h>
#include <string.h>

main(int argc, char *argv[])

{ int sockdescr;
int numbytesrecv;
struct sockaddr_in sa;
struct hostent *hp;
char buf[BUFSIZ+1];
char *host;
char *dados;

if(argc != 4) {
puts("Uso correto: <cliente> <nome-servidor> <porta> <dados>");
exit(1);
}

host = argv[1];
dados = argv[3];

if((hp = gethostbyname(host)) == NULL){
puts("Nao consegui obter endereco IP do servidor.");
exit(1);
}

bcopy((char *)hp->h_addr, (char *)&sa.sin_addr, hp->h_length);
sa.sin_family = hp->h_addrtype;

sa.sin_port = htons(atoi(argv[2]));

if((sockdescr=socket(hp->h_addrtype, SOCK_STREAM, 0)) < 0) {
puts("Nao consegui abrir o socket.");
exit(1);
}

printf("numero de bytes %d\n", sizeof sa);
if(connect(sockdescr, (struct sockaddr *) &sa, sizeof sa) < 0) {
puts("Nao consegui conectar ao servidor");
exit(1);
}

if(write(sockdescr, dados, strlen(dados)) != strlen(dados)){
puts("Nao consegui mandar os dados");
exit(1);
}

read(sockdescr, buf, BUFSIZ);
printf("Sou o cliente, recebi: %s\n", buf);

close(sockdescr);
exit(0);
}


12. servidor.c

Alex Nunes
allex777

(usa Ubuntu)

Enviado em 19/05/2008 - 12:15h

Código retirado por não estar 100%.






Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts