打印
[MM32软件]

(分享)基于MM32F3270 以太网 Client_Socket使用

[复制链接]
3494|11
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
在进行本节之前,首先解决大家的一个疑惑点:Client和Client_Socket有什么区别或分别代表的含义?


Socket标准定义为套接字,应用于主流的网络设计程序,具有使用简单,多平台移植方便的特点。在Socket应用中,使用一个套接字来记录网络的一个连接,套接字是一个整数,就像操作文件一样,利用一个文件描述符,进行打开、读、写、关闭等操作。在网络中,可以对Socket 套接字进行类似的操作,比如开启一个网络的连接、读取连接主机发送来的数据、向连接的主机发送数据、终止连接等操作。LwIP设计目的主要应用于嵌入式平台,对于Socket的支持并不完全,只是通过对netconn进行封装实现部分功能,使得LwIP也具有多平台应用的特性,通过Socket方式的了解能够极大简化通信过程的理解,快速实现应用开发。

使用特权

评论回复
沙发
两只袜子|  楼主 | 2021-10-19 15:00 | 只看该作者
Demo应用中,使用的开发板为MB-039,在工程中使用LwIP+FreeRTOS,实验展示如何制作一个客户端并发送数据,板载Ethernet相关的硬件部分电路如下:

MB-039 完整原理图可以通过MM32官网下载。


各个信号引脚对应如下:




使用特权

评论回复
板凳
两只袜子|  楼主 | 2021-10-19 15:00 | 只看该作者
通过配置复用相关引脚为RMII相关的功能,初始化以太网功能,执行FreeRTOS的启动。具体过程可参考样例初始化程序中代码。



在进行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) = -1\n",

                                  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, ("%d\n", i));

  set_errno(0);

  return i;

}


使用特权

评论回复
地板
两只袜子|  楼主 | 2021-10-19 15:02 | 只看该作者
从源码中我们可以看出,本质上是对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);

}


使用特权

评论回复
5
两只袜子|  楼主 | 2021-10-19 15:03 | 只看该作者
了解了以上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可以获取本机地址与服务器的地址。


使用特权

评论回复
6
两只袜子|  楼主 | 2021-10-19 15:35 | 只看该作者
可以观察到PC地址为:192.168.105.34,在sys_arch.h文件中对DEST_IP_ADDR0 、DEST_IP_ADDR1、DEST_IP_ADDR2、DEST_IP_ADDR3进行修改,DEST_PORT可选用空闲端口,设备IP需要设置在同一个网段内通信才能进行IP_ADDR0、IP_ADDR1  、IP_ADDR2,需要与PC地址保持一致,IP_ADDR3可以随意设置(和PC地址不一致即可)。#define DEST_IP_ADDR0               192

#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


使用特权

评论回复
7
两只袜子|  楼主 | 2021-10-19 15:39 | 只看该作者
将程序下载入开发板中,使用SSCOM工具进行如下设置:

使用特权

评论回复
8
两只袜子|  楼主 | 2021-10-19 15:39 | 只看该作者
点击侦听:

使用特权

评论回复
9
两只袜子|  楼主 | 2021-10-19 15:39 | 只看该作者
可以观察到正常侦听并接收到数据,表明实验成功。Demo程序可登录MindMotion的官网(http://www.mindmotion.com.cn/download.aspx?cid=2542&page=2)下载MM32F3270 lib_Samples,工程路径如下:
~\MM32F3270_Lib_Samples_V0.90\Demo_app\Ethernet_Demo\ETH_RTOS\Freertos_Client_socket
下章的题目为《基于MM32F3270 以太网 Server使用》讲解服务器端的实现及使用方式

使用特权

评论回复
10
豌豆爹| | 2021-10-20 15:59 | 只看该作者
分享的知识很棒,赞

使用特权

评论回复
11
ynndmalh21| | 2021-10-29 08:47 | 只看该作者
感谢楼主的分享,很棒,很赞的。

使用特权

评论回复
12
lajdfla001| | 2021-10-29 09:58 | 只看该作者
看见这个原理图,就特别的熟悉,很棒了。
不错的。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

2038

主题

7363

帖子

10

粉丝