IOT-9608I-L(工控板)实现TCP Client

目录

概述

[1 硬件接口介绍](#1 硬件接口介绍)

[1.1 接口介绍](#1.1 接口介绍)

[1.2 硬件接口](#1.2 硬件接口)

[2 TCP Client相关接口函数](#2 TCP Client相关接口函数)

[2.1 接口函数](#2.1 接口函数)

[2.2 认识函数](#2.2 认识函数)

[2.2.1 socket函数](#2.2.1 socket函数)

[2.2.2 bind函数](#2.2.2 bind函数)

[2.2.3 connect函数](#2.2.3 connect函数)

[2.2.4 读数据函数](#2.2.4 读数据函数)

[2.2.5 写数据函数](#2.2.5 写数据函数)

[3 TCP/IP Clinet功能实现](#3 TCP/IP Clinet功能实现)

[3.1 代码实现](#3.1 代码实现)

[3.2 详尽代码](#3.2 详尽代码)

[4 测试](#4 测试)

[4.1 编译代码](#4.1 编译代码)

[4.2 运行代码](#4.2 运行代码)


概述

本文主要介绍在IOT-9608I-L(工控板)实现TCP Client 的方法,其内容包括:板卡的NET硬件端口,以及和TCP Client相关接口函数的功能和用法,还编写一个实例,实现了TCP/IP Client,并在PC上配置一个servers实现数据的接收和发送功能。

1 硬件接口介绍

1.1 接口介绍

IoT-9608提供两路以太网接口,一路百兆网,一路千兆网。连接器物理形式为双网口RJ45插座,每个网口均有两个LED指示灯,用来指示以太网的工作情况。双网口工位为J12,其中,在主板上百兆网的标志为"NET1", 在主板上千兆网的标志为"NET2"。

系统上电以后NET1的绿灯亮,表示配置为百兆网,接入网线后黄灯亮,表示连接正常;NET2的指示灯在不接入网线时均不亮,当接入网线后,黄灯亮,表示连接正常,当有数据传输时,绿灯闪烁。

1.2 硬件接口

1)百兆RJ45接口引脚定义(NET1)

管脚号 符号 功能 管脚号 符号 功能 管脚号 符号 功能
1 TX+ 发送+ 4 NC 7 NC
2 TX- 发送- 5 NC 8 NC
3 RX+ 接收+ 6 RX- 接收-

2)千兆RJ45接口引脚定义(NET2)

管脚号 符号 功能 管脚号 符号 功能 管脚号 符号 功能
1 MX1+ 差分对1数据正 4 MX3+ 差分对3数据正 MX4+ NC 差分对4数据正
2 MX1- 差分对1数据负 5 MX3- 差分对3数据负 MX4- NC 差分对4数据负
3 MX2+ 差分对2数据正 6 MX2- 差分对2数据负

2 TCP Client相关接口函数

2.1 接口函数

Socket接口提供了一些接口函数,用于实现Client功能,其具体函数接口如下:

函数名称 功能描述
socket 创建一个Socket通信节点
bind 绑定地址和端口
connect 连接服务器端口
sendto 发送数据接口
recvfrom 接收数据接口

2.2 认识函数

2.2.1 socket函数

函数原型:

cpp 复制代码
int socket(int domain, int type, int protocol);

参数介绍

参数名称 功能描述
domain Socket所使用的地址类型
type Socket的类型
protocol 协议类型

函数返回值:

ERROR 类型 错误含义
EAFNOSUPPORT 本实现不支持指定的地址族
EMFILE 进程不再有文件描述符可用
ENFILE 系统不再有文件描述符可用
EPROTONOSUPPORT 地址族或本实现不支持协议
EPROTOTYPE 协议不支持套接字类型

2.2.2 bind函数

函数原型

cpp 复制代码
int bind(int socket, const struct sockaddr *address, socklentaddress_len);

参数介绍:

参数名称 功能描述
socket 指向Socket的有效文件描述符
address 一个指向struct sockaddr结构的指针,根据不同的协议,可以有不同的具体结构,对于IP地址,就是struct sockaddr_in
address_len 指明使用的地址数据结构的长度

返回值:

当bind()调用成功时返回0,失败时返回-1,这时需要检查的errno值见表。

ERROR 类型 含义
EADDRINUSE 指定的地址和端口已经被占用
EADDRNOTAVAIL 本机不存在指定的地址
EAFNOSUPPORT 对于指定的地址族来说,地址无效
ENOTSOCK socket不是指向socket的文件描述符
EBADF socket不是有效的文件描述符
EINVAL socket已经保定到一个地址,协议不支持绑定到新地址,或者socket已关闭
EOPNOTSUPP socket类型不支持对地址的绑定

2.2.3 connect函数

函数原型:

cpp 复制代码
int connect(int socket, const struct sockaddr *address, socklentaddress_len);

参数介绍:

参数名称 功能描述
socket 指向Socket的有效文件描述符
address 一个指向struct sockaddr结构的指针,根据不同的协议,可以有不同的具体结构,对于IP地址,就是struct sockaddr_in
address_len 指明使用的地址数据结构的长度

connect()需要处理的errno

errno 含义
EADDRNOTAVAIL 本机上没有指定地址
EAFNOSUPPORT 对于指定Socket的地址族来说,指定地址无效
EALREADY Socket已经做过connect()操作
EBADF 参数Socket不是有效的文件描述符
ECONNREFUSED 对方未监听Socket或拒绝连接
EINPROGRSS 已经设置为O_NONBLOCK的Socket不能立即建立连接,需要异步建立连接
EINTR 信号中断了建立连接的尝试,需要异步建立连接
EISCONN 指定的Socket已经连接
ENETUNREACH 没有到目标网络的路由
ENOTSOCK 文件描述符未指向Socket
EPROTOTYPE 指定的地址类型与绑定到指定对等地址的Socket类型不同
ETIMEDOUT 试图建立连接超时

2.2.4 读数据函数

函数原型

cpp 复制代码
ssize_t read(int fd, void *buf, size_t count);

ssize_t recv(int sockfd, void *buf, size_t len, int flags);

ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
              struct sockaddr *src_addr, socklen_t *addrlen);

ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);

2.2.5 写数据函数

函数原型

cpp 复制代码
ssize_t write(int fd, const void *buf, size_t count);

ssize_t send(int sockfd, const void *buf, size_t len, int flags);

ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
            const struct sockaddr *dest_addr, socklen_t addrlen);

3 TCP/IP Clinet功能实现

3.1 代码实现

1)创建socket

  1. 使用connect连接服务器端口

3)接收/发送数据

3.2 详尽代码

1) 创建client.c文件,编写client功能代码

cpp 复制代码
/***************************************************************
Copyright  2024-2029. All rights reserved.
文件名     :  client.c
作者       : tangmingfei2013@126.com
版本       : V1.0
描述       : IOT_9608 TCP/IP Client测试程序
其他       : 无
日志       : 初版V1.0 2024/04/23
***************************************************************/
#include <stdio.h> 
#include <stdlib.h>
#include <unistd.h>
#include <errno.h> 
#include <string.h> 
#include <netdb.h> 
#include <sys/types.h> 
#include <netinet/in.h> 
#include <sys/socket.h> 
#include <arpa/inet.h>

#define PORT        5000                    // The port which is communicate with server
#define LENGTH      256                     // Buffer length

int main(int argc, char *argv[])
{
    int sockfd;                         // Socket file descriptor
    int num;                           // Counter of received bytes  
    char revbuf[LENGTH];               // Receive buffer
    char buff[LENGTH]; 
    struct sockaddr_in remote_addr;    // Host address information

    /* Check parameters number */
    if (argc != 2)                     
    {    
        printf ("Usage: client HOST IP (ex: ./client 192.168.1.4).\n");
        return (0);
    }

    /* Get the Socket file descriptor */
    if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
    {
        printf("ERROR: Failed to obtain Socket Descriptor!\n");
        return (0);
    }
    
    /* Fill the socket address struct */
    remote_addr.sin_family = AF_INET;                   // Protocol Family
    remote_addr.sin_port = htons(PORT);                 // Port number
    inet_pton(AF_INET, argv[1], &remote_addr.sin_addr); // Net Address
    bzero(&(remote_addr.sin_zero), 8);                  // Flush the rest of struct

    /* Try to connect the remote */
    if (connect(sockfd, (struct sockaddr *)&remote_addr,  sizeof(struct sockaddr)) == -1) 
    {
        printf ("ERROR: Failed to connect to the host!\n");
        return (0);
    }  
    else
    {
        printf ("OK: Have connected to the %s\n",argv[1]);
    }

    /* Try to connect the server */
    while (strcmp(revbuf,"exit") != 0)     // Check remoter command
    {      
        bzero(revbuf,LENGTH);
        num = recv(sockfd, revbuf, LENGTH, 0);

        switch(num)
        {
            case -1:
        	printf("ERROR: Receive string error!\n");
                close(sockfd);
                return (0);
                
            case  0:
                close(sockfd);
                return(0);
              
            default:
                printf ("OK: Receviced numbytes = %d\n", num);
                break;
        }
        
        revbuf[num] = '\0';
        printf ("OK: Receviced string is: %s \n", revbuf);
       
        // send response message to server
        memset(buff,'\0',sizeof(buff));
        sprintf(buff,"IOT_9608 TCP/IP Client,i am %s:%d\n",
                inet_ntoa(remote_addr.sin_addr),ntohs(remote_addr.sin_port));
        
        ssize_t send_ret = send(sockfd, buff, strlen(buff),0); 
        if(send_ret < 0)
        {
            close(sockfd);
            return(0);
        }
    }

    close (sockfd);
    return (0);
}

2)编写Makefile

bash 复制代码
EXEC= client
OBJS= client.o

CROSS = arm-none-linux-gnueabi-
CC= ${CROSS}gcc

LDFLAGS =
CFLAGS += -g -Wall
EXTRA_LIBS += 

all: $(EXEC)

$(EXEC): $(OBJS)
	$(CC) $(LDFLAGS) -o $@ $(OBJS)  $(EXTRA_LIBS)

clean:
	-rm -f $(EXEC) *.elf *.gdb *.o

4 测试

4.1 编译代码

使用make编译代码,然后将编译的可执行文件共享至NFS目录

4.2 运行代码

1)使用NetAssist,创建服务器,端口设置为5000

2)在板卡上运行代码,使用如下命令:

cpp 复制代码
./client 192.168.1.4

板卡上的log信息:

服务器软件上收到的log:

相关推荐
没有名字的小羊19 分钟前
Linux基础命令——账户简单管理
linux·运维·服务器·网络·数据库
沈艺强22 分钟前
计算机网络nat 映射案列
网络·计算机网络
嘻嘻仙人1 小时前
【网络通信基础与实践第四讲】用户数据报协议UDP和传输控制协议TCP
网络·网络协议·udp·tcp·三次握手·流量控制·拥塞控制
极客小张1 小时前
基于正点原子Linux开发板的智能监控与家电控制系统设计:深度解析Video4Linux和TCP/IP技术栈
linux·运维·c++·物联网·网络协议·tcp/ip·算法
DC_BLOG4 小时前
IPv6(四)
运维·服务器·网络·ip
小珑也要变强4 小时前
队列基础概念
c语言·开发语言·数据结构·物联网
明朝百晓生4 小时前
无线感知会议系列【3】【基于WiFi和4G/5G的非接触无线感知:挑战、理论和应用-1】
网络·5g
城南云小白8 小时前
Linux网络服务只iptables防火墙工具
linux·服务器·网络
咩咩大主教8 小时前
C++基于select和epoll的TCP服务器
linux·服务器·c语言·开发语言·c++·tcp/ip·io多路复用