前言
日常开发除了串口还有网口也用来作为常用的协议收发端口,补充常见的网口编程
基本概念
该博客写的比较清晰了
https://www.cnblogs.com/luoxiao23/p/11545363.html#:~:text=Linux%E4%B8%AD%E7%9A%84%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B%E9%80%9A%E8%BF%87Socket%20%28%E5%A5%97%E6%8E%A5%E5%AD%97%29%E6%8E%A5%E5%8F%A3%E5%AE%9E%E7%8E%B0%EF%BC%8CSocket%E6%98%AF%E4%B8%80%E7%A7%8D%E6%96%87%E4%BB%B6%E6%8F%8F%E8%BF%B0%E7%AC%A6%E3%80%82,%E6%B5%81%E5%BC%8F%E7%9A%84%E5%A5%97%E6%8E%A5%E5%AD%97%E5%8F%AF%E4%BB%A5%E6%8F%90%E4%BE%9B%E5%8F%AF%E9%9D%A0%E7%9A%84%E3%80%81%E9%9D%A2%E5%90%91%E8%BF%9E%E6%8E%A5%E7%9A%84%E9%80%9A%E8%AE%AF%E6%B5%81%E3%80%82%20%E5%AE%83%E4%BD%BF%E7%94%A8%E4%BA%86TCP%E5%8D%8F%E8%AE%AE%E3%80%82%20TCP%E4%BF%9D%E8%AF%81%E4%BA%86%E6%95%B0%E6%8D%AE%E4%BC%A0%E8%BE%93%E7%9A%84%E6%AD%A3%E7%A1%AE%E6%80%A7%E5%92%8C%E9%A1%BA%E5%BA%8F%E6%80%A7%E3%80%82
代码
tcp client写法:
#include "eth.h" #define SERVER_PORT 8080 // #define SERVER_IP "192.168.119.100" //服务器IP地址 int listen_fd = -1; void signal_handler(int arg) { printf("close listen_fd(signal = %d)\n", arg); close(listen_fd); exit(0); } /*描述 :网口发送线程 *参数 :arg 无参数传入 *返回值:无 *注意 :使用需打开网口服务器端 */ HI_VOID * eth_client_send_task(HI_VOID *arg) { int connect_fd = -1; struct sockaddr_in server; socklen_t saddrlen = sizeof(server); memset(&server, 0, sizeof(server)); connect_fd = socket(AF_INET, SOCK_STREAM, 0); if (connect_fd < 0) { printf("socket error!\n"); // return NULL; } printf("\nETH CLIENT SEND TEST\n"); server.sin_family = AF_INET; server.sin_port = htons(SERVER_PORT); server.sin_addr.s_addr = inet_addr(SERVER_IP); if (connect(connect_fd, (struct sockaddr *)&server, saddrlen) < 0) { printf("connect failed!\n"); // return -1; } char sendbuf[1024]="HelloWorld1234567890"; while (1) { sleep(1); write(connect_fd, sendbuf, sizeof(sendbuf)); } close(connect_fd); return 0; } /*描述 :网口接收线程 *参数 :arg 无参数传入 *返回值:无 *注意 :使用需打开网口服务器端 */ HI_VOID * eth_client_recv_task(HI_VOID *arg) { cpu_set_t mask;//cpu核的集合 cpu_set_t get;//获取在集合中的cpu int num = sysconf(_SC_NPROCESSORS_CONF); printf("frame_check_task:system has %d processor(s)\n", num); CPU_ZERO(&mask);//置空 CPU_SET(0, &mask);//设置亲和力值 if (pthread_setaffinity_np(pthread_self(), sizeof(mask), &mask) < 0)//设置线程CPU亲和力 { fprintf(stderr, "set thread affinity failed\n"); } if (pthread_getaffinity_np(pthread_self(), sizeof(get), &get) < 0)//获取线程CPU亲和力 { fprintf(stderr, "get thread affinity failed\n"); } int connect_fd = -1; int recv_len,i; struct sockaddr_in server; socklen_t saddrlen = sizeof(server); uint8 data_header[] = {0x55, 0xAA}; unsigned char addchk=0; // uint8 data_header[] = {0x55, 0xAA}; // printf("\nbeforen DataParser\n "); DataParser *data_parser = parser_init(data_header, sizeof(data_header), NULL, 0, CMD_LENGTH); // printf("\nDataParser INIT SUCCESS\n "); char* tmp_cmd=(char*)&g_trk_cmd; memset(&server, 0, sizeof(server)); connect_fd = socket(AF_INET, SOCK_STREAM, 0); if (connect_fd < 0) { printf("socket error!\n"); // return NULL; } printf("\nETH CLIENT RECV TEST\n"); server.sin_family = AF_INET; server.sin_port = htons(SERVER_PORT); // server.sin_addr.s_addr = inet_addr(SERVER_IP); server.sin_addr.s_addr = inet_addr(server_ip); if (connect(connect_fd, (struct sockaddr *)&server, saddrlen) < 0) { printf("connect failed!\n"); // return -1; } // char PLATFORM_IP_SET[64]={0}; // char PLATFORM_IP_CMD[]="192.168.0.168"; // sprintf(PLATFORM_IP_SET,"ifconfig eth0 %s up",PLATFORM_IP_CMD); // system(PLATFORM_IP_SET); else { char recvbuf[1024]={0}; while (1) { recv_len = read(connect_fd, recvbuf, sizeof(recvbuf)); if(recv_len) { // printf("\nEth:recv origin data: "); // recvbuf[len] = '\0'; for (i = 0;i < recv_len ;i++) { // printf("%02x ",recvbuf[i]); if(parser_put_data(data_parser, recvbuf[i]) == RESULT_TRUE) { // printf("成功解析出一帧数据...\n"); // /* 一位一位取出解析后的数据 */ // g_trk_cmd.length = parser_get_data(data_parser, 0); // g_trk_cmd.CmdType = parser_get_data(data_parser, 1); // for (int ii = 0; ii < DATA_LENGTH ;ii++) // { // g_trk_cmd.Para[ii] = parser_get_data(data_parser, 2+ii); // } tmp_cmd=(char*)&g_trk_cmd; // memset_s(tmp_cmd, sizeof(g_trk_cmd)-sizeof(data_header), 0, sizeof(g_trk_cmd)-sizeof(data_header)); addchk = 0; for(int jj=0;jj<sizeof(g_trk_cmd)-sizeof(data_header);jj++) { tmp_cmd[jj+2]=parser_get_data(data_parser, jj); printf("%x ",tmp_cmd[jj+2]); } printf("\n"); for(int kk = 2;kk < sizeof(g_trk_cmd)-1;kk++) { // addchk += parser_get_data(data_parser, kk); addchk+=tmp_cmd[kk]; printf("%x ",tmp_cmd[kk]); } printf("\n"); printf("addchk is %x\n",addchk); g_trk_cmd.addchk = parser_get_data(data_parser,(CMD_LENGTH-1-2));//第19个数,从0开始计18,故-1,又因为去头在-2 printf("g_trk_cmd.addchk is %x\n",g_trk_cmd.addchk); if(addchk != g_trk_cmd.addchk ) { memset_s(((uint8_t*)&g_trk_cmd)+2, sizeof(g_trk_cmd)-sizeof(data_header), 0, sizeof(g_trk_cmd)-sizeof(data_header)); continue; } g_trk_cmd.length = tmp_cmd[2]; printf(" tmp_cmd[2]is %x\n",tmp_cmd[2]); g_trk_cmd.CmdType = tmp_cmd[3]; printf(" tmp_cmd[3]is %x\n",tmp_cmd[3]); for (int ii = 0; ii < DATA_LENGTH ;ii++) { g_trk_cmd.Para[ii] = tmp_cmd[ii+4];; } // printf("数据长度是0x%x\n", parser_get_data(data_parser, 0)); // printf("功能码是0x%x\n", parser_get_data(data_parser, 1)); // printf("具体功能是0x%x\n\n\n", parser_get_data(data_parser, 2)); } } // printf("\n"); } protocol_parser(); } close(connect_fd); } return 0; }
头文件
/************************************************************************************************ *****Describe: This program is writen to operate HI35xx eth devices. ***** *****Author: xin.han ***** *****Date: 2022-09-17 ***** *************************************************************************************************/ #ifndef _ETH_H_ #define _ETH_H_ #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <signal.h> #include <arpa/inet.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include "platform.h" #include "parser.h" #include "queue.h" /*描述 :网口发送线程 *参数 :arg 无参数传入 *返回值:无 *注意 :使用需打开网口服务器端 */ HI_VOID * eth_client_send_task(HI_VOID *arg); HI_VOID * eth_client_recv_task(HI_VOID *arg); HI_VOID * eth_server_task(HI_VOID *arg); #endif
还是新建收发线程,用网口助手进行模拟调试
/*描述 :网口接收线程
*参数 :arg 无参数传入
*返回值:无
*注意 :使用需打开网口服务器端
*/
tcp服务器端代码和udp的代码详见
https://blog.csdn.net/Mr_XJC/article/details/106788694
https://blog.csdn.net/YEDITABA/article/details/54635543
小bug
单纯的这样测试,在通路都正常的情况下,短时间是没有测出来问题的
但是有次忘记打开服务器端后,就会发现程序闪退了!
远程调试一下发现
J :k[i].[i].F575859// {// else ate :... 60 char sendbuf[1024]="HelloWorld1234567890"; while (1) sleep(1); write(connect fd, sendbuf, sizeof(sendbuf)); 出现异常。 x Broken pipe close(connect fd); // }
broken pipe最直接的意思是:写入端出现的时候,另一端却休息或退出了,因此造成没有及时取走管道中的数据,从而系统异常退出
那就很明显了,加个判断在链接成功的时候在执行收发操作
以后写代码还是得严谨,最基本的ifelse不能老是偷懒只写一半,不然真的可能积累不少没必要的错误经验