tcp与串口透传(select)

介绍#

tcp作为服务端,监听端口8888,实现串口透传,这里是使用select监听tcp的receive和串口的read,单工通信

  • -p 指定tcp端口
  • -s 指定串口
  • -b 指定波特率 支持4800 9600 115200
  • -? 打印具体用法

程序#

Copy
#include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h> #include <unistd.h> #include <fcntl.h> #include <unistd.h> #include <stdio.h> #include <string.h> #include <errno.h> #include <stdlib.h> #include <linux/serial.h> #include <sys/ioctl.h> #include <sys/select.h> #include <unistd.h> #include <termios.h> void Test_err(int flg) { if(flg<0) { perror(strerror(errno)); exit(1); } } int main(int argc, char** argv) { printf("usage : %s ?\n",argv[0]); short listenPort=8888; unsigned char uart_port[100]={"/dev/ttyS2"}; int bps=0; unsigned int baudRate= B9600; int opt; while ((opt=getopt(argc,argv,"p:s:b:?")) != -1) { switch (opt) { case 'p': listenPort = atoi(optarg); break; case 's': memset(uart_port,0,sizeof(uart_port)); strncpy(uart_port,optarg,99); break; case 'b': bps = atoi(optarg); break; default: /* '?' */ fprintf(stderr, "Usage: %s [-p port -s serial port -b baund] \n", argv[0]); exit(EXIT_FAILURE); } } switch(bps) { case 4800: baudRate=B4800; break; case 19200: baudRate=B19200; break; case 38400: baudRate=B38400; break; case 57600: baudRate=B57600; break; case 115200: baudRate=B115200; break; default: baudRate=B9600; bps=9600; break; } printf("tcp-server...enter\n"); printf("set uartport is %d\n",bps); printf("set uartspeed is %s\n",uart_port); printf("set tcpport is %d\n",listenPort); // uart-------------------------------------------------------- int uart_fd=open(uart_port, O_RDWR | O_NOCTTY | O_NDELAY); struct termios newtio; memset(&newtio,0, sizeof( newtio )); newtio.c_cflag=0; newtio.c_iflag=0; newtio.c_cflag |= CLOCAL | CREAD; newtio.c_cflag &= ~CSIZE; newtio.c_cflag |= CS8; newtio.c_cflag &= ~PARENB; newtio.c_cflag &= ~CSTOPB; newtio.c_cc[VTIME] = 0; newtio.c_cc[VMIN] = 0; cfsetispeed(&newtio, baudRate); cfsetispeed(&newtio, baudRate); tcflush(uart_fd,TCIFLUSH); if((tcsetattr(uart_fd,TCSANOW,&newtio))!=0) { perror("uart open error\n"); return -1; } int portfd; #if (__GNUC__ == 4 && __GNUC_MINOR__ == 3) struct my_serial_rs485 rs485conf; struct my_serial_rs485 rs485conf_bak; #else struct serial_rs485 rs485conf; struct serial_rs485 rs485conf_bak; #endif portfd=uart_fd; /* Driver-specific ioctls: ...\linux-3.10.x\include\uapi\asm-generic\ioctls.h */ #define TIOCGRS485 0x542E #define TIOCSRS485 0x542F if (ioctl (portfd, TIOCGRS485, &rs485conf) < 0) { /* Error handling.*/ // Log::Inf("ioctl TIOCGRS485 error.\n"); printf( "[ERR] ioctl TIOCGRS485 error.\n"); } /* Enable RS485 mode: */ rs485conf.flags |= SER_RS485_ENABLED; /* Set logical level for RTS pin equal to 1 when sending: */ rs485conf.flags |= SER_RS485_RTS_ON_SEND; //rs485conf.flags |= SER_RS485_RTS_AFTER_SEND; /* set logical level for RTS pin equal to 0 after sending: */ rs485conf.flags &= ~(SER_RS485_RTS_AFTER_SEND); //rs485conf.flags &= ~(SER_RS485_RTS_ON_SEND); /* Set rts delay after send, if needed: */ rs485conf.delay_rts_after_send = 0x80; if (ioctl (portfd, TIOCSRS485, &rs485conf) < 0) { /* Error handling.*/ printf("ioctl TIOCSRS485 error.\n"); } if (ioctl (portfd, TIOCGRS485, &rs485conf_bak) < 0) { /* Error handling.*/ printf("ioctl TIOCGRS485 error.\n"); } /*----------------------------------------------------*/ unsigned char test_msg[]="this is send by uart\n"; int uart_sent_cnt = write(uart_fd, test_msg, sizeof(test_msg)); // tcp-------------------------------------------------------- int listen_fd=-1; int accept_fd=-1; int flags; int max_listen_num=10; unsigned char r_buf[255]; int n; struct sockaddr_in server_addr; struct sockaddr_in clinet_addr; listen_fd=socket(AF_INET, SOCK_STREAM, 0); Test_err(listen_fd); memset(&server_addr,0,sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_addr.s_addr = htonl(INADDR_ANY); server_addr.sin_port = htons(listenPort); int i = 1;/* 允许重复使用本地地址与套接字进行绑定 */ setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i)); flags=bind(listen_fd, (struct sockaddr *)&server_addr,sizeof(struct sockaddr)); Test_err(flags); flags= listen(listen_fd, max_listen_num); Test_err(flags); int clinet_addr_len=sizeof(clinet_addr); __ACCEPT_AGAIN__: accept_fd= accept(listen_fd, (struct sockaddr *)&clinet_addr, &clinet_addr_len); // show clinet message printf("accept_fd is %d \n",accept_fd); printf("port=%d\n",ntohs(clinet_addr.sin_port)); unsigned char strbuf[20]; inet_ntop(AF_INET,&clinet_addr.sin_addr,strbuf,sizeof(strbuf)); printf("ip=%s\n",strbuf); memset(r_buf , 0, sizeof(r_buf)); int maxfd; fd_set rset, allset; struct timeval tv; FD_ZERO(&allset); FD_SET(uart_fd, &allset); FD_SET(accept_fd, &allset); memset(&tv, 0, sizeof(tv)); tv.tv_usec = 1000 * 1000; int len=0; while (accept_fd) { rset=allset; maxfd=(accept_fd>uart_fd?accept_fd:uart_fd); flags=select(maxfd + 1, &rset, NULL, NULL, &tv); Test_err(flags); // get from tcp>>>>>uart if (FD_ISSET(accept_fd, &rset)) { n = recv(accept_fd, r_buf, 100, 0); Test_err(n); if(n) { //write(0,r_buf,n); printf("Get from tcp %d\n",n); write(uart_fd,r_buf,n); } else { printf("socket is disconnect\n"); goto __ACCEPT_AGAIN__; } } // get from uart>>>>tcp else if (FD_ISSET(uart_fd, &rset)) { usleep(100000);//100ms 这里等待接受多一点的数据 int ret = read(uart_fd, (char*)r_buf,sizeof(r_buf)); if (ret < 0) { if ((errno == EAGAIN) || (errno == EWOULDBLOCK) || (errno == EINTR)) { printf("Serial,read timeout error:%s. ignore ti!!!", strerror(errno)); ret = 0; } } else { printf("Get from uart %d\n",ret); send(accept_fd, r_buf, ret, 0); } } } printf("tcp-server...exit\n"); return 0; }
posted @   zongzi10010  阅读(3935)  评论(0编辑  收藏  举报
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?
点击右上角即可分享
微信分享提示
CONTENTS