完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
在进行本节之前,首先解决大家的一个疑惑点:Client和Client_Socket有什么区别或分别代表的含义? Socket标准定义为套接字,应用于主流的网络设计程序,具有使用简单,多平台移植方便的特点。在Socket应用中,使用一个套接字来记录网络的一个连接,套接字是一个整数,就像操作文件一样,利用一个文件描述符,进行打开、读、写、关闭等操作。在网络中,可以对Socket 套接字进行类似的操作,比如开启一个网络的连接、读取连接主机发送来的数据、向连接的主机发送数据、终止连接等操作。LwIP设计目的主要应用于嵌入式平台,对于Socket的支持并不完全,只是通过对netconn进行封装实现部分功能,使得LwIP也具有多平台应用的特性,通过Socket方式的了解能够极大简化通信过程的理解,快速实现应用开发。 Demo应用中,使用的开发板为MB-039,在工程中使用LwIP+FreeRTOS,实验展示如何制作一个客户端并发送数据,板载Ethernet相关的硬件部分电路如下: 各个信号引脚对应如下: 在进行Client_Socket实验前,我们先了解需要使用到的应用功能函数: (1)socket () (2)connect () (3)write () (1) socket () Socket()指向lwip_socket(),功能为申请一个套接字,lwip_socket()源码如下:int lwip_socket(int domain, int type, int protocol) { struct netconn *conn; int i; LWIP_UNUSED_ARG(domain); /* @todo: check this */ /* create a netconn */ switch (type) { case SOCK_RAW: conn = netconn_new_with_proto_and_callback(DOMAIN_TO_NETCONN_TYPE(domain, NETCONN_RAW), (u8_t)protocol, DEFAULT_SOCKET_EVENTCB); LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_RAW, %d) = ", domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol)); break; case SOCK_DGRAM: conn = netconn_new_with_callback(DOMAIN_TO_NETCONN_TYPE(domain, ((protocol == IPPROTO_UDPLITE) ? NETCONN_UDPLITE : NETCONN_UDP)), DEFAULT_SOCKET_EVENTCB); LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_DGRAM, %d) = ", domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol)); #if LWIP_NETBUF_RECVINFO if (conn) { /* netconn layer enables pktinfo by default, sockets default to off */ conn->flags &= ~NETCONN_FLAG_PKTINFO; } #endif /* LWIP_NETBUF_RECVINFO */ break; case SOCK_STREAM: conn = netconn_new_with_callback(DOMAIN_TO_NETCONN_TYPE(domain, NETCONN_TCP), DEFAULT_SOCKET_EVENTCB); LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_STREAM, %d) = ", domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol)); break; default: LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%d, %d/UNKNOWN, %d) = -1n", domain, type, protocol)); set_errno(EINVAL); return -1; } if (!conn) { LWIP_DEBUGF(SOCKETS_DEBUG, ("-1 / ENOBUFS (could not create netconn)n")); set_errno(ENOBUFS); return -1; } i = alloc_socket(conn, 0); if (i == -1) { netconn_delete(conn); set_errno(ENFILE); return -1; } conn->socket = i; done_socket(&sockets[i - LWIP_SOCKET_OFFSET]); LWIP_DEBUGF(SOCKETS_DEBUG, ("%dn", i)); set_errno(0); return i; } 从源码中我们可以看出,本质上是对netconn_new()进行封装。我们关注一下其参数,domain表示协议簇,对于IP/TCP来说该值始终为AF_INET。重点需要关注一下type,我们查看API手册对于几种类型的解释如下: 1. SOCK_STREAM:提供可靠的(即能保证数据正确传送到对方)面向连接Socket服务,多用于资料(如文件)传输,如TCP协议。 2. SOCK_DGRAM:是提供无保障的面向消息的Socket服务,主要用于在网络上发广播信息,如UDP协议,提供无连接不可靠的数据报交付服务。 3. SOCK_RAW:表示原始套接字,它允许应用程序访问网络层的原始数据包,这个套接字用得比较少,暂时不用理会它。 Protocol指定套接字使用的协议,对于IPv4,TCP协议提供SOCK_STREAM服务,只有UDP协议提供SOCK_DGRAM服务。 (2) connect () connect()指向lwip_connect()(源码较长,就不进行粘贴了),函数的作用与前文介绍netconn_connect功能一致,通过源码可以知道其是通过对netconn_connect的封装实现。在TCP客户端连接中,调用这个函数将发生握手过程,并最终建立新的TCP连接。对于UDP来说调用这个函数只是在UDP控制块中记录远端IP地址与端口号。 (3) write () Write()指向lwip_write,源码如下,其通过调用lwip_send实现,flags为0。 ssize_t lwip_write(int s, const void *data, size_t size) { return lwip_send(s, data, size, 0); } 了解了以上3个API,接下来开始创建Client_Socket工程: static void client(void *thread_param) { int sock = -1; struct sockaddr_in client_addr; ip4_addr_t ipaddr; uint8_t send_buf[]= " This is MM32F3270 TCP Client_Socket Demo n"; IP4_ADDR(&ipaddr,DEST_IP_ADDR0,DEST_IP_ADDR1,DEST_IP_ADDR2,DEST_IP_ADDR3); while(1) { sock = socket(AF_INET, SOCK_STREAM, 0); //(1) if (sock < 0) { vTaskDelay(10); continue; } client_addr.sin_family = AF_INET; //(2) client_addr.sin_port = htons(DEST_PORT); //(3) client_addr.sin_addr.s_addr = ipaddr.addr; //(4) memset(&(client_addr.sin_zero), 0, sizeof(client_addr.sin_zero)); if (connect(sock, (struct sockaddr *)&client_addr, sizeof(struct sockaddr)) == -1) //(5) { printf("Connect failed!n"); closesocket(sock); vTaskDelay(10); continue; } while (1) { if(write(sock,send_buf,sizeof(send_buf)) < 0) //(6) break; vTaskDelay(1000); } closesocket(sock); } } (1)申请一个套接字:socket (2)协议簇类型(AF_INET用于TCP/IP协议) (3)将端口赋值给client_addr的sin_port成员 (4)将地址赋值给client_addr的sin_addr.s_addr成员 (5)创建连接,将sock与地址端口进行绑定,建立连接 (6)发送数据 到这里已经完成了Client Socket工程的创建,还有一步比较重要的是配置Client与Server端的IP,将数据发送给服务器端。 在Windows下,通过打开命令行窗口输入:ipconfig可以获取本机地址与服务器的地址。 #define DEST_IP_ADDR1 168 #define DEST_IP_ADDR2 105 #define DEST_IP_ADDR3 34 #define DEST_PORT 5001 #define IP_ADDR0 192 #define IP_ADDR1 168 #define IP_ADDR2 105 #define IP_ADDR3 130 将程序下载入开发板中,使用SSCOM工具进行如下设置: ~MM32F3270_Lib_Samples_V0.90Demo_appEthernet_DemoETH_RTOSFreertos_Client_socket 下章的题目为《基于MM32F3270 以太网 Server使用》讲解服务器端的实现及使用方式。 |
|
相关推荐
|
|
只有小组成员才能发言,加入小组>>
2243个成员聚集在这个小组
加入小组灵动微电子MM32全系列MCU产品应用手册,库函数和例程和选型表
11465 浏览 3 评论
【MM32 eMiniBoard试用连载】+基于OLED12864的GUI---U8G2
5896 浏览 1 评论
【MM32 eMiniBoard试用连载】移植RT-Thread至MM32L373PS
10784 浏览 0 评论
【MM32 eMiniBoard测评报告】+ 开箱 + 初探
4550 浏览 1 评论
灵动微课堂(第106讲) | MM32 USB功能学习笔记 —— WinUSB设备
4270 浏览 1 评论
[MM32软件] MM32F002使用内部flash存储数据怎么操作?
937浏览 1评论
760浏览 0评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-3 06:51 , Processed in 0.667333 second(s), Total 55, Slave 42 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号