Red informática | Implementación de código del modelo C/S basado en UDP

inserte la descripción de la imagen aquí

Bienvenido a seguir al bloguero Mindtechnist o unirse a [ Linux C/C++/Python Community ] para aprender y compartir Linux, C, C++, Python, Matlab, control de movimiento de robots, colaboración de varios robots, algoritmo de optimización inteligente, estimación de filtros, sensores múltiples fusión de información, conocimiento y tecnología en aprendizaje automático, inteligencia artificial y otros campos relacionados.


Realización del código del modelo C/S basado en UDP


Columna: "Programación de red"


servidor UDP

Hay dos modelos de protocolo principales utilizados en la capa de transporte, uno es el protocolo TCP y el otro es el protocolo UDP. El protocolo TCP juega un papel dominante en la comunicación de red, y la gran mayoría de las comunicaciones de red utilizan el protocolo TCP para completar la transmisión de datos. Pero UDP también es un medio de comunicación indispensable en la comunicación de red.
En comparación con TCP, la forma de comunicación UDP se parece más al envío de mensajes de texto. No es necesario establecer y mantener una conexión antes de la transmisión de datos. Solo enfócate en obtener los datos. Se omite el proceso de apretón de manos de tres vías y la velocidad de comunicación se puede mejorar considerablemente, pero no se puede garantizar la estabilidad y precisión de la comunicación que lo acompaña. Por lo tanto, llamamos UDP "entrega de mensajes no confiables sin conexión".
Entonces, en comparación con el conocido TCP, ¿cuáles son las ventajas y desventajas de UDP? Dado que no es necesario crear una conexión, la sobrecarga de UDP es pequeña, la velocidad de transmisión de datos es rápida y el rendimiento en tiempo real es sólido. Se utiliza principalmente en ocasiones de comunicación que requieren un alto rendimiento en tiempo real, como videoconferencias, teleconferencias, etc. Pero también va acompañado de una transmisión de datos poco fiable, y la precisión, la secuencia de transmisión y el flujo de datos transmitidos no se pueden controlar ni garantizar. Por lo tanto, en circunstancias normales, el protocolo UDP se usa para la transmisión de datos.Para garantizar la exactitud de los datos, necesitamos agregar un protocolo de verificación auxiliar en la capa de aplicación para compensar las deficiencias de UDP, a fin de lograr el propósito de la transmisión confiable de datos.
Al igual que TCP, UDP también puede experimentar pérdida de paquetes al recibir datos después de que se llene el búfer. Debido a que no tiene un mecanismo de ventana deslizante de TCP, generalmente se usan los siguientes dos métodos para resolverlo:
1) La capa de aplicación del servidor diseña el control de flujo para controlar la velocidad de envío de datos.
2) Utilice la función setsockopt para cambiar el tamaño del búfer de recepción. como:

#include <sys/socket.h>
int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen);
	int n = 220x1024
	setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &n, sizeof(n));

Modelo C/S

Modelo de procesamiento UDP

Dado que UDP no necesita mantener conexiones, la lógica del programa es mucho más simple, pero el protocolo UDP no es confiable y el mecanismo para garantizar la confiabilidad de la comunicación debe implementarse en la capa de aplicación.
Compile y ejecute el servidor, y abra un cliente en cada una de las dos terminales para interactuar con el servidor y ver si el servidor tiene la capacidad de servir simultáneamente. Use Ctrl+C para cerrar el servidor y luego ejecútelo para ver si el cliente aún puede comunicarse con el servidor. Comparado con los resultados de ejecución del programa TCP, comprenda el significado de no conexión.

servidor

#include <string.h>
#include <netinet/in.h>
#include <stdio.h>
#include <unistd.h>
#include <strings.h>
#include <arpa/inet.h>
#include <ctype.h>

#define MAXLINE 80
#define SERV_PORT 6666

