飞凌嵌入式ElfBoard-网络编程示例之网络socket编程示例-tcp协议程序

1.tcp服务端

#include <errno.h>

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <unistd.h>

#include <fcntl.h>

#include <netinet/tcp.h>

#include <sys/socket.h>

#include <net/if.h>

#include <arpa/inet.h>

#include <termios.h> /*PPSIX 终端控制定义*/

#define CREATE_TURE 1

#define CREATE_FALSE 0

/*

 * @description  : 检测TCP服务端连接状态

 * @param - fd   : 文件描述符

 * @return  : 执行结果 链接断返回-1 正常返回0

 */

int func_detect_tcp_server_link(int fd)

{

    int info_len = 0, re_err = 0;

    struct tcp_info info;

    info_len = sizeof(struct tcp_info);

    getsockopt(fd, IPPROTO_TCP, TCP_INFO, (void *)&info, (socklen_t *)&info_len);

    if (info.tcpi_state != TCP_ESTABLISHED) {

        re_err = -1;

    }

    return re_err;

}

/*

 * @description  : 建立TCP服务端监听

 * @param - *fd  : 监听文件描述符

 * @param - listen_port: 监听端口

 * @return  : 执行结果 创建失败返回-1 正常返回0

 */

int func_create_tcp_server_listen(int *fd, unsigned int listen_port)

