Continuando nossa odisseia, já enfrentamos um ciclope entendendo STREAMS, ou seja, comunicação TCP ficou faltando RAW_SOCK, famoso raw sockets, DGRAM - UDP. Mesmo tendo 3 exemplos eu quero passar mais alguns problemas, bora fazer um servidor tipo QuestBook, que é um cliente que entra, deixa uma mensagem e se o cliente quiser sair ele digita "exit".
O nosso servidor vai poder ter no máximo 5 conexões ao mesmo tempo, para tal feito vamos usar fork, veja:
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "unistd.h"
#include "errno.h"
#include "sys/socket.h"
#include "sys/types.h"
#include "arpa/inet.h"
#include "netdb.h"
#include "netinet/in.h"
#include "sys/wait.h"
#define PORTA 6666
#define ERRO -1
#define TAMMAX 250 //tamanho maximo da string
int main () {
struct sockaddr_in network,local;
int sock,
newSock,
resp,
strucsize,pros;
char msgbuffer [TAMMAX];
if(fork() == 0){
sock = socket (AF_INET, SOCK_STREAM, 0);
if (sock == ERRO) {
perror ("Socket");
exit (0);
}
bzero ((char *)&local, sizeof (local));
local.sin_family = AF_INET;
local.sin_port = htons (PORTA);
local.sin_addr.s_addr = INADDR_ANY;
strucsize = sizeof (local);
resp = bind (sock, (struct sockaddr *)&local, strucsize);
if (resp == ERRO) {
perror ("Bind");
exit (0);
}
//numero maximo de conexões agente definiu aqui
listen (sock, 5);
for(;;) {
if((newSock = accept (sock, (struct sockaddr *)&network, &strucsize))==1) {
perror("accept");
exit(1);
}
if (newSock == ERRO) {
perror ("Accept");
exit (0);
}
if(!fork()) {
printf ("Recebendo conexao de: %s\n", inet_ntoa (network.sin_addr));
//permite o cliente da uma entrada e a mostra, se a entrada for exit bula o laço "for" infinito
for (;;) {
recv (newSock, msgbuffer, TAMMAX, 0);
fprintf (stdout, "\nMensagem Recebida: %s\n", msgbuffer);
if (!strcmp (msgbuffer, "exit")) break;
}
}
}
}
}
Explicando:
Função recv - usada para receber mensagens de um socket. Sua sintaxe é:
int recv(int Meusocket, void *buf, int len, unsigned int flags);
Onde:
- Meusocket -> é o socket para ler de outro, no caso um socket local.
- buf -> aqui é o endereço da área do buffer.
- len -> é o tamanho do buffer.
- flags -> são formados por MSG_OOB e MSG_PEEK, permitindo receber dados out-of-band e permitindo espiar dados que entram, consequentemente. Esta chamada deve ser usada somente com sockets do tipo SOCK_STREAM.
- MSG_OOB -> para dados oob (out-of-band).
- MSG_WAITALL -> este argumento faz com que seja bloqueada a chegada de dados até que a requisição seja satisfeita. Flags podem ser: MSG_OOB, MSG_PEEK, MSG_WAITALL, MSG_ERRQUEUE, MSG_NOSIGNAL.
Agora o cliente para nosso servidor, papel dele é simples, ele pega a entrada do usuário, manda para o servidor e continua na conexão, enquanto não digitar "exit".
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "errno.h"
#include "sys/socket.h"
#include "sys/types.h"
#include "arpa/inet.h"
#include "netdb.h"
#include "netinet/in.h"
#include "sys/wait.h"
#define PORTA 6666
#define ERRO -1
#define TAMMAX 250 //tamanho maximo da string
main (int argc, char * * argv) {
struct sockaddr_in network;
int sock,
newSock,
resp,
strucsize;
char msg [TAMMAX];
if (argc < 2) {
printf ("Use %s <host>\n\n", argv [0]);
exit (0);
}
sock = socket (AF_INET, SOCK_STREAM, 0);
if (sock == ERRO) {
perror ("Socket");
exit (0);
}
bzero ((char *)&network, sizeof (network));
network.sin_family = AF_INET;
network.sin_port = htons (PORTA);
network.sin_addr.s_addr = inet_addr (argv [1]);
strucsize = sizeof (network);
resp = connect (sock, (struct sockaddr *)&network, strucsize);
if (resp == ERRO) {
perror ("Connect");
exit (0);
}
fprintf (stdout, "Conectado em %s\n", argv [1]);
for (;;) {
printf ("\nMensagem: ");
fgets(msg, sizeof(msg), stdin);
msg[strlen(msg)-1] = '\0';
send (sock, msg, sizeof (msg), 0);
if (!strcmp (msg, "exit"))
{
exit (0);
}
}
}
Rode o servidor num terminal e abra dois terminais. Rode:
./client ip_do_server
Mande mensagem pelos os dois e veja por si o servidor rolando no terminal em que você executou ele. As dúvidas geralmente vão com a prática, então não fique triste se não rolar, apenas não desista. Se ajudar, baixe uma música aí do Raul Seixas chamada "tente outra vez", sempre que estou desanimado escuto esta música, abro o GDB e depuro o código, leio um bom livro como Ansi C do K&R, Dragon Books, entre outros aí, entrar no IRC e conversar com alguém que tem mais experiência também ajuda.