Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- 1) Dada o seguinte código em C++:
- /*
- *
- * mysocket.h
- *
- */
- #include <mysocketapi.h> // Header que conterá a nossa API de sockets a ser definida logo adiante
- class Socket;
- typedef void (*TOnConnecting)(Socket *socket);
- typedef void (*TOnConnected)(Socket *socket);
- typedef void (*TOnReceiveData)(Socket *socket, const char* data, int len);
- typedef void (*TOnDisconnect)(Socket *socket);
- typedef void (*TOnError)(Socket *socket, SOCKET_ERROR errcode);
- class Socket {
- private:
- int sckt; // Handle para o socket
- bool connected;
- char *host;
- int port;
- // Eventos
- TOnConnecting OnConnecting;
- TOnConnected OnConnected;
- TOnReceiveData OnReceiveData;
- TOnDisconnect OnDisconnect;
- TOnError OnError;
- // Event handler: Redireciona cada evento recebido para seu ponteiro de método correspondente (caso esteja setado).
- void OnSocketEvent(SOCKET_EVENT event) {
- switch (event) {
- case SCKT_EVENT_CONNECTING:
- if (OnConnecting != NULL)
- (*OnConnecting)(this);
- break;
- case SCKT_EVENT_CONNECTED:
- connected = true;
- if (OnConnected != NULL)
- (*OnConnected)(this);
- break;
- case SCKT_EVENT_RECEIVEDATA:
- if (OnReceiveData != NULL) {
- int len = getreceivedlen(sckt);
- char *data = malloc(len * sizeof(char));
- getreceiveddata(sckt, data, len);
- (*OnReceiveData)(this, data, len);
- free(data);
- }
- break;
- case SCKT_EVENT_DISCONNECT:
- connected = false;
- if (OnDisconnect != NULL)
- (*OnDisconnect)(this);
- break;
- case SCKT_EVENT_ERROR:
- if (OnError != NULL) {
- int lasterror = getlasterror(sckt);
- (*OnError)(this, lasterror);
- }
- break;
- }
- }
- // Método estático usado como handle para a funçãos setsocketeventhandler.
- // Quando ocorrer um evento no socket, este método apenas redireciona o evento para o método OnSocketEvent acima.
- static void _OnSocketEvent(int sckt, SOCKET_EVENT event, void *ptr) {
- ((Socket *)ptr)->OnSocketEvent(event);
- }
- public:
- // Construtor
- Socket() {
- // Inicializa os eventos como NULL
- OnConnecting = NULL;
- OnConnected = NULL;
- OnReceiveData = NULL;
- OnDisconnect = NULL;
- OnError = NULL;
- connected = false;
- sckt = createsocket(); // Cria o socket
- if (sckt != 0) // Se ele foi criado com sucesso...
- setsocketeventhandler(sckt, (void *)this, &_OnSocketEvent); // seta o nosso event handler para ficarmos atentos de todos os eventos que ocorrerem no socket.
- }
- // Destrutor
- ~Socket() {
- closesocket(sckt); // Fecha o socket
- sckt = 0; // Seta o handle para o socket como zero para indicar que ele está fechado e que nenhuma outra operação poderá ser feita depois disso.
- }
- // Connecta a um host:port específico
- void Connect(const char* host, int port) {
- this->host = host;
- this->port = port;
- if (sckt != 0)
- connect(sckt, host, port);
- }
- // Envia dados para uma conexão previamente aberta
- void SendData(const char* data, int len) {
- if (sckt != 0)
- send(sckt, data, len);
- }
- // Fecha a conexão previamente aberta
- void Disconnect() {
- if (sckt != 0)
- disconnect(sckt);
- }
- char *GetHost() {
- return host;
- }
- int GetPort() {
- return port;
- }
- bool IsConnected() {
- return connected;
- }
- // propriedade OnConnecting
- TOnConnecting GetOnConnecting() {
- return OnConnecting;
- }
- void SetOnConnecting(TOnConnecting OnConnecting) {
- this->OnConnecting = OnConnecting;
- }
- // propriedade OnConnected
- TOnConnected GetOnConnected() {
- return OnConnected;
- }
- void SetOnConnected(TOnConnected OnConnected) {
- this->OnConnected = OnConnected;
- }
- // propriedade OnReceiveData
- TOnReceiveData GetOnReceiveData() {
- return OnReceiveData;
- }
- void SetOnReceiveData(TOnReceiveData OnReceiveData) {
- this->OnReceiveData = OnReceiveData;
- }
- // propriedade OnDisconnect
- TOnDisconnect GetOnDisconnect() {
- return OnDisconnect;
- }
- void SetOnDisconnect(TOnDisconnect OnDisconnect) {
- this->OnDisconnect = OnDisconnect;
- }
- // propriedade OnError
- TOnError GetOnError() {
- return OnError;
- }
- void SetOnError(TOnError OnError) {
- this->OnError = OnError;
- }
- }
- A classe Socket definida acima por sua vez encapsula a seguinte API destinada a comunicação assíncrona via TCP sockets:
- /*
- *
- * mysocketapi.h
- *
- */
- enum SOCKET_EVENT {
- SCKT_EVENT_CONNECTING = 0,
- SCKT_EVENT_CONNECTED = 1,
- SCKT_EVENT_RECEIVEDATA = 2,
- SCKT_EVENT_DISCONNECT = 3,
- SCKT_EVENT_ERROR = 4
- }
- enum SOCKET_ERROR {
- SCKT_ERROR_NO_ERROR = 0,
- SCKT_ERROR_CONNECT = 1,
- SCKT_ERROR_SEND = 2,
- SCKT_ERROR_DISCONNECT = 3,
- SCKT_ERROR_CLOSE = 4
- }
- typedef void (SocketEventHandler*)(int sckt, int event, void *ptr)
- /*
- *
- * Retorno: Se criado com sucesso, retorna o handle para o socket (diferente de zero). Em caso de erro retorna 0.
- *
- * Descrição: Cria um novo socket tcp e retorna seu número de identificação (handle)
- *
- */
- int createsocket();
- /*
- *
- * Parâmetros:
- *
- * socket: Handle para o socket
- * ptr: Um ponteiro para uma estrutura de dados qualquer ou NULL caso não deseje passar nenhum ponteiro. Este ponteiro será o mesmo que será passado no parâmetro ptr na chamada do callback do event handler.
- * handler: A função de callback usada para ser chamada assim que ocorrer um evento no socket.
- *
- * Descrição: Define um novo event handler para o socket
- *
- */
- void setsocketeventhandler(int socket, const void *ptr, SocketEventHandler handler);
- /*
- *
- * Parâmetros:
- *
- * socket: Handle para o socket
- *
- * Descrição:
- * Fecha o socket.
- * Se existir alguma conexão aberta no socket, ela também será fechada.
- * Qualquer event handler associado ao socket também será removido.
- * Se ocorrer um erro durante o fechamento da conexão, ele será passado como um evento SCKT_EVENT_ERROR com o código de erro SCKT_ERROR_CLOSE para o handler (caso ele tenha sido previamente definido com setsocketeventhandler).
- *
- */
- void closesocket(int socket);
- /*
- *
- * Parâmetros:
- *
- * socket: Handle para o socket
- * host: endereço do host de destino
- * port: porta do host de destino
- *
- * Descrição:
- * Abre uma conexão com o host de destino e atribui ela ao socket.
- * Se ocorrer um erro durante a conexão (por exemplo, se o host não responder ou se a conexão for encerrada por ele ativamente), ele será passado como um evento SCKT_EVENT_ERROR com o código de erro SCKT_ERROR_CONNECT para o handler (caso ele tenha sido previamente definido com setsocketeventhandler).
- *
- */
- void connect(int socket, const char* host, int port);
- /*
- *
- * Parâmetros:
- *
- * socket: Handle para o socket
- * data: buffer contendo os dados a serem enviados
- * len: quantidade de bytes contidos no buffer
- *
- * Descrição:
- * Envia uma cadeia de bytes atráves da conexão previamente aberta.
- * Se ocorrer um erro durante o envio dos dados (por exemplo, se a conexão for encerrada durante a transmissão ou se ela já estiver fechada), ele será passado como um evento SCKT_EVENT_ERROR com o código de erro SCKT_ERROR_SEND para o handler (caso ele tenha sido previamente definido com setsocketeventhandler).
- *
- */
- void send(int socket, const char* data, int len);
- /*
- *
- * Retorno: Código de erro para o último erro ocorrido no socket.
- *
- * Descrição:
- * Retorna o código referente ao último erro ocorrido no socket.
- * Usualmente essa função deverá ser chamada quando realmente ocorrer um erro no socket.
- *
- */
- SOCKET_ERROR getlasterror(int socket);
- /*
- *
- * Parâmetros:
- *
- * socket: Handle para o socket
- *
- * Descrição:
- * Encerra a conexão previamente aberta no socket.
- * Se ocorrer um erro durante o envio dos dados (por exemplo, se o socket já estava desconectado), ele será passado como um evento SCKT_EVENT_ERROR com o código de erro SCKT_ERROR_DISCONNECT para o handler (caso ele tenha sido previamente definido com setsocketeventhandler).
- *
- */
- void disconnect(int socket);
- Uma vez que as seguintes suposições sejam verdadeiras:
- 1) A API de comunicação via TCP sockets exposta acima é assíncrona, ou seja, todo o processo de comunicação ocorre em uma linha de execução separada de nosso programa.
- 2) Nunca haverá problemas de sincronização entre todo o código aqui exposto e a API assíncrona exposta acima. Entre outras palavras, isso significa que não precisaremos nos preocupar com possíveis implementações de seções críticas em nosso programa para garantir a sincronização correta do fluxo de dados.
- 3) Tudo o que foi definido anteriormente faça exatamente o que foi especificado conforme está em suas descrições.
- 4) Exista um servidor na internet rodando sob host fictício fanzackviadinhodafaquinha.com.br aberto na porta 24 no qual a cada requisição enviada que termine com o caracter de quebra de linha '\n' ele sempre retorná uma string numérica representando o comprimento da sua última requisição recebida (também terminada com '\n') sem contar com o caractere de quebra de linha. Por exemplo, se for enviado para o servidor a string "HELLO\n" ele retornará a string "5\n".
- 5) Não ocorra nenhuma falha na comunicação entre o cliente e o servidor a não ser que ela seja provocada pelo próprio cliente. Entre outras palavras, a conexão entre os dois será supostamente estável.
- Qual deverá ser a saída do programa abaixo?
- /*
- *
- * programa.cpp
- *
- */
- #include <stdio.h>
- #include <string.h>
- #include <windows.h>
- #include <mysocket.h> // Header que contém a nossa classe Socket
- char buf[65536]; // Buffer de entrada
- int pos; // Posição para o buffer de entrada
- char lastLine[256]; // Armazena a última linha lida
- char phrases[16][16] = { // Array contendo as frases associadas para cada número lido do servidor que deverá ser enviada ao servidor.
- "HELLO",
- "Oi?",
- "Td bem??",
- "Cansei, tchau!!",
- "Tchau!!!!!!!!!!!",
- ":/",
- "Vai demorar?",
- "Cade vc???",
- "Acorda!",
- ".",
- "Reponde!!!!",
- "Responde F**!",
- "Como vai?",
- "Aloooo",
- "Blz?",
- "A v** vc vai!!"
- }
- /*
- *
- * Parâmetros:
- * buf: Buffer para a entrada de dados (uma string).
- * pos: Posição do buffer no qual se iniciará a leitura (passado por referência).
- * dest: Buffer de saída contendo os dados lidos.
- *
- * Retorno: true se foi encontrado o caractere de quebra de linha durante a leitura, falso caso contrário.
- *
- * Descrição: Lê uma linha que possivelmente esteja terminada com o caractere de quebra de linha '\n'.
- *
- */
- bool ReadLine(const char* buf, int &pos, char *dest) {
- int len = strlen(buf);
- int counter = 0;
- bool foundLineBreak = false;
- for (; counter < len; counter++) {
- char c = buf[pos++];
- if (c == '\n') {
- foundLineBreak = true;
- counter++;
- break;
- }
- dest[counter] = c;
- }
- dest[counter] = '\0'; // Nunca se esquecer que strings em C ou C++ são sempre terminadas com um caractere nulo.
- return foundLineBreak;
- }
- void OnConnecting(Socket *socket) {
- printf("Conectando...");
- }
- void OnConnected(Socket *socket) {
- printf("Conectado.");
- }
- /*
- *
- * Descrição: Processa uma linha de dados atualmente lida do servidor que segundo a descrição dada deve ser sempre uma string numérica contendo o tamanho da última requisição enviada. Se o número lido estiver entre 1 e 15 (incluindo o 1 e o 15) uma nova requisição será enviada ao servidor de acordo com o número lido, caso contrário a conexão será fechada (e consequentemente o programa será encerrado).
- *
- */
- void ProcessInput(Socket *socket, char *input) {
- int number = atoi(input); // A função atoi converte uma string para um número inteiro
- if (number < 1 || number > 15) {
- socket->disconnect();
- return;
- }
- printf("Fanzack: %d", number);
- char *phrase = &phrases[number];
- printf("Eu: %s", phrase);
- strcat(phrase, "\n");
- socket.SendData(phrase, strlen(phrase));
- }
- void OnReceiveData(Socket *socket, const char* data, int len) {
- if (len <= 0)
- return;
- strcat(buf, data); // Lembrando que a funçao strcat concatena duas strings e o resultado será atribuido no primeiro parâmetro. Neste caso em particular seria o mesmo que fazer buf = buf + data (ou buf += data) em C# ou Java.
- while (true) {
- char line[256];
- if (!ReadLine(buf, pos, line)) { // Tenta ler a próxima linha, se não for encontrado o caracter de quebra de linha no buffer a partir da posição informada então salva os dados atualmente lidos e sai da sub-rotina com a esperança de que na próxima lida o caracter de quebra de linha irá aparecer.
- strcpy(lastLine, line);
- return;
- }
- strcat(lastLine, line);
- stpcpy(line, lastLine); // stpcpy realiza uma cópia de uma string para outra onde a string de destino é o primeiro parâmetro. Note que fazer isso não é o mesmo que fazer line = lastLine pois esta última copia o pointeiro de lastLine para line enquanto strcpy copia os dados de lastLine para line.
- lastLine[0] = '\0';
- memmove(buf, buf + pos, pos); // Após ler a linha, realiza um deslocamento para a direita na nossa string de forma que os dados anteriormente lidos sejam apagados dela. Nada melhor do que a função memmove para esta operação. Poderia ser usada a função memccpy ao invés de memmove aqui?
- buf[pos] = '\0';
- pos = 0;
- ProcessInput(socket, line); // Processa a linha lida.
- }
- }
- void OnDisconnect(Socket *socket) {
- printf("Desconectado.");
- }
- void OnError(Socket *socket, SOCKET_ERROR errcode) {
- switch (errcode) {
- case SCKT_ERROR_CONNECT:
- printf("Erro durante a conexão.");
- break;
- case SCKT_ERROR_SEND:
- printf("Erro durante o envio de dados.");
- break;
- case SCKT_ERROR_DISCONNECT:
- printf("Erro durante a desconexão.");
- break;
- case SCKT_ERROR_CLOSE:
- printf("Erro durante o fechamento do socket.");
- break;
- default:
- printf("Erro desconhecido.");
- }
- }
- void main() {
- buf[0] = '\0'; // Uma forma de inicializar uma string fixa como string nula é apenas setando sua primeira posição com o caracter nulo '\0'. Lembrando que nas linguagens C e C++ todas as strings são terminadas com o caractere nulo, é a forma usada por essas linguagens de delimitar a extensão de uma string.
- pos = 0;
- lastLine[0] = '\0';
- Socket socket;
- socket.SetOnConnecting(&OnConnecting);
- socket.SetOnConnected(&OnConnected);
- socket.SetOnReceiveData(&OnReceiveData);
- socket.SetOnDisconnect(&OnDisconnect);
- socket.SetOnError(&OnError);
- socket.Connect("fanzackviadinhodafaquinha.com.br", 24);
- char *data = "HELLO\n";
- printf("Eu: %s", data);
- socket.SendData(data, strlen(data));
- while(socket.IsConnected())
- Sleep(1000); // Espera 1 seguindo
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement