En artículos anteriores, hemos visto un servidor TCP y un servidor UDP . Pero ahora podemos combinar nuestro servidor de eco TCP simultáneo y el servidor UDP iterativo en un solo servidor que usa select para multiplexar TCP y UDP socket.
La función Seleccionar se utiliza para seleccionar entre conectores TCP y UDP. Esta función le da instrucciones al kernel para que espere a que ocurra cualquiera de los múltiples eventos y activa el proceso solo después de que ocurra uno o más eventos o pase un tiempo específico.
Ejemplo : el kernel regresará solo cuando ocurra una de estas condiciones
- Cualquier descriptor de {1, 2, 3} está listo para leer
- Cualquier Descriptor de {4, 5, 6} está listo para escribir
- Ha pasado el tiempo de 5 segundos
Todo el proceso se puede dividir en los siguientes pasos:
Servidor:
- Crear TCP, es decir, socket de escucha
- Crear un enchufe UDP
- Enlace ambos sockets a la dirección del servidor.
- Inicialice un conjunto de descriptores para seleccionar y calcule un máximo de 2 descriptores por los cuales esperaremos
- Seleccione la llamada y obtenga el descriptor listo (TCP o UDP)
- Manejar nueva conexión si el descriptor listo es de TCP O recibir datagrama si el descriptor listo es de UDP
Cliente UDP:
- Cree un conector UDP.
- Envía un mensaje al servidor.
- Espere hasta que se reciba una respuesta del servidor.
- Cierra el descriptor de socket y sal.
Cliente TCP:
- Cree un conector TCP.
- Llame a connect para establecer una conexión con el servidor.
- Cuando se acepta la conexión escribe un mensaje a un servidor.
- Lea la respuesta del servidor.
- Cierra el descriptor de socket y sal.
Funciones necesarias:
int select(int maxfd, fd_set *readsset, fd_set *writeset, fd_set *exceptset, const struct timeval *timeout); Returns: positive count of descriptors ready, 0 on timeout, -1 error
Argumentos:
- maxfd: número máximo de descriptores listos.
- timeout: cuánto tiempo esperar para que select regrese.
struct timeval{ long tv_sec; long tv_usec; }; if timeout==NULL then wait forever if timeout == fixed_amount_time then wait until specified time if timeout == 0 return immediately.
- readset: conjunto de descriptores que queremos que el kernel pruebe para leer.
- conjunto de escritura: conjunto de descriptores que queremos que el kernel pruebe para escribir.
- exceptset: conjunto de descriptores que queremos que el kernel pruebe para condiciones de excepción.
int read(int sockfd, void * buff, size_t nbytes); Returns: number of bytes read from the descriptor. -1 on error
Argumentos:
- sockfd: Descriptor que recibe los datos.
- buff: los datos del descriptor de socket del búfer de la aplicación se copian en este búfer.
- nbytes: número de bytes que se copiarán en el búfer de la aplicación.
Servidor.c
C
// Server program #include <arpa/inet.h> #include <errno.h> #include <netinet/in.h> #include <signal.h> #include <stdio.h> #include <stdlib.h> #include <strings.h> #include <sys/socket.h> #include <sys/types.h> #include <unistd.h> #define PORT 5000 #define MAXLINE 1024 int max(int x, int y) { if (x > y) return x; else return y; } int main() { int listenfd, connfd, udpfd, nready, maxfdp1; char buffer[MAXLINE]; pid_t childpid; fd_set rset; ssize_t n; socklen_t len; const int on = 1; struct sockaddr_in cliaddr, servaddr; char* message = "Hello Client"; void sig_chld(int); /* create listening TCP socket */ listenfd = socket(AF_INET, SOCK_STREAM, 0); bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl(INADDR_ANY); servaddr.sin_port = htons(PORT); // binding server addr structure to listenfd bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)); listen(listenfd, 10); /* create UDP socket */ udpfd = socket(AF_INET, SOCK_DGRAM, 0); // binding server addr structure to udp sockfd bind(udpfd, (struct sockaddr*)&servaddr, sizeof(servaddr)); // clear the descriptor set FD_ZERO(&rset); // get maxfd maxfdp1 = max(listenfd, udpfd) + 1; for (;;) { // set listenfd and udpfd in readset FD_SET(listenfd, &rset); FD_SET(udpfd, &rset); // select the ready descriptor nready = select(maxfdp1, &rset, NULL, NULL, NULL); // if tcp socket is readable then handle // it by accepting the connection if (FD_ISSET(listenfd, &rset)) { len = sizeof(cliaddr); connfd = accept(listenfd, (struct sockaddr*)&cliaddr, &len); if ((childpid = fork()) == 0) { close(listenfd); bzero(buffer, sizeof(buffer)); printf("Message From TCP client: "); read(connfd, buffer, sizeof(buffer)); puts(buffer); write(connfd, (const char*)message, sizeof(buffer)); close(connfd); exit(0); } close(connfd); } // if udp socket is readable receive the message. if (FD_ISSET(udpfd, &rset)) { len = sizeof(cliaddr); bzero(buffer, sizeof(buffer)); printf("\nMessage from UDP client: "); n = recvfrom(udpfd, buffer, sizeof(buffer), 0, (struct sockaddr*)&cliaddr, &len); puts(buffer); sendto(udpfd, (const char*)message, sizeof(buffer), 0, (struct sockaddr*)&cliaddr, sizeof(cliaddr)); } } }
Cliente_TCP.c
C
// TCP Client program #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/socket.h> #include <sys/types.h> #define PORT 5000 #define MAXLINE 1024 int main() { int sockfd; char buffer[MAXLINE]; char* message = "Hello Server"; struct sockaddr_in servaddr; int n, len; // Creating socket file descriptor if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { printf("socket creation failed"); exit(0); } memset(&servaddr, 0, sizeof(servaddr)); // Filling server information servaddr.sin_family = AF_INET; servaddr.sin_port = htons(PORT); servaddr.sin_addr.s_addr = inet_addr("127.0.0.1"); if (connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0) { printf("\n Error : Connect Failed \n"); } memset(buffer, 0, sizeof(buffer)); strcpy(buffer, "Hello Server"); write(sockfd, buffer, sizeof(buffer)); printf("Message from server: "); read(sockfd, buffer, sizeof(buffer)); puts(buffer); close(sockfd); }
UDP_cliente.c
C
// UDP client program #include <arpa/inet.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <strings.h> #include <sys/socket.h> #include <sys/types.h> #define PORT 5000 #define MAXLINE 1024 int main() { int sockfd; char buffer[MAXLINE]; char* message = "Hello Server"; struct sockaddr_in servaddr; int n, len; // Creating socket file descriptor if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { printf("socket creation failed"); exit(0); } memset(&servaddr, 0, sizeof(servaddr)); // Filling server information servaddr.sin_family = AF_INET; servaddr.sin_port = htons(PORT); servaddr.sin_addr.s_addr = inet_addr("127.0.0.1"); // send hello message to server sendto(sockfd, (const char*)message, strlen(message), 0, (const struct sockaddr*)&servaddr, sizeof(servaddr)); // receive server's response printf("Message from server: "); n = recvfrom(sockfd, (char*)buffer, MAXLINE, 0, (struct sockaddr*)&servaddr, &len); puts(buffer); close(sockfd); return 0; }
Pasos para compilar y ejecutar los códigos anteriores:
- Compile el programa del servidor (gcc server.c -o ser)
- Ejecutar servidor usando (./ser)
- En otro terminal, compile el programa cliente tcp (gcc tcp_client.c -o tcpcli)
- Ejecute el cliente tcp (./tcpcli)
- En otro terminal, compile el programa cliente udp (gcc udp_client.c -o udpcli)
- Ejecute el cliente UDP (./udpcli)
Salida de los códigos anteriores:
Publicación traducida automáticamente
Artículo escrito por Mohityadav y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA