网站首页 > 文章精选 正文
UDP简介
1. UDP是无连接的,即发送数据之前不需要建立连接
2. UDP没有拥塞控制,因此网络出现的拥塞不会使源主机的发送速率降低。
3. UDP支持一对一、一对多、多对一、多对多的交互通信。
4. UDP的首部开销小,只有8字节,比TCP的还要短。
流程
1. 创建socket
使用socket()函数创建socket套接字
2. 发送数据
使用sendto()函数向目标主机发送数据
3. 接收数据
使用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));
}
运行结果
- 上一篇: 分享一个嵌入式代码生成器编写思路!
- 下一篇: C++|整型的最值、上溢、下溢、截断、类型提升和转换
猜你喜欢
- 2025-01-05 PHP源码系列之扩展的原理与开发
- 2025-01-05 「linux」多个套接字可以绑定同一个端口吗
- 2025-01-05 基于netmap的用户态协议栈(一)
- 2025-01-05 Linux文件:超级块inode dentry file关系
- 2025-01-05 实战Netty!基于私有协议,怎样快速开发网络通信服务
- 2025-01-05 char, unsigned char,之间的相互转换
- 2025-01-05 PHP 扩展与 ZEND 引擎的整合
- 2025-01-05 C语言:位域和字节序
- 2025-01-05 Nor Flash的两种规范
- 2025-01-05 「技术干货」Ip头udp数据包ARP协议(代码实现netmap)
- 最近发表
- 标签列表
-
- newcoder (56)
- 字符串的长度是指 (45)
- drawcontours()参数说明 (60)
- unsignedshortint (59)
- postman并发请求 (47)
- python列表删除 (50)
- 左程云什么水平 (56)
- 计算机网络的拓扑结构是指() (45)
- 稳压管的稳压区是工作在什么区 (45)
- 编程题 (64)
- postgresql默认端口 (66)
- 数据库的概念模型独立于 (48)
- 产生系统死锁的原因可能是由于 (51)
- 数据库中只存放视图的 (62)
- 在vi中退出不保存的命令是 (53)
- 哪个命令可以将普通用户转换成超级用户 (49)
- noscript标签的作用 (48)
- 联合利华网申 (49)
- swagger和postman (46)
- 结构化程序设计主要强调 (53)
- 172.1 (57)
- apipostwebsocket (47)
- 唯品会后台 (61)
- 简历助手 (56)
- offshow (61)