当前位置:首页 > > ZYNQ


前言

最近在做Zynq的ps端,需要用到网络传输,遇到一些问题,在这里汇总一下。有些lwip的发送与接收函数中已经加了锁,我们翻阅底层函数是可以看到的,所以发送接收不会冲突,本篇中,我们就没加锁了。

客户端与服务器共存?

言归正传,我们知道在sdk的例程中,既有做客户端client,又有做服务器server 的,那么Zynq lwip怎么既可以做客户端又可以做服务器呢?

简而言之,在同一个连接中,怎么做到既可以接收又可以发送呢?

以udp协议为例

我们以udp协议为例吧。先看看怎么发送数据到pc端。

在我们建立sock连接之后,当有数据需要发送时,则触发事件,进行发送,在taskUdpSendHandleEvent(event);函数中操作。

 1void taskUdpSendMesg(void *pPara,QueueHandle_t evntQueue)  2{  3 err_t err;  4 u32_t i;  5  6 memset(&addr, 0, sizeof(struct sockaddr_in));  7 addr.sin_family = AF_INET;  8 addr.sin_port = htons(UDP_CONN_PORT);  9 addr.sin_addr.s_addr = inet_addr(SERVER_IP_ADDRESS); 10 11 for (i = 0; i < NUM_OF_PARALLEL_CLIENTS; i++) { 12 if ((sock[i] = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 13 xil_printf("UDP client: Error creating Socket\r\n"); 14 return; 15 } 16 17 err = connect(sock[i], (struct sockaddr *)&addr, sizeof(addr)); 18 if (err != ERR_OK) { 19 xil_printf("UDP client: Error on connect: %d\r\n", err); 20 close(sock[i]); 21 return; 22 } 23 } 24 25 /* Wait for successful connections */ 26 usleep(10); 27 28 reset_stats(); 29 const TickType_t xMaxBlockTime = pdMS_TO_TICKS(500); /* 设置最大等待时间500ms */ 30 Event event; 31 while(1) 32 { 33 taskUdpSendHandleEvent(event); 34 }

udp发送最主要的是lwip_sendto函数,当然下面这个还有一个简单的重发机制。

 1static int udpPacketSend(u16* buffer,int length)  2{  3 u8_t retries=0;  4 int i, count;  5 socklen_t len = sizeof(addr);  6 count = lwip_sendto(sock[0], buffer, length, 0,  7 (struct sockaddr *)&addr, len);//return sizeof(send_buf)  8 //printf("count value is : %d \r\n",count);  9 if (count <= 0) { 10 retries = MAX_SEND_RETRY; 11 xil_printf("enter udp_packet_send\r\n\r\n, "); 12 usleep(ERROR_SLEEP); 13 } 14 for (i = 0; i < NUM_OF_PARALLEL_CLIENTS; i++) { 15 while (retries) { 16 xil_printf("retries value is %d\r\n\r\n",retries); 17 count = lwip_sendto(sock[0], buffer, length, 0, 18 (struct sockaddr *)&addr, len);//return sizeof(send_buf) 19 if (count <= 0) { 20 retries--; 21 usleep(ERROR_SLEEP); 22 } else { 23 client.total_bytes += count; 24 client.cnt_datagrams++; 25 client.i_report.total_bytes += count; 26 break; 27 } 28 } 29 }

在说完了发送之后,那么怎么在发送的时候建立接收机制呢?

我们再开另外一个线程,产生一个新的线程,即进入主线程,complete_nw_thread标志置为1,代码如下:

 1void networkRecvThread(void *pPara)  2{  3 /* the mac address of the board. this should be unique per board */  4 u8_t mac_ethernet_address[] = { 0x00, 0x0a, 0x35, 0x00, 0x01, 0x02 };  5  6 /* Add network interface to the netif_list, and set it as default */  7 /*xemac_add添加网络接口,并将其设置为默认接口*/  8 if (!xemac_add(&server_netif, NULL, NULL, NULL, mac_ethernet_address,  9 PLATFORM_EMAC_BASEADDR)) { 10 xil_printf("Error adding N/W interface\r\n"); 11 return; 12 } 13 14 netif_set_default(&server_netif); 15 16 /* 启用网络接口 specify that the network if is up */ 17 netif_set_up(&server_netif); 18 19 /* start packet receive thread - required for lwIP operation */ 20 /*为xemacif_input_thread()函数单独开启一个线程,将从中断响应过程中接收到的数据包移植到lwip的* xemacif_input_thread()函数运行的线程中,该线程在lwip数据包到达时发出通知,并接收中断句柄将数据存储到缓存中*/ 21 sys_thread_new("xemacif_input_thread", 22 (void(*)(void*))xemacif_input_thread, &server_netif, 23 THREAD_STACKSIZE, DEFAULT_THREAD_PRIO); 24 complete_nw_thread = 1; 25 26 //receive task begin 27 vTaskUdpRecvMesg(&pPara); 28 29 vTaskDelete(NULL); 30 31}

上述函数vTaskUdpRecvMesg()中在中我们开始做这接收的操作,重点是我们需要申明一个不同的sock,定义如下:

1static int sock1[NUM_OF_PARALLEL_CLIENTS];

接收端主要是lwip_recvfrom()函数,当然lwip_recv()函数也是一样的,只是形参的区别。

我们在建立好连接之后,如果pc端有数据发送,则会在recv_buf里接收到,这里我把数据发送出去处理,如果没有数据接收,那么会堵塞在接收函数中,这样就可以解决既可以接收又可以发送的问题了。

 1void taskUdpRecvMesg(void *pPara)  2{  3 QueueHandle_t taskUdpRecvQueue;  4 taskUdpRecvQueue = getTaskQueue(getTaskId("PsSendOrder2PlTask"));  5 //BaseType_t xHigherPriorityTaskWoken = pdFALSE;  6 //create a event, send it  7 Event event;  8 int count;  9 struct sockaddr_in from; 10 socklen_t fromlen = sizeof(from); 11 while (1) { 12 if((count = lwip_recvfrom(sock1[0], recv_buf, UDP_SEND_BUFSIZE, 0, 13 (struct sockaddr *)&from, &fromlen)) > 0) 14 { 15 makeEvent(&event,UdpRec_ID,psSendData2pl,strlen(recv_buf),recv_buf); 16 xQueueSendToBack(taskUdpRecvQueue,&event,0); 17 } 18 } 19}

总结

在项目中,我们经常会遇到这样的问题,第一点使用操作系统,第二点根据需求抓住难点,重点还是要理解udp/tcp的原理,这样很多问题就会迎刃而解。

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
关闭