while((lwipdev.dhcpstatus!=2)&&(lwipdev.dhcpstatus!=0XFF))//等待DHCP获取成功/超时溢出 { lwip_periodic_handle(); }什么意思
时间: 2024-05-18 21:11:30 浏览: 147
这段代码的意思是:在lwIP网络协议栈中,等待DHCP获取成功或超时溢出。代码中的while循环会一直执行lwip_periodic_handle()函数,直到lwipdev.dhcpstatus变量的值等于2(DHCP获取成功)或0XFF(超时溢出)。在此期间,程序会不断地发送DHCP请求,直到获取到IP地址或超时。
相关问题
Linux C++ 发送DHCP报文获取DHCP信息
要发送DHCP报文获取DHCP信息,可以使用Linux下的socket编程来实现。具体步骤如下:
1. 创建socket对象,使用raw socket类型。
2. 设置socket属性,包括IP地址、端口号等。
3. 创建DHCP报文,并填充报文字段。
4. 发送DHCP报文。
5. 接收DHCP服务器的响应报文。
6. 解析响应报文,获取DHCP信息。
以下是一个简单的示例代码:
```c++
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define BUF_SIZE 1024
#define DHCP_PORT 67
#define DHCP_SERVER_PORT 68
typedef struct {
uint8_t op; // Message op code / message type.
uint8_t htype; // Hardware address type (e.g., '1' = 10mb ethernet).
uint8_t hlen; // Hardware address length (e.g., '6' for 10mb ethernet).
uint8_t hops; // Client sets to zero, optionally used by relay agents when booting via a relay agent.
uint32_t xid; // Transaction ID, a random number chosen by the client, used by the client and server to associate messages and responses between a client and a server.
uint16_t secs; // Filled in by client, seconds elapsed since client began address acquisition or renewal process.
uint16_t flags; // Broadcast flag.
struct in_addr ciaddr; // Client IP address; only filled in if client is in BOUND, RENEW or REBINDING state and can respond to ARP requests.
struct in_addr yiaddr; // 'your' (client) IP address.
struct in_addr siaddr; // IP address of next server to use in bootstrap; returned in DHCPOFFER, DHCPACK by server.
struct in_addr giaddr; // Relay agent IP address, used in booting via a relay agent.
uint8_t chaddr[16]; // Client hardware address.
char sname[64]; // Optional server host name, null terminated string.
char file[128]; // Boot file name, null terminated string; "generic" name or null in DHCPDISCOVER, fully qualified directory-path name in DHCPOFFER.
uint32_t magic_cookie; // Fixed value: 0x63825363.
uint8_t options[308]; // Optional parameters field.
} dhcp_packet;
int main(int argc, char* argv[]) {
int sockfd;
struct sockaddr_in servaddr, cliaddr;
char buf[BUF_SIZE];
socklen_t len = sizeof(cliaddr);
dhcp_packet packet;
// 创建socket对象
sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_UDP);
if (sockfd < 0) {
perror("socket");
exit(1);
}
// 设置socket属性
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(DHCP_SERVER_PORT);
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0) {
perror("bind");
exit(1);
}
// 创建DHCP报文
memset(&packet, 0, sizeof(packet));
packet.op = 0x01; // Message type: Boot Request
packet.htype = 0x01; // Hardware type: Ethernet
packet.hlen = 0x06; // Hardware address length: 6
packet.xid = random(); // Transaction ID
packet.magic_cookie = htonl(0x63825363); // DHCP Magic Cookie
// DHCP Option 53: DHCP Discover
packet.options[0] = 0x35; // Option 53
packet.options[1] = 0x01; // Length
packet.options[2] = 0x01; // DHCP Discover
// DHCP Option 55: Parameter Request List
packet.options[3] = 0x37; // Option 55
packet.options[4] = 0x04; // Length
packet.options[5] = 0x01; // Subnet Mask
packet.options[6] = 0x03; // Router
packet.options[7] = 0x06; // Domain Name Server
packet.options[8] = 0x0f; // Domain Name
packet.options[9] = 0x2c; // Static Route
packet.options[10] = 0xff; // End
// 发送DHCP报文
memset(&cliaddr, 0, sizeof(cliaddr));
cliaddr.sin_family = AF_INET;
cliaddr.sin_port = htons(DHCP_PORT);
cliaddr.sin_addr.s_addr = inet_addr("255.255.255.255");
if (sendto(sockfd, &packet, sizeof(packet), 0, (struct sockaddr*)&cliaddr, sizeof(cliaddr)) < 0) {
perror("sendto");
exit(1);
}
// 接收DHCP服务器的响应报文
memset(buf, 0, sizeof(buf));
if (recvfrom(sockfd, buf, sizeof(buf), 0, (struct sockaddr*)&cliaddr, &len) < 0) {
perror("recvfrom");
exit(1);
}
// 解析响应报文,获取DHCP信息
// ...
close(sockfd);
return 0;
}
```
W5500 DHCP代码
以下是W5500使用DHCP获取IP地址的示例代码:
```c
#include <stdio.h>
#include <string.h>
#include "W5500.h"
#define SOCK_DHCP 6 // DHCP套接字号
#define DHCP_CHADDR_LEN 6 // 客户机(W5500)MAC地址长度
#define DHCP_SNAME_LEN 64 // 服务器名称长度
#define DHCP_FILE_LEN 128 // 引导文件名长度
// DHCP状态码
#define DHCP_STATE_INIT 0
#define DHCP_STATE_SELECTING 1
#define DHCP_STATE_REQUESTING 2
#define DHCP_STATE_BOUND 3
#define DHCP_STATE_RENEW 4
#define DHCP_STATE_REBIND 5
// DHCP消息类型
#define DHCP_DISCOVER 1
#define DHCP_OFFER 2
#define DHCP_REQUEST 3
#define DHCP_DECLINE 4
#define DHCP_ACK 5
#define DHCP_NAK 6
#define DHCP_RELEASE 7
// DHCP选项
#define DHCP_OPT_END 0
#define DHCP_OPT_SUBNET 1
#define DHCP_OPT_ROUTER 3
#define DHCP_OPT_DNS 6
#define DHCP_OPT_REQ_IP 50
#define DHCP_OPT_LEASE_TIME 51
#define DHCP_OPT_MSG_TYPE 53
#define DHCP_OPT_SERVER 54
#define DHCP_OPT_REQ_LIST 55
// DHCP服务器IP地址
#define DHCP_SERVER_IP {192, 168, 0, 1}
static uint8_t dhcp_state = DHCP_STATE_INIT;
static uint32_t dhcp_tick = 0;
static uint8_t dhcp_chaddr[DHCP_CHADDR_LEN]; // MAC地址
static uint8_t dhcp_xid[4]; // 会话ID
static uint32_t dhcp_leasetime; // 租期
static uint32_t dhcp_renewtime; // 续租时间
static uint32_t dhcp_rebindtime; // 重新绑定时间
static uint32_t dhcp_serverip; // DHCP服务器IP地址
static uint8_t dhcp_subnetmask[4]; // 子网掩码
static uint8_t dhcp_gateway[4]; // 网关
static uint8_t dhcp_dns[4]; // DNS
// 发送DHCP消息
static void dhcp_send(uint8_t msgtype)
{
uint8_t txbuf[1024];
uint8_t *p;
uint16_t len;
// 构造DHCP消息
p = txbuf;
memset(p, 0, 28);
p[0] = DHCP_BOOTREQUEST;
p[1] = DHCP_HTYPE_ETHER;
p[2] = DHCP_HLEN_ETHER;
p[3] = DHCP_HOPS;
memcpy(p + 4, dhcp_xid, 4);
p += 8;
memcpy(p, dhcp_chaddr, DHCP_CHADDR_LEN);
p += DHCP_CHADDR_LEN;
memset(p, 0, 192);
p += 192;
memcpy(p, "\x63\x82\x53\x63", 4); // Magic Cookie
p += 4;
*p++ = DHCP_OPT_MSG_TYPE;
*p++ = 1;
*p++ = msgtype;
*p++ = DHCP_OPT_REQ_IP;
*p++ = 4;
memset(p, 0, 4);
p += 4;
*p++ = DHCP_OPT_SERVER;
*p++ = 4;
memcpy(p, &dhcp_serverip, 4);
p += 4;
*p++ = DHCP_OPT_END;
// 发送DHCP消息
len = (uint16_t)(p - txbuf);
wiz_send_data(SOCK_DHCP, txbuf, len);
}
// 解析DHCP消息
static uint8_t dhcp_parse(uint8_t *rxbuf)
{
uint8_t *p;
uint8_t opt, optlen;
uint16_t len;
uint32_t lease;
// 验证会话ID和MAC地址
if (memcmp(dhcp_xid, rxbuf + 4, 4) != 0 ||
memcmp(dhcp_chaddr, rxbuf + 28, DHCP_CHADDR_LEN) != 0) {
return 0;
}
// 解析DHCP选项
p = rxbuf + 240;
while (*p != DHCP_OPT_END && p < rxbuf + 512) {
opt = *p++;
if (opt == DHCP_OPT_MSG_TYPE) { // 消息类型
optlen = *p++;
if (*p == DHCP_OFFER && dhcp_state == DHCP_STATE_SELECTING) {
dhcp_serverip = *(uint32_t *)(p + 1);
dhcp_send(DHCP_REQUEST);
dhcp_state = DHCP_STATE_REQUESTING;
} else if (*p == DHCP_ACK && dhcp_state == DHCP_STATE_REQUESTING) {
dhcp_leasetime = *(uint32_t *)(p + 1);
dhcp_tick = wiz_millis();
dhcp_state = DHCP_STATE_BOUND;
return 1;
}
} else if (opt == DHCP_OPT_SUBNET) { // 子网掩码
optlen = *p++;
memcpy(dhcp_subnetmask, p, 4);
} else if (opt == DHCP_OPT_ROUTER) { // 网关
optlen = *p++;
memcpy(dhcp_gateway, p, 4);
} else if (opt == DHCP_OPT_DNS) { // DNS
optlen = *p++;
memcpy(dhcp_dns, p, 4);
} else if (opt == DHCP_OPT_LEASE_TIME) { // 租期
optlen = *p++;
lease = *(uint32_t *)(p + 1);
dhcp_renewtime = lease / 2;
dhcp_rebindtime = lease * 7 / 8;
} else if (opt == DHCP_OPT_SERVER) { // DHCP服务器IP地址
optlen = *p++;
dhcp_serverip = *(uint32_t *)(p + 1);
} else { // 其他选项
optlen = *p++;
}
p += optlen;
}
return 0;
}
// DHCP初始化
void dhcp_init(void)
{
wiz_get_mac(dhcp_chaddr); // 获取MAC地址
dhcp_xid[0] = rand() & 0xFF;
dhcp_xid[1] = rand() & 0xFF;
dhcp_xid[2] = rand() & 0xFF;
dhcp_xid[3] = rand() & 0xFF;
dhcp_serverip = MAKE_IP_ADDR(DHCP_SERVER_IP);
}
// DHCP处理
void dhcp_process(void)
{
uint8_t rxbuf[512];
uint16_t len;
switch (dhcp_state) {
case DHCP_STATE_INIT: // 初始化
dhcp_send(DHCP_DISCOVER);
dhcp_state = DHCP_STATE_SELECTING;
break;
case DHCP_STATE_BOUND: // 已绑定
if (wiz_millis() - dhcp_tick > dhcp_renewtime * 1000) { // 续租
dhcp_send(DHCP_REQUEST);
dhcp_state = DHCP_STATE_RENEW;
}
break;
case DHCP_STATE_RENEW: // 续租
if (dhcp_parse(rxbuf)) {
dhcp_tick = wiz_millis();
dhcp_state = DHCP_STATE_BOUND;
} else if (wiz_millis() - dhcp_tick > 5000) {
dhcp_send(DHCP_REQUEST);
}
break;
case DHCP_STATE_REBIND: // 重新绑定
if (dhcp_parse(rxbuf)) {
dhcp_tick = wiz_millis();
dhcp_state = DHCP_STATE_BOUND;
} else if (wiz_millis() - dhcp_tick > 5000) {
dhcp_send(DHCP_REQUEST);
}
break;
default: // 其他状态
if (dhcp_parse(rxbuf)) {
dhcp_tick = wiz_millis();
}
break;
}
// 接收DHCP消息
len = wiz_recv_data(SOCK_DHCP, rxbuf, sizeof(rxbuf));
if (len > 0 && dhcp_parse(rxbuf)) {
dhcp_tick = wiz_millis();
}
}
```
使用方法:
1. 在初始化W5500之后,调用`dhcp_init()`函数进行DHCP初始化。
2. 在主循环中,调用`dhcp_process()`函数处理DHCP状态。
3. 如果DHCP已成功获取IP地址,则可以通过`wiz_get_ip()`等函数获取IP地址、子网掩码、网关和DNS等信息。
注意事项:
1. 必须使用单独的套接字(如SOCK_DHCP)来发送和接收DHCP消息。
2. 在发送DHCP消息时,必须设置DHCP选项,包括消息类型、请求IP地址、DHCP服务器IP地址等。
3. 在解析DHCP消息时,必须验证会话ID和MAC地址,以确保收到的消息是针对当前W5500的。
4. 在DHCP续租或重新绑定时,必须根据DHCP服务器返回的租期计算续租时间和重新绑定时间。
以上代码仅供参考,具体实现可能需要根据实际情况进行修改。
阅读全文