LWIP分析与socket编程方法

先分析出LWIP大致结构:

lwip_init_task
netif_add(lpc17xx_netif, &ipaddr, &netmask, &gw, NULL, ethernetif_init, tcpip_input)
	init(netif)  //就是ethernetif_init
		low_level_init(netif);
			ethernetif_input
				CoPendSem(semEthRx, 0) //等待semEthRx,由ENET_IRQHandler的isr_PostSem(semEthRx)发送,说明缓存区接收完成
				p = low_level_input(netif);  //从MAC缓存区取数据
					len = StartReadFrame();
					p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
					CopyFromFrame_EMAC(q->payload, q->len);
					EndReadFrame();
				netif->input(p, netif)  //就是tcpip_input,通过netif_add设置的
					sys_mbox_trypost(mbox, msg)  //发送msg到——>tcpip_thread线程
					----------------------------
					----------------------------
					sys_mbox_fetch(mbox, (void *)&msg); //tcpip_thread线程等待msg
					ip_input(struct pbuf *p, struct netif *inp)
						tcp_input(p, inp);或udp_input(p, inp);协议层处理

Lwip的socket编程用到的底层函数:
底层链接初始化:low_level_init

底层数据发送: low_level_output  //发送数据时最后会调用此netif->output,也就是etharp_output,而etharp_output会调用netif->linkoutput,也就是low_level_output

底层数据接收: low_level_input    //在ethernetif_input里面等待底层有数据就调用此函数接收数据


下面介绍基于LwIP socket的UDP服务器的编写步骤,并且比较客户端和服务器之间的区别,UDP服务器编写步骤如下所示:

1、创建一个基于数据包的socket

2、设置本地服务器地址及端口号

3、将本地服务器地址与创建好的socket进行绑定

4、接收绑定好的socket的消息

经过了以上四个步骤以后,一个简单的UDP服务器就搭建好了,其他客户端发来的数据就会被服务器接收下来,其源代码如下所示

/*
  *	receive UDP packet from PC
  *   local server IP:192.168.0.80 or INADDR_ANY
  */

#include 
#include 
#include 

#define	PORT			50000

static RAW_U32 udp_msg[100];

static void udp_server_thread(void *p_arg)
{
	struct sockaddr_in server_addr;
	int sock_fd;				/* server socked */
	int err;
	int count = 0;
	
	
	sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
	if (sock_fd == -1) {
		Uart_Printf("failed to create sock_fd!\n");
		RAW_ASSERT(0);
	}
	
	raw_memset(&server_addr, 0, sizeof(server_addr));
	server_addr.sin_family = AF_INET;		
	//server_addr.sin_addr.s_addr = INADDR_ANY;
	server_addr.sin_addr.s_addr = inet_addr("192.168.0.80");
	server_addr.sin_port = htons(PORT);
	
	err = bind(sock_fd, (struct sockaddr *)&server_addr, sizeof(server_addr));
	if (err == -1) {
		RAW_ASSERT(0);
	}
	
	while (1) {
		raw_memset(udp_msg, 0, sizeof(udp_msg));
		err = recv(sock_fd, (RAW_U8 *)udp_msg, sizeof(udp_msg), 0);
		
		Uart_Printf("receive msg: %s", udp_msg);
		
		count++;
	}
}

void udp_server_init(void)
{
	sys_thread_new("udp_server_thread",  udp_server_thread, NULL, DEFAULT_THREAD_STACKSIZE, DEFAULT_THREAD_PRIO - 1);
}

UDP客户端编程的基本步骤及测试代码。

1、创建一个数据包类型socket

2、绑定socket IP地址及端口号

3、往绑定好的socket发送数据

通过以上步骤,即可以搭建好一个基于socket 的客户端,代码如下所示

/*
 * send UDP packet to PC
 * remote IP: 192.168.0.100 or INADDR_BROADCAST
 */

#include 
#include 
#include 

#define	PORT			50000

char udp_msg[] = "this is a UDP test package";

static void udp_client_thread(void *p_arg)
{
	struct sockaddr_in client_addr;
	int sock_fd;				/* client socked */
	int err;
	int count = 0;
	
	err = err;
	
	sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
	if (sock_fd == -1) {
		Uart_Printf("failed to create sock_fd!\n");
		RAW_ASSERT(0);
	}
	
	raw_memset(&client_addr, 0, sizeof(client_addr));
	client_addr.sin_family = AF_INET;
	//client_addr.sin_addr.s_addr = INADDR_BROADCAST;		
	client_addr.sin_addr.s_addr = inet_addr("192.168.0.100");
	client_addr.sin_port = htons(PORT);
	
	while (1) {
		err = sendto(sock_fd, (char *)udp_msg, sizeof(udp_msg), 0, \
						(struct sockaddr *)&client_addr, sizeof(client_addr));
		count++;
		Uart_Printf("-------------------send count %d-------------------\n", count);
		raw_sleep(100);
	}
}

