1. Conceptos y características de UDP
UDP: Protocolo de datagramas de usuario
Protocolo de datagramas de usuario UDP: protocolo sin conexión y poco confiable. UDP no requiere conexión, por lo que realiza una transmisión de alta eficiencia.
Situaciones aplicables:
- Después de recibir datos, es difícil dar una respuesta a la red.
- para transmisión/multidifusión
- Videollamada QQ/WeChat/llamada de voz
Streaming de medios, VoIP, IPTV y otros servicios de red
2. Proceso de programación UDP
Proceso de comunicación --- proceso sin conexión (conectar aceptar)
UDP no puede determinar si el cliente ha salido: use paquetes de latidos, use el cliente y envíe contenido al servidor con regularidad.
Proceso UDP: (similar al envío de mensajes de texto)
servidor:
Crear un socket de datagrama (socket(,SOCK_DGRAM,))----->tener un teléfono móvil
Vincular información de red (bind()) -----------> Vincular IP y puerto (enviar mensajes de texto para saber a quién enviarlos)
Recibir información (recvfrom()) ---------- -- >Recibir información y obtener la IP y el puerto del remitente.
Cierre el socket (close())-------------->Recepción completada
cliente:
Crear un socket de datagrama (socket())----------------------->Tener un teléfono móvil
Especifique la información de red del servidor-------------------------------- ------- >Tener el número de la otra parte
Enviar información (sendto()) ---------------------------->Enviar mensajes de texto de acuerdo con la información de la estructura completa
Cierre el socket (close())--------------------->Enviado completado
Aviso:
1. Para TCP, el servidor debe ejecutarse primero antes de que el cliente pueda ejecutarse.
2. Para UDP, no hay orden en el que se ejecutan el servidor y el cliente, debido a que no hay conexión, no importa quién inicia primero, el servidor o el cliente.
3. Un servidor UDP puede conectarse a varios clientes al mismo tiempo. Si desea saber qué cliente está iniciando sesión, puede imprimir la IP y el número de puerto en el código del servidor.
La entrevista puede preguntar sobre lo siguiente: Si está interesado, puede probarlo usted mismo.
4. UDP, cuando el cliente usa enviar, necesita agregar conexión, esta conexión no representa la función de la conexión, pero especifica a quién está a punto de enviar datos el cliente. De esta manera no es necesario usar sendto y solo usar send.
5. En TCP, también puede usar recvfrom y sendto. Cuando lo use, escriba los dos últimos parámetros como NULL y estará bien.
3. Interfaz de funciones
(1) socket crea un socket
int socket(dominio int, tipo int, protocolo int);
Archivo de encabezado: #include <sys/types.h>
#incluir <sys/socket.h>
dominio: familia de protocolos
AF_UNIX, AF_LOCAL comunicación local
AF_INET ipv4
AF_INET6 ipv6
tipo: tipo de enchufe
SOCK_STREAM: conector de transmisión
SOCK_DGRAM: socket de datagrama
protocolo: protocolo: complete 0 para que coincida automáticamente con la capa inferior y ayude automáticamente a hacer coincidir el protocolo correspondiente según el tipo predeterminado del sistema
Iniciar sesión: IPPROTO_TCP, IPPROTO_UDP, IPPROTO_ICMP
Capa de red: htons(ETH_P_IP|ETH_P_ARP|ETH_P_ALL)
Éxito: descriptor de archivo de socket
Fallo: -1, establecer código de error
(2)bind une el zócalo
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
Archivo de encabezado: #include<sys/types.h>
#incluir<sys/socket.h>
#incluir<netinet/in.h>
#incluir<netinet/ip.h>
sockfd: descriptor de archivo de socket
addr: estructura de comunicación (siempre que sea una estructura general, debe completar la estructura correspondiente de acuerdo con el método de comunicación seleccionado; el primer parámetro del socket se determina en el momento de la comunicación y debe forzarse)
Estructura general:
estructura sockaddr {
en_familia_t en_familia;
char in_data[14];
}
Estructura de comunicación ipv4:
estructura sockaddr_in {
sa_family_t sin_family; ----Familia de protocolo
in_port_t sin_port; ----puerto
estructura in_addr sin_addr; ----estructura ip
};
estructura in_addr {
uint32_t s_addr; --dirección ip
};
addrlen: tamaño de la estructura
(3) recvfrom recibe datos
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
estructura sockaddr *src_addr, socklen_t *addrlen);
sockfd: descriptor de socket
buf: la primera dirección del área del buffer de recepción
len: el tamaño del área del buffer de recepción
banderas: 0 recibir datos y bloquear
MSG_DONTWAIT: Establecer sin bloqueo
src_addr: puntero a la estructura de información de red del remitente (el caddr de la otra parte)
addrlen: puntero al tamaño de la estructura de información de red del remitente (el caddr de la otra parte)
valor de retorno:
Éxito: número de bytes recibidos, los datos recibidos son 0:0
Fallo: -1
(4) sendto envía datos
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
const estructura sockaddr *dest_addr, socklen_t
sockfd: descriptor de socket
buf: la primera dirección del área del buffer de envío
len: el tamaño del buffer de envío
banderas: 0 enviar mensaje y bloquear
src_addr: puntero a la estructura de información de red del extremo receptor
addrlen: el tamaño de la estructura de información de red del extremo receptor
valor de retorno:
Éxito: número de bytes enviados
Fallo: -1
4. Código completo
(1) servidor:
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
#include <semaphore.h>
int main(int argc, char const *argv[])
{
char buf[128] = {0};
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0)
{
perror("sockfd err");
return -1;
}
struct sockaddr_in saddr, caddr;
saddr.sin_family = AF_INET;
saddr.sin_port = htons(atoi(argv[1]));
saddr.sin_addr.s_addr = inet_addr("0.0.0.0");
int len = sizeof(caddr);
if (bind(sockfd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0)
{
perror("bind is err");
exit(0);
}
printf("bind ok\n");
printf("等待接收客户端内容\n");
while (1)
{
int recvbyte = recvfrom(sockfd, buf, sizeof(buf), 0, (struct sockaddr *)&caddr, &len);
if (recvbyte < 0)
{
perror("bind is err");
exit(0);
}
else
{
printf("ip:%s port:%d 内容:%s\n", inet_ntoa(caddr.sin_addr), ntohs(caddr.sin_port), buf);
}
}
close(sockfd);
return 0;
}
(2) cliente:
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
#include <semaphore.h>
//ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen);
int main(int argc, char const *argv[])
{
char buf[128] = {0};
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0)
{
perror("sockfd err");
return -1;
}
struct sockaddr_in saddr;
saddr.sin_family = AF_INET;
saddr.sin_port = htons(atoi(argv[2]));
saddr.sin_addr.s_addr = inet_addr(argv[1]);
int len = sizeof(saddr);
while (1)
{
fgets(buf, sizeof(buf), stdin);
if (buf[strlen(buf) - 1] == '\n')
buf[strlen(buf) - 1] = '\0';
sendto(sockfd, buf, sizeof(buf), 0, (struct sockaddr *)&saddr, len);
}
close(sockfd);
return 0;
}