• 205ESP32_SDK开发TCP服务器(select方式,支持多连接,高速高并发传输)


    <p><iframe name="ifd" src="https://mnifdv.cn/resource/cnblogs/LearnESP32" frameborder="0" scrolling="auto" width="100%" height="1500"></iframe></p>

    你好的时候,别人说你这好那好,你不好的时候,别人说你这不好那不好;  成功的时候谁都是朋友,但只有母亲她才是失败时的伴侣. 在她眼里你永远是她孩子.

    你想送你的孩子上最好的学校,考最好的成绩,报各种补习班,但是你是否给了孩子幸福?

    说明

    1.参考代码

    https://www.cnblogs.com/orlion/p/6119812.html

    #include <string.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <ctype.h>
    #include "wrap.h"
    #define MAXLINE 80
    #define SERV_PORT 8001
    int main(int argc, char **argv)
    {
        int i, maxi, maxfd, listenfd, connfd, sockfd;
        int nready, client[FD_SETSIZE];
        ssize_t n;
        fd_set rset, allset;
        char buf[MAXLINE];
        char str[INET_ADDRSTRLEN];
        socklen_t cliaddr_len;
        struct sockaddr_in
        cliaddr, servaddr;
        listenfd = Socket(AF_INET, SOCK_STREAM, 0);
        bzero(&servaddr, sizeof(servaddr));
        servaddr.sin_family = AF_INET;
        servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
        servaddr.sin_port = htons(SERV_PORT);
        Bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
        Listen(listenfd, 20);
        maxfd = listenfd;
        maxi = -1;
        for (i = 0; i < FD_SETSIZE; i++)
            client[i] = -1; /* -1 indicates available entry */
        FD_ZERO(&allset);
        FD_SET(listenfd, &allset);
        for ( ; ; ) {
            rset = allset; /* structure assignment */
            nready = select(maxfd+1, &rset, NULL, NULL, NULL);
            if (nready < 0)
                perr_exit("select error");
            if (FD_ISSET(listenfd, &rset)) { /* new client connection */
                cliaddr_len = sizeof(cliaddr);
                connfd = Accept(listenfd, (struct sockaddr *)&cliaddr, &cliaddr_len);
                printf("received from %s at PORT %d\n",
                inet_ntop(AF_INET, &cliaddr.sin_addr, str, sizeof(str)),
                ntohs(cliaddr.sin_port));
                for (i = 0; i < FD_SETSIZE; i++)
                    if (client[i] < 0) {
                        client[i] = connfd; /* save descriptor */
                        break;
                    }
                if (i == FD_SETSIZE) {
                    fputs("too many clients\n", stderr);
                    exit(1);
                }
                FD_SET(connfd, &allset); /* add new descriptor to set */
                if (connfd > maxfd)
                    maxfd = connfd; /* for select */
                if (i > maxi)
                    maxi = i; /* max index in client[] array */
                if (--nready == 0)
                    continue; /* no more readable descriptors */
            }
            for (i = 0; i <= maxi; i++) {
                /* check all clients 714 for data */
                if ( (sockfd = client[i]) < 0)
                    continue;
                if (FD_ISSET(sockfd, &rset)) {
                    if ( (n = Read(sockfd, buf, MAXLINE)) == 0) {
                        Close(sockfd);
                        FD_CLR(sockfd, &allset);
                        client[i] = -1;
                    } else {
                        int j;
                        for (j = 0; j < n; j++)
                            buf[j] = toupper(buf[j]);
                        Write(sockfd, buf, n);
                    }
                    if (--nready == 0)
                        break; /* no more readable descriptors */
                }
            }
        }
    }
    View Code
    #include <stdlib.h>
    #include <stdio.h>
    #include <errno.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <string.h>
    #include <unistd.h>
    
    void perr_exit(const char *s)
    {
        perror(s);
        exit(1);
    }
    
    int Accept(int fd, struct sockaddr *sa, socklen_t *salenptr)
    {
        int n;
    again:
        if ((n = accept(fd, sa, salenptr)) < 0) {
            if ((errno == ECONNABORTED) || (errno == EINTR))
                goto again;
            else 
                perr_exit("accept error");
        }
    
        return n;
    }
    
    void Bind(int fd, struct sockaddr *sa, socklen_t salen)
    {
        if (bind(fd, sa, salen) < 0)
            perr_exit("bind error");
    }
    
    void Connect(int fd, const struct sockaddr *sa, socklen_t salen)
    {
        if (connect(fd, sa, salen) < 0)
            perr_exit("connent error");
    }
    
    void Listen(int fd, int backlog)
    {
        if (listen(fd, backlog) < 0) 
            perr_exit("listen error");
    }
    
    int Socket(int family, int type, int protocol)
    {
        int n;
        if ((n = socket(family, type, protocol)) < 0) 
            perr_exit("socket error");
        return n;
    }
    
    ssize_t Read(int fd, void *ptr, size_t nbytes)
    {
        ssize_t n;
    again:
        if ((n = read(fd, ptr, nbytes)) < 0) {
            if (errno == EINTR)
                goto again;
            else 
                return -1;
        }
    
        return n;
    }
    
    ssize_t Write(int fd, const void *ptr, size_t nbytes)
    {
        ssize_t n;
    again:
        if ((n = write(fd, ptr, nbytes)) == -1) {
            if (errno == EINTR)
                goto again;
            else 
                return -1;
        }
    
        return n;
    }
    
    void Close(int fd)
    {
        if (close(fd) == -1)
            perr_exit("close error");
    }
    
    ssize_t Readn(int fd, void *vptr, size_t n)
    {
        size_t nleft;
        ssize_t nread;
        char *ptr;
    
        ptr = vptr;
        nleft = n;
        while (nleft > 0) {
            if ((nread = read(fd, ptr, nleft))  < 0) {
                if (errno == EINTR)
                    nread = 0;
                else 
                    return -1;
            } else if (nread == 0) {
                break;
            }
            nleft -= nread;
            ptr += nread;
        }
    
        return n - nleft;
    }
    
    ssize_t Writen(int fd, const void *vptr, size_t n)
    {
        size_t nleft;
    
        ssize_t nwritten;
        const char *ptr;
    
        ptr = vptr;
        nleft = n;
        while (nleft > 0) {
            if ((nwritten = write(fd, ptr, nleft)) <= 0) {
                if (nwritten < 0 && errno == EINTR)
                    nwritten = 0;
                else 
                    return -1;
            }
    
            nleft -= nwritten;
            ptr += nwritten;
        }
    
        return n;
    }
    
    static ssize_t my_read(int fd, char *ptr)
    {
        static int read_cnt;
        static char *read_ptr;
        static char read_buf[100];
    
        if (read_cnt <= 0) {
        again:
            if ((read_cnt = read(fd, read_buf, sizeof(read_buf))) < 0) {
                if (errno == EINTR)
                    goto again;
                return -1;
            } else if (read_cnt == 0)
                return 0;
            read_ptr = read_buf;
        }
        read_cnt--;
        *ptr = *read_ptr++;
        return 1;
    }
    
    ssize_t Readline(int fd, void *vptr, size_t maxlen)
    {
        ssize_t n, rc;
        char c, *ptr;
    
        ptr = vptr;
        for (n = 1; n < maxlen; n++) {
            if ((rc = my_read(fd, &c)) == 1) {
                *ptr++ = c;
                if (c == '\n') 
                    break;
            } else if (rc == 0) {
                *ptr = 0;
                return n - 1;
            } else {
                return -1;
            }
        }
        *ptr = 0;
        return n;
    }
    View Code

    2.说明

    由于当前做的项目需要做到高速高效率传输,所以就使用lwip的select封装了一套TCP服务器程序

    也推荐大家伙使用此程序作为TCP服务器,这样子的话以后只要做类似的项目用这个底层就可以了.

    下载程序到开发板

    1.把这节的代码放到英文目录

    2.鼠标右键选择使用VScode打开

    3.关于部分配置

    用户进到此函数文件里面可以配置模块热点名称和模块连接的路由器信息

    如果不需要连接路由器也不需要修改,顶多是内部连接不上而已.

     

    用户可以在这里设置TCP服务器监听的端口号: 现在监听的是8888

    4.编译下载到开发板(第一次编译时间有点长)

    测试

    1.程序下载以后会有个名称为  ESP32_WIFI   的热点

    2.如果让模块连接了路由器,日志里面也会打印连接路由器之后的信息

    3.提示

    如果大家伙使用手机或者电脑连接模组的热点进行测试,

    那么模组的TCP服务器的IP地址是:192.168.4.1  端口号是:8888

    我现在电脑和模组在一个路由器下哈,我就使用那个192.168.0.102地址测试

    4.打开网络调试助手测试

    程序里面写的是接收到什么数据就返回什么数据

    再加个客户端

    程序使用说明(先说下如何使用)

    1.如果用户需要移植使用的话直接把下面的文件放到自己的工程里面就可以

    2.创建TCP服务器(各个参数见下下图)

     

     

    3.服务器接收到数据在这个里面(这个函数是在TCP监听任务里面的,注意不要在这个里面阻塞哈) 

    4.关于发送数据给客户端

    1,发送数据给客户端有两个函数  tcp_server_select_write  和  tcp_server_select_send

    2, tcp_server_select_write 就是上面说的只能在接收数据里面调用才可以使用

    3,假设现在需要把串口接到的数据发送给所有TCP客户端  tcp_server_select_send(-1, 数据地址,数据长度)

    4,假设现在需要把串口接到的数据发送给指定的TCP客户端,则需要先在接收函数里面获取客户端的 index

    我只是举例子哈,一般是接收到什么数据以后再去赋值后面的数据发给哪个客户端

    程序说明

    1,创建TCP服务器

    2,TCP服务器监听任务,在里面监听连接 和 接收数据

    3,发送数据

    发送数据是使用 Ringbuffer + 信号量 + 任务

    发送数据的时候是把数存储到 Ringbuffer 然后 信号量 +1

    任务里面获取信号量然后获取缓存里面的数据,然后发送数据给客户端

  • 相关阅读:
    using关键字的使用
    浅谈重写、重载、继承、多态
    ASP.NET控件之Content控件
    CommandArgument用法
    sql语句导入导出大全
    常用正则表达式
    做饭71技巧
    SQL Server 阻止了对组件 'Ad Hoc Distributed Queries' 的 STATEMENT'OpenRowset/OpenDatasource' 的访问,因为此组件已作为此服务器安全配置的一部分而被关闭。系统管理员
    如何成为一个技术“牛人”
    Yahoo! Media Player 将播放器放在自己网站上
  • 原文地址:https://www.cnblogs.com/yangfengwu/p/15669119.html
Copyright © 2020-2023  润新知