ZYNQ—使用lwip的Socket API—TCP服务器代码示例

文章详细描述了在Zynq平台上使用Lwip协议栈1.2版本进行TCP通信的初始化过程,包括创建Lwip初始化任务,配置PHY芯片,设置IP地址、子网掩码和网关,以及建立监听和数据处理任务。代码示例展示了如何使用SocketAPI进行TCP连接的建立、监听和数据交换。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

简介

由于项目需要与上位机通过以太网进行稳定可靠的通信,需要使用Lwip协议栈的TCP部分。zynq的lwip协议栈的版本是1.2,将API模式配置为Socket API。
在这里插入图片描述

代码

创建lwip初始化任务

创建lwip初始化任务,在任务中需要对iwip协议栈初始化以及初始化,初始化配置连接配置信息,例如服务器ip地址,掩码,网关等信息。

/*系统任务开启中创建任务LWIP_TASK用于初始化lwip协议栈*/
#define LWIP_TASK__STACKSIZE 1024
#define THREAD_STACKSIZE 1024
int new_sd;

sys_thread_new("LWIP_TASK", (void(*)(void*))Lwip_TASK, 0,
						LWIP_TASK__STACKSIZE,
		                DEFAULT_THREAD_PRIO);//创建LWIP_TASK线程

初始化任务函数

//lwip初始化任务函数
int Lwip_TASK(){
	int mscnt = 0;
	/* 系统初始化任务 */
    lwip_init();
    /* 创建NW_THRD任务 */
    sys_thread_new("NW_THRD", network_thread, NULL,
					THREAD_STACKSIZE,
            		DEFAULT_THREAD_PRIO);
    while (1) {
		vTaskDelay(DHCP_FINE_TIMER_MSECS / portTICK_RATE_MS);
		mscnt += DHCP_FINE_TIMER_MSECS;
		if (mscnt >= 5000) {
			xil_printf("Configuring default IP of 192.168.10.10\r\n");
			IP4_ADDR(&(server_netif.ip_addr),  192, 168, 10, 10);
			IP4_ADDR(&(server_netif.netmask), 255, 255, 255, 0);
			IP4_ADDR(&(server_netif.gw),  192, 168, 10, 1);
			print_ip_settings(&(server_netif.ip_addr), &(server_netif.netmask), &(server_netif.gw));
			/* print all application headers */
			sys_thread_new("lwip_listen_TASK",Lwip_Listen_TASK,0,
					THREAD_STACKSIZE,
					DEFAULT_THREAD_PRIO);
			break;
		}
	}
    vTaskDelete(NULL); //删除任务
    return 0;
}


配置phy芯片

//用于配置PHY芯片的部分功能
void network_thread(void *p)
{
    struct netif *netif;
    /* mac地址 每个开发板应该是唯一的 */
    unsigned char mac_ethernet_address[] = { 0x00, 0x0a, 0x35, 0x00, 0x01, 0x02 };
    ip_addr_t ipaddr, netmask, gw;
    int mscnt = 0;
    netif = &server_netif;
	ipaddr.addr = 0;
	gw.addr = 0;
	netmask.addr = 0;
    /* 将ip地址、网关、子网掩码加到netif */
    if (!xemac_add(netif, &ipaddr, &netmask, &gw, mac_ethernet_address, PLATFORM_EMAC_BASEADDR)) {
	xil_printf("Error adding N/W interface\r\n");
	return;
    }
    netif_set_default(netif);
    /*启动指定网络*/
    netif_set_up(netif);
    /*启动数据包接收线程-lwIP操作所需*/
    sys_thread_new("xemacif_input_thread", (void(*)(void*))xemacif_input_thread, netif,
            THREAD_STACKSIZE,
            DEFAULT_THREAD_PRIO);

    dhcp_start(netif);
    while (1) {
		vTaskDelay(DHCP_FINE_TIMER_MSECS / portTICK_RATE_MS);
		dhcp_fine_tmr();
		mscnt += DHCP_FINE_TIMER_MSECS;
		if (mscnt >= DHCP_COARSE_TIMER_SECS*1000) {
			dhcp_coarse_tmr();
			mscnt = 0;
		}
	}
    return;
}
//该函数是库中的函数,无法使用(调度函数)
/*输入线程调用lwIP来处理任何接收到的数据包。该线程等待直到接收到一个数据包(sem_rx_data_available),然后调用xemacif_input,该线程一次处理1个数据包*/
void xemacif_input_thread(struct netif *netif){
	struct xemac_s *emac = (struct xemac_s *)netif->state;
	while (1) {
		/* 睡眠直到有数据包要处理 这个信号量是由数据包接收中断例程设置的*/
		sys_sem_wait(&emac->sem_rx_data_available);
		/* 将所有接收到的数据包移动到lwIP */
		xemacif_input(netif);
	}
}

监听任务

当协议初始化完成后,进入监听和应答任务

void Lwip_Listen_TASK()
{
	int sock;
	int size;
	struct sockaddr_in address, remote;
	memset(&address, 0, sizeof(address));

	if ((sock = lwip_socket(AF_INET, SOCK_STREAM, 0)) < 0)
		return;

	address.sin_family = AF_INET;
	address.sin_port = htons(LWIP_PORT);
	address.sin_addr.s_addr = INADDR_ANY;

	if (lwip_bind(sock, (struct sockaddr *)&address, sizeof (address)) < 0)
		return;

	lwip_listen(sock, 0);//监听
	size = sizeof(remote);

	while (1) {
		/*连接应答任务*/
		if ((new_sd = lwip_accept(sock, (struct sockaddr *)&remote, (socklen_t *)&size)) > 0) {
			//连接后创建数据应答的任务
			printf("Connect SuccessFul !\r\n");
			sys_thread_new("lwip_data_TASK", 
				 			Lwip_Data_TASK,
							(void*)new_sd,
							THREAD_STACKSIZE,
							FreeRtos_ECHOS_TASK_PRIO);
		}
		//时间调度 防止任务卡死
		vTaskDelay(DHCP_FINE_TIMER_MSECS / portTICK_RATE_MS);
	}
}

接收数据后数据处理任务

/* 接收数据后进入任务 */
void Lwip_Data_TASK(void *p)
{
	int sd = (int)p;
	int RECV_BUF_SIZE = 15;
	u8 recv_buf[RECV_BUF_SIZE];
	int n,nwrote;

	while (1) {
		/* 接受数据放到缓存区 */
		if ((n = read(sd, recv_buf, RECV_BUF_SIZE)) < 0) {
			/*接受数据错误*/
			xil_printf("%s: error reading from socket %d, closing socket\r\n", __FUNCTION__, sd);
			break;
		}
		if (!strncmp(recv_buf, "quit", 4)){

			break;
		}


		/*如果客户端关闭连接则中断*/
		if (n <= 0){
			break;
		}
		/*将接收的数据返回*/
		write(sd, recv_buf, RECV_BUF_SIZE);

	}
	close(sd);
	vTaskDelete(NULL);
}

源码连接

链接:资料连接
提取码:k2cl

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

嘉鑫的程序员

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值