我调通的代码:
#include <rtthread.h>
#include <string.h>
//#include <app_sfcon1_tcp.h>
//#if !defined(SAL_USING_POSIX)
//#error "Please enable SAL_USING_POSIX!"
//#else
//#include <sys/time.h>
//#include <sys/select.h>
//#endif
#include <sys/socket.h> /* 使用BSD socket,需要包含socket.h头文件 */
//#include "netdb.h"
#include <lwip/opt.h>
#include <lwip/sockets.h>
#include <lwip/inet_chksum.h>
#include <netif/etharp.h>
#include <netif/ethernetif.h>
#include <lwip/ip.h>
#include <lwip/init.h>
#include <lwip/init.h>
#include "lwip/udp.h"
#include "lwip/def.h"
#define DEBUG_UDP_SERVER
#define DBG_TAG "UDP"
#ifdef DEBUG_UDP_SERVER
#define DBG_LVL DBG_LOG
#else
#define DBG_LVL DBG_INFO /* DBG_ERROR */
#endif
#include <rtdbg.h>
#define BUFSZ 1024
static int started = 0;
static int is_running = 0;
static int port = 11010;
#define UDP_DEMO_RX_BUFSIZE 1024
unsigned char udp_demo_recvbuf[UDP_DEMO_RX_BUFSIZE];
void udp_demo_recv(void *arg,struct udp_pcb *upcb,struct pbuf *p,struct ip_addr *addr,u16_t port)
{
unsigned int data_len = 0;
struct pbuf *q;
u32_t addr1;
if(p!=NULL) //接收到不为空的数据时
{
rt_memset(udp_demo_recvbuf,0,UDP_DEMO_RX_BUFSIZE); //数据接收缓冲区清零
for(q=p;q!=NULL;q=q->next)//遍历完整个pbuf链表
{
//判断要拷贝到UDP_DEMO_RX_BUFSIZE中的数据是否大于UDP_DEMO_RX_BUFSIZE的剩余空间,如果大于
//的话就只拷贝UDP_DEMO_RX_BUFSIZE中剩余长度的数据,否则的话就拷贝所有的数据
if(q->len > (UDP_DEMO_RX_BUFSIZE-data_len)) rt_memcpy((udp_demo_recvbuf+data_len),q->payload,(UDP_DEMO_RX_BUFSIZE-data_len));//拷贝数据
else rt_memcpy((udp_demo_recvbuf+data_len),q->payload,q->len);
data_len += q->len;
if(data_len > UDP_DEMO_RX_BUFSIZE) break; //超出TCP客户端接收数组,跳出
}
LOG_D("Received data = ");
for(unsigned char i = 0;i<data_len;i++)
{
LOG_D("%x",udp_demo_recvbuf[i]);
}
LOG_D("\n");
rt_memcpy(&addr1,addr,sizeof(addr1));
// upcb->remote_ip=*addr; //记录远程主机的IP地址
// upcb->remote_port=port; //记录远程主机的端口号
// lwipdev.remoteip[0]=upcb->remote_ip.addr&0xff; //IADDR4
// lwipdev.remoteip[1]=(upcb->remote_ip.addr>>8)&0xff; //IADDR3
// lwipdev.remoteip[2]=(upcb->remote_ip.addr>>16)&0xff;//IADDR2
// lwipdev.remoteip[3]=(upcb->remote_ip.addr>>24)&0xff;//IADDR1
LOG_D("ip1 = %d", (addr1&0xff)); //IADDR4
LOG_D("ip2 = %d",(addr1>>8)&0xff); //IADDR3
LOG_D("ip3 = %d",(addr1>>16)&0xff);//IADDR2
LOG_D("ip4 = %d",(addr1>>24)&0xff);//IADDR1
LOG_D("port = %d",port);//IADDR1
//udp_demo_flag|=1<<6; //标记接收到数据了
pbuf_free(p);//释放内存
}else
{
udp_disconnect(upcb);
// udp_demo_flag &= ~(1<<5); //标记连接断开
}
}
static void udpserv_connector4_entry(void *paramemter)
{
int sock;
int bytes_read;
char *recv_data;
socklen_t addr_len;
struct sockaddr_in server_addr, client_addr;
struct timeval timeout;
fd_set readset;
/* 分配接收用的数据缓冲 */
recv_data = rt_malloc(BUFSZ);
if (recv_data == RT_NULL)
{
LOG_E("No memory");
return;
}
/* 初始化服务端地址 */
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(port);
server_addr.sin_addr.s_addr = INADDR_ANY;//INADDR_NONE;//
rt_memset(&(server_addr.sin_zero), 0, sizeof(server_addr.sin_zero));
/* 创建一个socket,类型是SOCK_DGRAM,UDP类型 */
// if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
// {
// LOG_E("Create udp socket error");
// goto __exit;
// }
// setsockopt(sock,SOL_SOCKET,SO_BROADCAST,( void *)&optval,sizeof(optval));
udp_recv
// /* 绑定socket到服务端地址 */
// if (bind(sock, (struct sockaddr *)&server_addr,
// sizeof(struct sockaddr)) == -1)
if (udp_bind(sock, IP_ADDR_BROADCAST,port) == -1)
// {
// LOG_E("Unable to bind");
// goto __exit;
// }
struct udp_pcb *udp_pcb;
udp_pcb = udp_new();
if(udp_pcb!=NULL)
{
ip_set_option(udp_pcb, SOF_BROADCAST);
udp_bind(udp_pcb,IP_ADDR_ANY,11010);//组播端口
udp_recv(udp_pcb,udp_demo_recv,NULL);//接收回调函数
}
addr_len = sizeof(struct sockaddr);
LOG_I("UDPServer Waiting for client on port %d...", port);
started = 1;
is_running = 1;
timeout.tv_sec = 3;
timeout.tv_usec = 0;
while (is_running)
{
rt_thread_delay(100);
// FD_ZERO(&readset);
// FD_SET(sock, &readset);
/* Wait for read or write */
// if (select(sock + 1, &readset, RT_NULL, RT_NULL, &timeout) == 0)
// continue;
/* 从sock中收取最大BUFSZ - 1字节数据 */
// bytes_read = recvfrom(sock, recv_data, BUFSZ - 1, 0,
// (struct sockaddr *)&client_addr, &addr_len);
bytes_read = recv(sock, recv_data, BUFSZ - 1, 0);
if (bytes_read < 0)
{
LOG_E("Received error, close the connect.");
goto __exit;
}
else if (bytes_read == 0)
{
LOG_W("Received warning, recv function return 0.");
continue;
}
else
{
recv_data[bytes_read] = '\0'; /* 把末端清零 */
/* 输出接收的数据 */
LOG_D("Received data = %s", recv_data);
// sendto(sock, recv_data, rt_strlen(recv_data), 0,
// (struct sockaddr *)&client_addr, sizeof(struct sockaddr));
/* 如果接收数据是exit,退出 */
if (strcmp(recv_data, "exit") == 0)
{
goto __exit;
}
}
}
__exit:
if (recv_data)
{
rt_free(recv_data);
recv_data = RT_NULL;
}
if (sock >= 0)
{
closesocket(sock);
sock = -1;
}
started = 0;
is_running = 0;
}
//移植正点原子的UDP通信历程。
//1.将ENC28J60_Write(ERXFCON,ERXFCON_UCEN|ERXFCON_CRCEN|ERXFCON_PMEN);//能实现UDP,TCP的收发。但组播数据不行。
// 修改为ENC28J60_Write(ERXFCON,ERXFCON_CRCEN);//实现组播
//2.打开LWIP中的IGMP。在opt.h文件中 #define LWIP_IGMP 1
//3.在ethernetif.c中的static err_t low_level_init(struct netif *netif)中,添加NETIF_FLAG_IGMP
//netif->flags = NETIF_FLAG_BROADCAST|NETIF_FLAG_ETHARP|NETIF_FLAG_LINK_UP|NETIF_FLAG_IGMP;//添加IGMP
//4.在lwip_comm.c中的void lwip_periodic_handle()中加入
//#if LWIP_IGMP
// if(lwip_localtime-IGMPTimer >= IGMP_TMR_INTERVAL)
// {
// IGMPTimer = lwip_localtime;
// igmp_tmr();
// }
//#endif
//周期性处理igmp_tmr();函数
//5.UDP初始化
//void Init_UDP_Server(void)
//{
// IP4_ADDR(&ipgroup, 224,0,0,50);//组播IP地址
//#if LWIP_IGMP
// igmp_joingroup(IP_ADDR_ANY,(struct ip_addr *)(&ipgroup));//组播加入当前
//#endif
// udp_server_pcb = udp_new();
// if(udp_server_pcb!=NULL){
// udp_bind(udp_server_pcb,IP_ADDR_ANY,9999);//组播端口
// udp_recv(udp_server_pcb,udp_demo_recv,NULL);//接收回调函数
// }
//}
//6.添加组播发送函数
void multicast_send_data(unsigned char * data,unsigned short len)
{
// struct pbuf *p = pbuf_alloc(PBUF_TRANSPORT,len, PBUF_RAM);
// memcpy(p->payload, data, len);
// udp_sendto(udp_server_pcb, p,(struct ip_addr *) (&ipgroup),9999);
// pbuf_free(p);
}
//7.UDP接受回调函数
//UDP回调函数
static void usage(void)
{
rt_kprintf("Usage: udpserver -p <port>\n");
rt_kprintf(" udpserver --stop\n");
rt_kprintf(" udpserver --help\n");
rt_kprintf("\n");
rt_kprintf("Miscellaneous:\n");
rt_kprintf(" -p Specify the host port number\n");
rt_kprintf(" --stop Stop udpserver program\n");
rt_kprintf(" --help Print help information\n");
}
static void udpserver_sfcon4_config(int argc, char** argv)
{
rt_thread_t tid;
tid = rt_thread_create("udp_serv_sfcon4",
udpserv_connector4_entry, RT_NULL,
2048, RT_THREAD_PRIORITY_MAX/3, 20);
if (tid != RT_NULL)
{
rt_thread_startup(tid);
}
return;
//__usage:
// usage();
}
//INIT_APP_EXPORT(udpserver_sfcon4_config);
//#ifdef RT_USING_FINSH
MSH_CMD_EXPORT_ALIAS(udpserver_sfcon4_config, udpserver11,
Start a udp server. Help: udpserver --help);
//#endif
参考:http://www.openedv.com/forum.php?mod=viewthread&tid=107160&page=1#pid593578
恩,我实现了,我用的是
g_pcb = udp_new();
udp_bind(g_pcb,IP_ADDR_BROADCAST,UDP_DEMO_PORT);
udp_recv(g_pcb,udp_server_recv,NULL);
void udp_server_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p,struct ip_addr *addr, u16_t port)
{
struct ip_addr destAddr = *addr;
destipaddr2 = *addr;
if(p != NULL)
{
printf("\r\nIP:%d.%d.%d.%d",((uint32_t)(destAddr.addr)>>0&0xff),((uint32_t)(destAddr.addr)>>8)&0xff,((uint32_t)(destAddr.addr)>>16)&0xff,((uint32_t)(destAddr.addr)>>24)&0xff);
printf("\r\nport:%d",port);
udp_flag = 1;
udp_sendto(pcb,p,&destAddr,port);
pbuf_free(p);
}
}
udp_flag 是标记收到广播数据,发送函数用的是原子哥的教程里的发送函数,这个子函数里的udp_sendto(pcb,p,&destAddr,port); 是发送不成功,我也不知道原因各参数都是正确的