int main(void)
{
    
    
	struct sockaddr_in servaddr, cliaddr;
	socklen_t cliaddr_len;
	int sockfd;
	char buf[MAXLINE];
	char str[INET_ADDRSTRLEN];
	int i, n;

	sockfd = socket(AF_INET, SOCK_DGRAM, 0);

	bzero(&servaddr, sizeof(servaddr));
	servaddr.sin_family = AF_INET;
	servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
	servaddr.sin_port = htons(SERV_PORT);

	bind(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
	printf("Accepting connections ...\n");

	while (1) {
    
    
		cliaddr_len = sizeof(cliaddr);
		n = recvfrom(sockfd, buf, MAXLINE,0, (struct sockaddr *)&cliaddr, &cliaddr_len);
		if (n == -1)
			perror("recvfrom error");
		printf("received from %s at PORT %d\n", 
				inet_ntop(AF_INET, &cliaddr.sin_addr, str, sizeof(str)),
				ntohs(cliaddr.sin_port));
		for (i = 0; i < n; i++)
			buf[i] = toupper(buf[i]);

		n = sendto(sockfd, buf, n, 0, (struct sockaddr *)&cliaddr, sizeof(cliaddr));
		if (n == -1)
			perror("sendto error");
	}
	close(sockfd);
	return 0;
}

cliente

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <strings.h>
#include <ctype.h>

#define MAXLINE 80
#define SERV_PORT 6666

int main(int argc, char *argv[])
{
    
    
	struct sockaddr_in servaddr;
	int sockfd, n;
	char buf[MAXLINE];

	sockfd = socket(AF_INET, SOCK_DGRAM, 0);

	bzero(&servaddr, sizeof(servaddr));
	servaddr.sin_family = AF_INET;
	inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr);
	servaddr.sin_port = htons(SERV_PORT);

	while (fgets(buf, MAXLINE, stdin) != NULL) {
    
    
		n = sendto(sockfd, buf, strlen(buf), 0, (struct sockaddr *)&servaddr, sizeof(servaddr));
		if (n == -1)
			perror("sendto error");
		n = recvfrom(sockfd, buf, MAXLINE, 0, NULL, 0);
		if (n == -1)
			perror("recvfrom error");
		write(STDOUT_FILENO, buf, n);
	}
	close(sockfd);
	return 0;
}

multidifusión (multidifusión)

Los grupos de multidifusión pueden ser permanentes o temporales. Algunas de las direcciones de grupos de multidifusión se asignan oficialmente y se denominan grupos de multidifusión permanentes. Lo que permanece sin cambios en un grupo de multidifusión permanente es su dirección IP, y la composición de los miembros del grupo puede cambiar. El número de miembros en un grupo de multidifusión permanente puede ser arbitrario, incluso cero. Aquellas direcciones ip multicast que no están reservadas para grupos multicast permanentes pueden ser utilizadas por grupos multicast temporales.

224.0.0.0~224.0.0.255 son direcciones de multidifusión reservadas (direcciones de grupo permanente), la dirección 224.0.0.0 está reservada y no asignada, y los protocolos de enrutamiento utilizan otras direcciones; 224.0.1.0~224.0.1.255 son direcciones de multidifusión públicas,
que puede ser Para uso en Internet, se requiere una aplicación para su uso.
224.0.2.0~238.255.255.255 son direcciones de multidifusión disponibles para el usuario (direcciones de grupo temporales), que son válidas en toda la red; 239.0.0.0
~239.255.255.255 son direcciones de multidifusión de administración local, que solo son válidas dentro de un área local específica.

Puede usar el comando ip ad para ver el número de la tarjeta de red, como:

itcast$ ip ad
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state DESCONOCIDO grupo predeterminado
enlace/bucle invertido 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 host de alcance lo
valid_lft para siempre lft_preferido para siempre
inet6 ::1/128 host de alcance
valid_lft para siempre lft_preferido para siempre
2: eth0: <NO-CARRIER, BROADCAST, MULTICAST, UP> mtu 1500 qdisc pfifo_fast state DOWN group default qlen 1000
link /ether 00:0c:29:0a:c4:f4 brd ff:ff:ff:ff:ff:ff
inet6 fe80::20c:29ff:fe0a:c4f4/64 enlace de alcance
valid_lft para siempre preferido_lft para siempre

