Pular para o conteúdo

Programar em Socket

Responder tópico
O Viva o Linux depende da receita de anúncios para se manter. Ative os cookies aqui para nos patrocinar.
Não conseguimos carregar os anúncios. Se usa bloqueador, considere liberar o Viva o Linux para nos patrocinar.
  • Denunciar
  • Indicar

1. Programar em Socket

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

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

Responder tópico

O Viva o Linux depende da receita de anúncios para se manter. Ative os cookies aqui para nos patrocinar.
Não conseguimos carregar os anúncios. Se usa bloqueador, considere liberar o Viva o Linux para nos patrocinar.

3. Re: Programar em Socket

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

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

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

5. Re: Programar em Socket

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

Esse link ai de cima não funciona.

6. cara

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

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

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

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!

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

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

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

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

Responder tópico

O Viva o Linux depende da receita de anúncios para se manter. Ative os cookies aqui para nos patrocinar.
Não conseguimos carregar os anúncios. Se usa bloqueador, considere liberar o Viva o Linux para nos patrocinar.

Responder tópico

Entre na sua conta para responder.

Fazer login para responder