void udp_client_init(void)
{
	sys_thread_new("udp_client_thread",  udp_client_thread, NULL, DEFAULT_THREAD_STACKSIZE, DEFAULT_THREAD_PRIO - 1);
}

下面介绍一下基于连接的TCP的编写方法,首先介绍TCP客户端编写流程,其步骤如下所示

1、创建一个基于流的socket

2、设置服务器IP地址和端口号

3、连接设置好以后的socket和服务器地址

4、连接好以后就发送/接收数据

从以上几个步骤可以发现TCP和UDP的最主要区别就是TCP有一个建立连接的过程,而UDP是没有的,其源代码如下所示

#include 
#include 
#include 

#define	PORT		50000

char msg[] = "hello, you are connected!\n";

static void tcp_client_thread(void * arg)
{
	struct sockaddr_in server_addr;
	int sock_fd;
	
	sock_fd = socket(AF_INET, SOCK_STREAM, 0);
	if (sock_fd == -1) {
		Uart_Printf("failed to create sock_fd!\n");
		RAW_ASSERT(0);
	}
	
	raw_memset(&server_addr, 0, sizeof(server_addr));
	server_addr.sin_family = AF_INET;
	server_addr.sin_addr.s_addr = inet_addr("192.168.0.100");
	server_addr.sin_port = htons(PORT);
	
	connect(sock_fd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr));

	while (1) {
		send(sock_fd, (char *)msg, sizeof(msg), 0);
		raw_sleep(100);
	}
	
//	close(sock_fd);
}


void tcp_client_init(void)
{
	sys_thread_new("tcp_client", tcp_client_thread, NULL, DEFAULT_THREAD_STACKSIZE, DEFAULT_THREAD_PRIO);
}

下面主要介绍TCP服务器的编写步骤方法,其流程如下所示

1、创建一个基于流的socket

2、设置本地服务器IP地址及端口号

3、绑定创建的socket和本地IP地址及端口信息

4、监听该socket(listen)

5、接受该socket(accept)

6、发送、接收数据

经过了以上几个步骤以后,一个简单的服务器就创建起来了,TCP服务器主要是多了监听和接受两个步骤,少了连接步骤,其源代码如下所示:

#include 
#include 
#include 

#define	PORT			50000

RAW_U8 data_buffer[100];

static void tcp_server_thread(void *p_arg)
{
	struct sockaddr_in server_addr;
	struct sockaddr_in conn_addr;
	int sock_fd;				/* server socked */
	int sock_conn;			/* request socked */
	socklen_t addr_len;
	int err;
	int length;
	int count = 0;
	
	
	sock_fd = socket(AF_INET, SOCK_STREAM, 0);
	if (sock_fd == -1) {
		Uart_Printf("failed to create sock_fd!\n");
		RAW_ASSERT(0);
	}
	
	raw_memset(&server_addr, 0, sizeof(server_addr));
	server_addr.sin_family = AF_INET;
	server_addr.sin_addr.s_addr =htonl(INADDR_ANY);
	server_addr.sin_port = htons(PORT);
	
	err = bind(sock_fd, (struct sockaddr *)&server_addr, sizeof(server_addr));
	if (err < 0) {
		RAW_ASSERT(0);
	}
	
	err = listen(sock_fd, 1);
	if (err < 0) {
		RAW_ASSERT(0);
	}

	addr_len = sizeof(struct sockaddr_in);
	
	Uart_Printf("before accept!\n");
	sock_conn = accept(sock_fd, (struct sockaddr *)&conn_addr, &addr_len);
	Uart_Printf("after accept!\n");
	
	while (1) {
		raw_memset(data_buffer, 0, sizeof(data_buffer));
		
		length = recv(sock_conn, (unsigned int *)data_buffer, 20, 0);
		
		Uart_Printf("length received %d\n", length);
		Uart_Printf("received string: %s\n", data_buffer);
		Uart_Printf("received count: %d\n", count);

		send(sock_conn, "good", 5, 0);
	}
}

void tcp_server_init(void)
{
	sys_thread_new("tcp_server_thread",  tcp_server_thread, NULL, DEFAULT_THREAD_STACKSIZE, DEFAULT_THREAD_PRIO - 1);
}


你可能感兴趣的:(LWIP)