tcp与串口透传(select)
介绍
tcp作为服务端,监听端口8888,实现串口透传,这里是使用select监听tcp的receive和串口的read,单工通信
- -p 指定tcp端口
- -s 指定串口
- -b 指定波特率 支持4800 9600 115200
- -? 打印具体用法
程序
#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;
}
tcp与串口透传(select)的更多相关文章
- CC1101 433无线模块,STM8串口透传
CC1101 433无线模块,STM8串口透传 原理图:http://download.csdn.net/detail/cp1300/7496509 下面是STM8程序 CC1101.C /*** ...
- ESP8266局域网 路由器下作服务器模式串口透传 arduino uno示例 模板参考2
ESP8266服务器模式串口透传编译需要下载8266的库文件后才可以正常 准备工作 下载一个Arduino IDE,下载8266的库文件ESP8266服务器模式串口透传编译 功能说明 1.直接使用路由 ...
- ESP8266局域网智能家居 路由器下作服务器模式串口透传 无线通信控制 arduino uno示例 模板参考
准备工作 下载一个Arduino IDE, 下载8266的库文件 ESP8266服务器模式串口透传编译 功能说明 1.直接使用路由器中转数据 2.手机放热点模式直接传输数据 两者有访问IP地址的差别, ...
- 18-ESP8266 SDK开发基础入门篇--TCP 服务器 RTOS版,串口透传,TCP客户端控制LED
https://www.cnblogs.com/yangfengwu/p/11112015.html 先规定一下协议 aa 55 02 01 F1 4C 控制LED点亮 F1 4C为CRC高位和低位 ...
- 16-ESP8266 SDK开发基础入门篇--TCP 服务器 非RTOS运行版,串口透传(串口回调函数处理版)
https://www.cnblogs.com/yangfengwu/p/11105466.html 其实官方给的RTOS的版本就是在原先非RTOS版本上增加的 https://www.cnblogs ...
- PHP workerMan tcp与webSocket 透传互通
<?php $work_path = dirname(__FILE__); chdir($work_path); use \Workerman\Worker; use \Workerman\Li ...
- wifi实现串口透传
环境: 串口服务器Ip:172.16.1.11 串口客户机ip:172.16.1.12 一.网络连接示意图 二.串口服务器的配置 参考:ser2net的编译及测试 三.串口客户端的配置 实际上这是一个 ...
- python 串口 透传
python正常情况通过串口 serial 传输数据的时候,都是以字符串的形式发送的 str = ‘abcd’ ser.write(str.encode())#直接发送str报错,需要发送byte类 ...
- 蓝牙4.0BLE 手机控制 cc2540 CC2541 的串口透传功能已实现
蓝牙4.0BLE 手机控制 cc2540 CC2541 的串口透传功能已实现 尽管蓝牙4.0 BLE芯片CC2540 是单芯片(即用户能够对它进行芯片级代码编写), 是80 ...
随机推荐
- 11、Spring Boot 2.x 集成 HBase
1.11 Spring Boot 2.x 集成 HBase 完整源码: Spring-Boot-Demos
- python自动华 (十八)
Python自动化 [第十八篇]:JavaScript 正则表达式及Django初识 本节内容 JavaScript 正则表达式 Django初识 正则表达式 1.定义正则表达式 /.../ 用于定 ...
- 查找、AVL树、散列表
插值查找是二分查找的改进,斐波那契查找是插值查找的改进. 二分查找:mid=(low+high)/ 2 插值查找:mid=(key-a[low])*(high-low)/ (a[high]-a[l ...
- ES6-3 变量的解构赋值
1.数组的解构赋值 数组的解构赋值其实是=左右进行“模式匹配”. ❗️❗️❗️=右侧是具体的数值,不是变量!,=左侧的是变量!如果右侧是变量形式,需要先计算出具体的数值!! let [a,[b],c] ...
- RX232串口发送
在进行工程调试的时候有时候需要对变量进行观察,SingnaTap II Logic Analyzer 只能对管脚进行观察,所以要观察内部的变量必须把内部的变量进行输出.一种方法是直接把变量定义成管脚通 ...
- C语言学习笔记8-函数
C语言学习笔记8-函数 ...待编辑 1.汇编看函数调用过程 2.函数调用过程图示:学好C这个是关键,要懂得原理 标准调用(_cdecl) 参数由右往左入栈,调用者平衡栈(即入多少参数后参数调用玩后 ...
- Jenkins 插件加速下载
本文主旨 看到好多加速Jenkins安装插件速度的文章,大多数教程中都是在插件配置里使用 https://mirrors.tuna.tsinghua.edu.cn/jenkins/updates/up ...
- JAVA导入支持类
导入支持类(可以是JDK基础类或者自己编写的类),可以供本类调用方法和属性. java中import用法: 1.单类型导入(single-type-import),例如import java.io.F ...
- 《你不知道的JavaScript(上)》笔记——动态作用域
动态作用域让作用域作为一个在运行时就被动态确定的形式, 而不是在写代码时进行静态确定的形式.动态作用域并不关心函数和作用域是如何声明以及在何处声明的, 只关心它们从何处调用. 换句话说, 作用域链是基 ...
- cookie和session的区别及其原理
1.为什么要有cookie/session? HTTP是一种无状态的协议,为了分辨链接是谁发起的,需自己去解决这个问题.不然有些情况下即使是同一个网站每打开一个页面也都要登录一下.而Session和C ...