免责声明:
本文所提供的信息和内容仅供参考。作者对本文内容的准确性、完整性、及时性或适用性不作任何明示或暗示的保证。在任何情况下,作者不对因使用本文内容而导致的任何直接或间接损失承担责任,包括但不限于数据丢失、业务中断或其他经济损失。
读者在使用本文信息时,应自行验证其准确性和适用性,并对其使用结果负责。本文内容不构成专业技术咨询或建议,具体的技术实现和应用应根据实际情况和需要进行详细分析和验证。
本文所涉及的任何商标、版权或其他知识产权均属于其各自的所有者。若本文中引用了第三方的资料或信息,引用仅为学术交流目的,不构成对第三方内容的认可或保证。
若有任何疑问或需进一步信息,请联系本文作者或相关专业人士。
前言
本期继续介绍LWIP-UDP 发送数据给目的端
一、初始化
这部分的代码无须更改,虽然很多冗余的,但方便调试,该程序的主要功能是初始化并配置一个基于 lwIP 的 UDP 客户端应用程序:
- 设置 MAC 地址:为开发板配置一个唯一的 MAC 地址。
- 初始化 lwIP 协议栈:调用
lwip_init()
初始化网络通讯。 - 添加网络接口:将网络接口添加到 lwIP 并设置为默认接口。
- 启用中断:启用网络通讯所需的系统中断。
- 配置 IP 地址:如果启用了 DHCP,程序会尝试动态获取 IP 地址;否则,使用默认的 IP 设置。
- 启动应用:调用
start_application()
启动具体的 UDP 客户端应用逻辑。
struct netif *netif;
/* the mac address of the board. this should be unique per board */
unsigned char mac_ethernet_address[] = {
0x00, 0x0a, 0x35, 0x00, 0x01, 0x02 };
netif = &server_netif;
init_platform();
xil_printf("\r\n\r\n");
xil_printf("-----lwIP RAW Mode UDP Client Application-----\r\n");
/* initialize lwIP */
lwip_init();
/* Add network interface to the netif_list, and set it as default */
if (!xemac_add(netif, NULL, NULL, NULL, mac_ethernet_address,
PLATFORM_EMAC_BASEADDR)) {
xil_printf("Error adding N/W interface\r\n");
return -1;
}
netif_set_default(netif);
/* now enable interrupts */
platform_enable_interrupts();
/* specify that the network if is up */
netif_set_up(netif);
#if (LWIP_DHCP==1)
/* Create a new DHCP client for this interface.
* Note: you must call dhcp_fine_tmr() and dhcp_coarse_tmr() at
* the predefined regular intervals after starting the client.
*/
dhcp_start(netif);
dhcp_timoutcntr = 24;
while (((netif->ip_addr.addr) == 0) && (dhcp_timoutcntr > 0))
xemacif_input(netif);
if (dhcp_timoutcntr <= 0) {
if ((netif->ip_addr.addr) == 0) {
xil_printf("ERROR: DHCP request timed out\r\n");
assign_default_ip(&(netif->ip_addr),
&(netif->netmask), &(netif->gw));
}
}
/* print IP address, netmask and gateway */
#else
assign_default_ip(&(netif->ip_addr), &(netif->netmask), &(netif->gw));
#endif
print_ip_settings(&(netif->ip_addr), &(netif->netmask), &(netif->gw));
xil_printf("\r\n");
/* print app header */
print_app_header();
二、UDP
绑定端口及IP
void start_application(void)
{
err_t err;
ip_addr_t remote_addr;
u32_t i;
err = inet_aton(UDP_SERVER_IP_ADDRESS, &remote_addr);
if (!err) {
xil_printf("Invalid Server IP address: %d\r\n", err);
return;
}
for (i = 0; i < NUM_OF_PARALLEL_CLIENTS; i++) {
/* Create Client PCB */
pcb[i] = udp_new();
if (!pcb[i]) {
xil_printf("Error in PCB creation. out of memory\r\n");
return;
}
err = udp_connect(pcb[i], &remote_addr, UDP_CONN_PORT);
if (err != ERR_OK) {
xil_printf("udp_client: Error on udp_connect: %d\r\n", err);
udp_remove(pcb[i]);
return;
}
}
/* Wait for successful connection */
usleep(10);
reset_stats();
/* initialize data buffer being sent with same as used in iperf */
for (i = 0; i < UDP_SEND_BUFSIZE; i++)
send_buf[i] = (i % 10) + '0';
}
udp_connect();绑定远端的IP(UDP_SERVER_IP_ADDRESS)及端口(UDP_CONN_PORT)
发送数据
void transfer_data(void)
{
int i = 0;
for (i = 0; i < NUM_OF_PARALLEL_CLIENTS; i++) {
if (pcb[i] == NULL)
return;
}
if (END_TIME || REPORT_INTERVAL_TIME) {
u64_t now = get_time_ms();
if (REPORT_INTERVAL_TIME) {
if (client.i_report.start_time) {
u64_t diff_ms = now - client.i_report.start_time;
if (diff_ms >= REPORT_INTERVAL_TIME) {
udp_conn_report(diff_ms, INTER_REPORT);
client.i_report.start_time = 0;
client.i_report.total_bytes = 0;
}
} else {
client.i_report.start_time = now;
}
}
if (END_TIME) {
/* this session is time-limited */
u64_t diff_ms = now - client.start_time;
if (diff_ms >= END_TIME) {
/* time specified is over,
* close the connection */
udp_packet_send(FINISH);
udp_conn_report(diff_ms, UDP_DONE_CLIENT);
xil_printf("UDP test passed Successfully\n\r");
return;
}
}
}
udp_packet_send(!FINISH);
}
transfer_data()中数据发送由udp_packet_send()负责,因此自接调用udp_packet_send()更省事。小编简化了该代码以专注于数据发送并减少代码量,去除多客户端支持、错误重试和终止逻辑,并简化包分配和发送流程。以下是一个精简版的代码示例:
static void udp_packet_send(void)
{
int *payload;
static int packet_id;
struct pbuf *packet;
/* 分配并填充数据包 */
packet = pbuf_alloc(PBUF_TRANSPORT, UDP_SEND_BUFSIZE, PBUF_POOL);
if (!packet) {
xil_printf("Error allocating pbuf\r\n");
return;
}
/* 将数据复制到数据包中 */
pbuf_take(packet, send_buf, UDP_SEND_BUFSIZE);
/* 设置包 ID */
payload = (int*)(packet->payload);
payload[0] = htonl(packet_id);
/* 发送数据包 */
udp_send(pcb[0], packet);
/* 释放 pbuf 资源 */
pbuf_free(packet);
/* 包 ID 自增 */
packet_id++;
}
使用方法
udp_packet_send 执行完一次后,更新send_buf,然后再执行udp_packet_send,一直循环这个过程即可
总结
以上就是本期讲解的全部内容。官方案例程序虽然繁琐,但便于调试。初始化过程无需修改程序,启用 DHCP 后会自动分配可用 IP,用户只需配置目标 IP 和端口号,然后将待发送的数据移动到 send_buf
即可。