{

    int value = 0, Flags = 0;

    struct sockaddr_in servaddr;

    /*(1) 创建套接字*/

    if ((*fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {

        return -1;

    }

    //设置为非阻塞

    Flags = fcntl(*fd, F_GETFL, 0);

    fcntl(*fd, F_SETFL, Flags | O_NONBLOCK);

    setsockopt(*fd, SOL_SOCKET, SO_REUSEADDR, &Flags, sizeof(int));

    /*(2) 设置服务器sockaddr_in结构*/

    bzero(&servaddr, sizeof(servaddr));

    servaddr.sin_family = AF_INET;

    servaddr.sin_addr.s_addr = htonl(INADDR_ANY); //

    servaddr.sin_port = htons(listen_port);

    /*(3) 绑定套接字和端口*/

    if (bind(*fd, (struct sockaddr *)&servaddr, sizeof(struct sockaddr)) == -1) {

        printf("Bind error%s\n", strerror(errno));

        value = -1;

        return value;

    }

    /*(4) 监听客户请求*/

    if (listen(*fd, 10) < 0) {

        printf("listen error%s\n", strerror(errno));

        value = -1;

        return value;

    }

    value = 1;

    return value;

}

/*

 * @description  : TCP服务端与客户端建立链接

 * @param - listen_fd: 监听文件描述符

 * @param - *fd  : 链接文件描述符

 * @param - *ip  : 客户端ip,用于ip过滤

 * @return  : 执行结果 无错误返回1 出现错误返回-1

 */

int func_tcp_server_accept(int listen_fd, int *fd, char *ip)

{

    struct sockaddr_in clientddr;

    socklen_t clilen = 0;

    int tempfd = 0, Flags = 0, value = 0;

    char temp_ip[16] = {0};

    unsigned int temp_port;

    bzero(&clientddr, sizeof(clientddr));

    clilen = sizeof(clientddr);

    //检测跟客户端建立链接是否成功

    if ((tempfd = accept(listen_fd, (struct sockaddr *)&clientddr, &clilen)) < 0) {

        return value;

    }

    //检测建立链接的客户端IP是否与设置的相同,此处不判别,将接收所有IP请求建立链接。

    memcpy(temp_ip, inet_ntoa(clientddr.sin_addr), 16);

    temp_port = ntohs(clientddr.sin_port);

    printf("client: IP=%s, port=%d\n", temp_ip, temp_port);

    if (memcmp(ip, temp_ip, 16) != 0) {

        close(tempfd);

        return value;

    }

    if (*fd > 0) {

        close(*fd);

    }

    //设置为非阻塞

    Flags = fcntl(tempfd, F_GETFL, 0);

    fcntl(tempfd, F_SETFL, Flags | O_NONBLOCK);

    *fd = tempfd;

    value = 1;

    return value;

}

/*

 * @description  : TCP服务端接收数据函数

 * @param - fd   : 链接文件描述符

 * @param - *p_receive_buff: 接收数据缓冲区首地址

 * @param - count: 最大接收长度

 * @return  : 实际接收数据长度

 */

int func_tcp_server_receive(int fd, char *p_receive_buff, int count)

{

    int receive_numb = 0;

    memset(p_receive_buff, 0x0, count);

    receive_numb = recv(fd, p_receive_buff, count, 0);

    return receive_numb;

}

/*

 * @description  : TCP服务端发送数据函数

 * @param - fd   : 链接文件描述符

 * @param - *p_send_buff: 发送数据缓冲区首地址

 * @param - count: 发送数据长度

 * @return  : 实际发送数据长度

 */

int func_tcp_server_send(int fd, char *p_send_buff, int count)

{

    int send_numb = 0;

    if (func_detect_tcp_server_link(fd) != 0) {  /*发送数据之前先检查链接状态*/

        printf("ReadCwnd judge connect break\n");

        return -1;

    }

    send_numb = write(fd, p_send_buff, count);

    if (count != send_numb) {

        printf("server terminated prematurely write err\n");

        return -1;

    }

    return send_numb;

}

/*

 * @description  : 主函数

 * @return  : 执行结果

 */

int main(int argc, char *argv[])

{

    char receive_buff[20];

    char send_buff[20] = "server test network";

    int receive_num = 0;

    unsigned int establish_listen = CREATE_FALSE;

    int sockfd, listenfd;

    int result = 0;

    int real_send_num = 0;

    while (1) {

        if (establish_listen == CREATE_FALSE) {

            // TCP做服务端,建立监听

            result = func_create_tcp_server_listen(&listenfd, 2404);

            if (result > 0) {

                establish_listen = CREATE_TURE;

                printf("tcp create server listen ok\n");

            } else {

                if (listenfd > 0) {

                    close(listenfd);

                }

            }

        } else {

            //接受客户端建立链接

            result = func_tcp_server_accept(listenfd, &sockfd, "192.168.0.2");

            if (result > 0) {

                printf("tcp connected\n");

                break;

            }

        }

    }

    while (1) {

        //接收数据

        receive_num = func_tcp_server_receive(sockfd, receive_buff, sizeof(receive_buff));

        if (receive_num > 0) {

            printf("[nread= %d] = %s\n", receive_num, receive_buff);

            //发送数据

            real_send_num = func_tcp_server_send(sockfd, send_buff, sizeof(send_buff));

            if (real_send_num > 0) {

                printf("[nwrite=%d] = %s\n", real_send_num, send_buff);

            } else {

                close(sockfd);

                printf("tcp server disconnect");

                break;

            }

        }

        usleep(1000); // 1ms

    }

    exit(0);

}

服务端仍然是按照如下顺序进行编写:

socket()//创建套接字;

bind()//分配套接字地址;

listen()//等待连接请求状态;

accept()//允许连接;

read()/write()//进行数据交换;

close()//断开连接;

需要注意我们在检测建立链接的客户端IP是否与设置的相同时没有做判别,将接收所有IP请求建立链接。下面我们看下详细解释:

func_detect_tcp_server_link(int fd): 检测 TCP 服务端连接状态的函数。它接受一个文件描述符 fd,通过调用 getsockopt 函数获取与该文件描述符相关的 TCP 连接信息,并判断连接状态是否为已建立(TCP_ESTABLISHED)。如果连接状态为已建立,则返回 0;否则返回-1。

func_create_tcp_server_listen(int *fd, unsigned int listen_port): 建立 TCP 服务端监听的函数。它接受一个指向监听文件描述符的指针 fd,以及监听的端口号 listen_port。函数首先创建一个套接字,并将其设置为非阻塞模式。然后,通过调用 bind 函数将套接字绑定到指定的端口上,并通过调用 listen 函数开始监听客户端请求。如果操作成功,返回 0;否则返回-1。

func_tcp_server_accept(int listen_fd, int *fd, char *ip): TCP 服务端与客户端建立连接的函数。它接受一个监听文件描述符 listen_fd,一个指向连接文件描述符的指针 fd,以及一个用于 IP 过滤的客户端 IP 地址 ip。函数通过调用 accept 函数接受客户端的连接请求,并检查建立连接的客户端 IP 是否与设置的 IP 相同。如果 IP 相同,将连接文件描述符赋值给 fd,并返回1;否则返回0。

func_tcp_server_receive(int fd, char *p_receive_buff, int count): TCP 服务端接收数据的函数。它接收一个连接文件描述符 fd,一个指向接收数据缓冲区的指针 p_receive_buff,以及最大接收长度 count。函数通过调用 recv 函数接收数据,并返回实际接收到的数据长度。

func_tcp_server_send(int fd, char *p_send_buff, int count): TCP 服务端发送数据的函数。它接收一个连接文件描述符 fd,一个指向发送数据缓冲区的指针 p_send_buff,以及发送数据的长度 count。函数首先调用 func_detect_tcp_server_link 函数检测连接状态,如果连接已断开,则返回 -1。然后通过调用 write 函数将数据发送给客户端,并返回实际发送的数据长度。如果发送的数据长度与指定的长度不一致,表示发送过程中出现错误,返回-1。

2.tcp客户端

#include <errno.h>

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <unistd.h>

#include <fcntl.h>

#include <netinet/tcp.h>

#include <sys/socket.h>

#include <net/if.h>

#include <arpa/inet.h>

#include <termios.h> /*PPSIX 终端控制定义*/

#define CONNECT 1

#define DISCONNECT 0

/*

 * @description  : 检测TCP客户端连接状态

 * @param - fd   : 文件描述符

 * @return  : 执行结果 链接断返回-1 正常返回0

 */

int func_detect_tcp_client_link(int fd)

{

    int info_len = 0, re_err = 0;

    struct tcp_info info;

    info_len = sizeof(struct tcp_info);

    getsockopt(fd, IPPROTO_TCP, TCP_INFO, (void *)&info, (socklen_t *)&info_len);

    if (info.tcpi_state != TCP_ESTABLISHED) {

        re_err = -1;

    }

    return re_err;

}

/*

 * @description  : TCP客户端与服务端建立链接

 * @param - *fd  : 链接文件描述符

 * @param - *ip  : 服务端ip,

 * @param - port : 服务端端口,

 * @return  : 执行结果 链接成功返回0 连接失败返回-1

 */

int func_create_tcp_client_link(int *fd, char *ip, unsigned int port)

{

    int value = 0, Flags = 0;

    struct sockaddr_in servaddr;

    fd_set set;

    struct timeval timeout;

    //设置建立连接等待时间

    timeout.tv_sec = 30;

    timeout.tv_usec = 0;

    /*(1) 创建套接字*/

    if ((*fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {

        value = -1;

        return value;

    }

    /*(2) 设置链接服务器地址结构*/

    bzero(&servaddr, sizeof(servaddr));

    servaddr.sin_family = AF_INET;

    servaddr.sin_addr.s_addr = inet_addr(ip);

    servaddr.sin_port = htons(port);

    //设置为非阻塞

    Flags = fcntl(*fd, F_GETFL, 0);

    fcntl(*fd, F_SETFL, Flags | O_NONBLOCK);

    /*(3) 发送链接服务器请求*/

    if (connect(*fd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) {

        FD_ZERO(&set);

        FD_SET(*fd, &set);

        if (select((*fd) + 1, NULL, &set, NULL, &timeout) > 0) {

            if (func_detect_tcp_client_link(*fd) == -1)

                return -1;

            else

                value = 0;

        } else {

            value = -1;

            return value;

        }

    }

    return value;

}

/*

 * @description  : TCP客户端接收数据函数

 * @param - fd   : 链接文件描述符

 * @param - *p_receive_buff: 接收数据缓冲区首地址

 * @param - count: 最大接收长度

 * @return  : 实际接收数据长度

 */

int func_tcp_client_receive(int fd, char *p_receive_buff, int count)

{

    int receive_numb = 0;

    memset(p_receive_buff, 0x0, count);

    receive_numb = recv(fd, p_receive_buff, count, 0);

    return receive_numb;

}

/*

 * @description  : TCP客户端发送数据函数

 * @param - fd   : 链接文件描述符

 * @param - *p_send_buff: 发送数据缓冲区首地址

 * @param - count: 发送数据长度

 * @return  : 实际发送数据长度

 */

int func_tcp_client_send(int fd, char *p_send_buff, int count)

{

    int send_numb = 0;

    if (func_detect_tcp_client_link(fd) != 0) {

        printf("ReadCwnd judge connect break\n");

        return -1;

    }

    send_numb = write(fd, p_send_buff, count);

    if (count != send_numb) {

        printf("server terminated prematurely write err\n");

        return -1;

    }

    return send_numb;

}

/*

 * @description  : 主函数

 * @return  : 执行结果

 */

int main()

{

    char receive_buff[20];

    char send_buff[20] = "client test network";

    unsigned int connect_state = DISCONNECT;

    int real_send_num = 0;

    int receive_num = 0;

    int sockfd;

    int result = 0;

    if (connect_state == DISCONNECT) {

        // TCP做客户端,主动跟服务端建立链接

        result = func_create_tcp_client_link(&sockfd, "192.168.0.1", 2404);

        if (result >= 0) {

            connect_state = CONNECT;

            printf("tcp connected\n");

        }

    }

    while (1) {

        if (connect_state == CONNECT) {

            //发送数据

            real_send_num = func_tcp_client_send(sockfd, send_buff, sizeof(send_buff));

            if (real_send_num > 0) {

                printf("[nwrite=%d] = %s\n", real_send_num, send_buff);

                sleep(1);

                //接收数据

                receive_num = func_tcp_client_receive(sockfd, receive_buff, sizeof(receive_buff));

                if (receive_num > 0) {

                    printf("[nread= %d] = %s\n", receive_num, receive_buff);

                }

            } else {

                connect_state = DISCONNECT;

                printf("tcp client disconnect");

                close(sockfd);

            }

        } else

            break;

    }

    exit(0);

}

func_detect_tcp_client_link(int fd): 检测 TCP 客户端连接状态的函数。它通过获取套接字的 TCP 状态信息,判断连接是否已经建立。如果连接状态为 TCP_ESTABLISHED(已建立连接),则返回 0;否则返回 -1。

func_create_tcp_client_link(int *fd, char *ip, unsigned int port): TCP 客户端与服务端建立连接的函数。它接受一个指向文件描述符的指针 fd,一个服务端 IP 地址字符串 ip,以及服务端端口号 port。函数首先创建一个套接字,然后设置服务器地址结构,尝试与服务端建立连接。如果连接成功,返回 0;连接失败返回 -1。

func_tcp_client_receive(int fd, char *p_receive_buff, int count): TCP 客户端接收数据的函数。它接收一个文件描述符 fd,一个指向接收数据缓冲区的指针 p_receive_buff,以及最大接收长度 count。函数通过调用 recv 函数接收数据,并返回实际接收到的数据长度。

func_tcp_client_send(int fd, char *p_send_buff, int count): TCP 客户端发送数据的函数。它接收一个文件描述符 fd,一个指向发送数据缓冲区的指针 p_send_buff,以及发送数据长度 count。函数首先调用 func_detect_tcp_client_link 检测连接状态,如果连接断开,则返回 -1。否则,调用 write 函数发送数据,并返回实际发送的数据长度。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值