El comando if_nametoindex puede obtener el número de serie de la tarjeta de red según el nombre de la tarjeta de red.

servidor

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <net/if.h>

#define SERVER_PORT 6666
#define CLIENT_PORT 9000
#define MAXLINE 1500
#define GROUP "239.0.0.2"

int main(void)
{
    
    
	int sockfd, i ;
	struct sockaddr_in serveraddr, clientaddr;
	char buf[MAXLINE] = "itcast\n";
	char ipstr[INET_ADDRSTRLEN]; /* 16 Bytes */
	socklen_t clientlen;
	ssize_t len;
	struct ip_mreqn group;

	/* 构造用于UDP通信的套接字 */
	sockfd = socket(AF_INET, SOCK_DGRAM, 0);

	bzero(&serveraddr, sizeof(serveraddr));
	serveraddr.sin_family = AF_INET; /* IPv4 */
	serveraddr.sin_addr.s_addr = htonl(INADDR_ANY); /* 本地任意IP INADDR_ANY = 0 */
	serveraddr.sin_port = htons(SERVER_PORT);

	bind(sockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr));

	/*设置组地址*/
	inet_pton(AF_INET, GROUP, &group.imr_multiaddr);
	/*本地任意IP*/
	inet_pton(AF_INET, "0.0.0.0", &group.imr_address);
	/* eth0 --> 编号 命令:ip ad */
	group.imr_ifindex = if_nametoindex("eth0");
	setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_IF, &group, sizeof(group));

	/*构造 client 地址 IP+端口 */
	bzero(&clientaddr, sizeof(clientaddr));
	clientaddr.sin_family = AF_INET; /* IPv4 */
	inet_pton(AF_INET, GROUP, &clientaddr.sin_addr.s_addr);
	clientaddr.sin_port = htons(CLIENT_PORT);

	while (1) {
    
    
		//fgets(buf, sizeof(buf), stdin);
		sendto(sockfd, buf, strlen(buf), 0, (struct sockaddr *)&clientaddr, sizeof(clientaddr));
		sleep(1);
	}
	close(sockfd);
	return 0;
}

cliente

#include <netinet/in.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <net/if.h>

#define SERVER_PORT 6666
#define MAXLINE 4096
#define CLIENT_PORT 9000
#define GROUP "239.0.0.2"

int main(int argc, char *argv[])
{
    
    
	struct sockaddr_in serveraddr, localaddr;
	int confd;
	ssize_t len;
	char buf[MAXLINE];

	/* 定义组播结构体 */
	struct ip_mreqn group;
	confd = socket(AF_INET, SOCK_DGRAM, 0);

	//初始化本地端地址
	bzero(&localaddr, sizeof(localaddr));
	localaddr.sin_family = AF_INET;
	inet_pton(AF_INET, "0.0.0.0" , &localaddr.sin_addr.s_addr);
	localaddr.sin_port = htons(CLIENT_PORT);

	bind(confd, (struct sockaddr *)&localaddr, sizeof(localaddr));

	/*设置组地址*/
	inet_pton(AF_INET, GROUP, &group.imr_multiaddr);
	/*本地任意IP*/
	inet_pton(AF_INET, "0.0.0.0", &group.imr_address);
	/* eth0 --> 编号 命令:ip ad */
	group.imr_ifindex = if_nametoindex("eth0");
	/*设置client 加入多播组 */
	setsockopt(confd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &group, sizeof(group));

	while (1) {
    
    
		len = recvfrom(confd, buf, sizeof(buf), 0, NULL, 0);
		write(STDOUT_FILENO, buf, len);
	}
	close(confd);
	return 0;
}

inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí


Supongo que te gusta

Origin blog.csdn.net/qq_43471489/article/details/130641167
Recomendado
Clasificación