UDP简介
-
UDP是无连接的,即发送数据之前不需要建立连接
-
UDP没有拥塞控制,因此网络出现的拥塞不会使源主机的发送速率降低。
-
UDP支持一对一、一对多、多对一、多对多的交互通信。
-
UDP的首部开销小,只有8字节,比TCP的还要短。
流程
- 创建socket
使用socket()函数创建socket套接字
- 发送数据
使用sendto()函数向目标主机发送数据
- 接收数据
使用recvfrom()接收数据,如果没有接收到数据,程序会一直阻塞到这里。
socket(套接字)实质上提供了进程通信的端点,进程通信之前,双方首先必须建立各自的端点,否则是没有办法通信的,通过socket将ip地址和端口绑定之后,客户端就可以和服务器通信了。当我们访问套接字时,需要访问文件一样使用 文件描述符
int socket(int domain,int type,int product)
参数:
domain:通信域,确定通讯特性,包括地址格式
| 域 | 描述 |
| AF_INET | ipv4因特网域 |
| AF_INET6 | ipv6因特网域 |
| AF_UNIX | UNIX域 |
| AF_UNSPEC | 未指定 |
type:套接字类型
| type | 描述 |
| SOCK_DGRAM | 长度固定的,无连接的不可靠报文输出 |
| SOCK_RAW | ip协议的数据端口 |
| SOCK_SEQPACKET | 长度固定,有序,可靠面向连接报文传递 |
| SOCK_STREAM | 有序,可靠,双向的面向连接的字节流|
protocol:执行相应的传输协议,也就是诸如TCP或UDP协议等等,系统系统对每一个协议簇类型提供了一个默认的协议,我们通过把protocol设置为0来使用这个默认的值。
返回值:
成功返回套接字文件描述符。
失败返回-1.
ip地址
在socket程序设计中struct sockaddr_in(或者struct sockaddr)用于记录网络地址。
struct sockaddr_in{
short sin_family; //协议簇
unsigned short int sin_port; //端口号
struct in_addr sin_addr; //协议簇特定地址 ip地址
uunsigned char sin_zero; //0
}
typedef struct in_addr{
union{
struct{
unsigned char s_b1;
s_b2;
s_b3;
s_b4;
}S_un_b;
struct{
unsigned short s_w1;
s_w2;
}S_un_w;
unsigned long s_addr;
}S_un
}IN_ADDR
ip地址通常由数字加点(192.168.1.1)的形式表示,而在struct in_addr中的ip地址是由32位的整数来表示的,为了转换我们可以使用两个函数
int inet_aton(const char *cp, struct in_addr *inp)
char *inet_ntoa(struct in_addr in)
inet_aton是将a.b.c.d形式的ip转换为32位的ip,存储在inp指针里
inet_ntoa是将32位的ip地址转换为a.b.c.d的形式。
不同类型的CPU对变量得到字节存储顺序可能不同,有的系统可能是高位在前,低位在后,而有的系统是低位在前,高位在后,而网络传输的数据顺序一定是统一的,所以当内部字节存储顺序和网络字节序不同时,一定要进行转换。 网络序都是大端
htons把unsigned short类型从主机序转换为网络序
htonl把unsigned long类型从主机序转换为网络序
ntons把unsigned short类型从网络序转换为主机序
ntol把unsigned long类型从网络序转换为主机序
实例
#include <stdio.h>
#include <string.h>
#include "esp_system.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_event.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "esp_wifi.h"
#include "esp_netif.h"
#include "sys/socket.h"
#include "netinet/in.h"
#include <lwip/netdb.h>
static const char* TAG = "UDP";
const char *payload = "this is from esp32";
static void System_Init(void);
static void WiFi_Init(void);
static void event_handler(void *arg,esp_event_base_t event_base, int32_t event_id, void *data);
void create_udp_clent(void);
void app_main(){
System_Init();
WiFi_Init();
}
void create_udp_clent(){
char rx_buf[128];
struct sockaddr_in socket_addr;
socket_addr.sin_addr.s_addr = inet_addr("192.168.8.104");
socket_addr.sin_family = AF_INET;
socket_addr.sin_port = htons(7778);
int sock = socket(AF_INET, SOCK_DGRAM,0);
if(sock < 0){
ESP_LOGE(TAG, "Unable to create socket");
close(sock);
return;;
}
ESP_LOGI(TAG,"socket cerated");
while(1){
int err = sendto(sock, payload,strlen(payload),0, (struct sockaddr *)&socket_addr, sizeof(socket_addr));
if(err < 0){
ESP_LOGI(TAG, "sendto error");
close(sock);
break;
}
ESP_LOGI(TAG,"message send");
struct sockaddr_in source_addr;
socklen_t socklen = sizeof(source_addr);
memset(rx_buf,0,sizeof(rx_buf));
int len = recvfrom(sock,rx_buf,sizeof(rx_buf),0,(struct sockaddr*)&source_addr,&socklen);
if(len <0){
ESP_LOGE(TAG, "recvfrom failed");
close(sock);
break;
}else{
rx_buf[len] = 0;
ESP_LOGI(TAG,"recv: %s",rx_buf);
}
//vTaskDelay(500/ portTICK_PERIOD_MS);
}
vTaskDelete(NULL);
}
static void event_handler(void *arg,esp_event_base_t event_base, int32_t event_id, void *data){
if(event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START){
ESP_LOGI(TAG, "wifi start");
esp_wifi_connect();
}else if(event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED){
ESP_LOGI(TAG,"wifi event sta disconnected");
esp_wifi_connect();
}else if(event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_CONNECTED){
ESP_LOGI(TAG,"wifi event connect");
}else if(event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP){
retry_times = 0;
ip_event_got_ip_t* event = (ip_event_got_ip_t*)data;
ESP_LOGI(TAG, "got ip:" IPSTR,IP2STR(&event->ip_info.ip));
xTaskCreate(&create_udp_clent,"task1",4096,NULL,3,NULL);
}
}
static void System_Init(){
esp_err_t ret = nvs_flash_init();
if(ret == ESP_ERR_NVS_NEW_VERSION_FOUND || ret == ESP_ERR_NVS_NO_FREE_PAGES){
ESP_ERROR_CHECK(ret);
ret = nvs_flash_init();
}
ESP_ERROR_CHECK(ret);
}
static void WiFi_Init(){
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
esp_netif_create_default_wifi_sta();
esp_event_handler_instance_t esp_any_id;
esp_event_handler_instance_t esp_ip_id;
ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,ESP_EVENT_ANY_ID,&event_handler,NULL,&esp_any_id));
ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT,IP_EVENT_STA_GOT_IP,&event_handler,NULL,&esp_ip_id));
wifi_init_config_t cnf = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cnf));
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
wifi_config_t cof = {
.sta = {
.ssid = "",
.password="",
.threshold.authmode=WIFI_AUTH_WPA2_PSK
}
};
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &cof));
ESP_ERROR_CHECK(esp_wifi_start());
ESP_ERROR_CHECK(esp_event_handler_instance_unregister(WIFI_EVENT,ESP_EVENT_ANY_ID,&esp_any_id));
ESP_ERROR_CHECK(esp_event_handler_instance_unregister(IP_EVENT,IP_EVENT_STA_GOT_IP,&esp_ip_id));
}
运行结果
网络调试助手获取
了解更多 blog点bkstudy点top