基于ARM开发板的简单串口服务器

串口服务器是为RS-232/485/422串口到TCP/IP网络之间完成数据转换的通讯接口转换器。提供RS-232/485/422终端串口与TCP/IP网络的数据双向透明传输,提供串口转网络功能,RS-232/485/422转网络的解决方案,可以让串口设备立即联接网络。

MOXA工业级串口服务器

MOXA工业级串口服务器

应用领域

门禁系统、考勤系统、售饭系统、 POS 系统、楼宇自控系统、自助银行系统电信机房监控,电力监控等。

产品特点

   ·体积小,火柴盒大小 
  ·支持RS232,RS485 
  ·10/100M以太网口 ,软件可升级 
  ·一个开关量输入,一个开关量输出 
  ·可作为TCP Server 或TCP Client ,UDP数据 
  ·内置WEB服务器,支持Java 
  ·支持多种异步串口格式 
  ·无需修改原有应用软件就可在网络环境下使用 
  ·将COM口定向至IP地址,每台计算机可同时拥有256个串口

工作方式

服务器方式:在该工作方式下,串口联网服务器作为TCP服务器端, 转换器在指定的TCP端口上监听平台程序的连接请求,该方式比较适合于一个转换器与多个平台程序建立连接(一个转换器不能同时与多个平台程序建立连接)。

客户端方式:在该工作方式下,串口联网服务器 作为 TCP 客户端,转换器上电时主动向平台程序请求连接,该方式比较适合于多个转换器同时向一个平台程序建立连接。

通讯模式

点对点通讯模式:该模式下,转换器成对的使用,一个作为服务器端,一个作为客户端,两者之间建立连接,实现数据的双向透明传输。该模式适用于将两个串口设备之间的总线连接改造为 TCP/IP 网络连接。
使用虚拟串口通讯模式:该模式下,一个或者多个转换器与一台电脑建立连接,实现数据的双向透明传输。由电脑上的虚拟串口软件管理下面的转换器,可以实现一个虚拟串口对应多个转换器, N 个虚拟串口对应 M 个转换器( N<=M )。该模式适用于串口设备由电脑控制的 485 总线或者 232 设备连接。
基于网络通讯模式: 该模式下,电脑上的应用程序基于SOCKET 协议编写了通讯程序,在转换器设置上直接选择支持 SOCKET 协议即可。

实现原理

这里写图片描述

ARM开发板
一般的开发板都可使用,只要带有网口(有线/无线)、串口。

这里写图片描述

开发板串口服务端源码

#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <pthread.h>
#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>
#include <fcntl.h>     
#include <termios.h>    /*PPSIX终端控制定义*/
#include <errno.h>      /*错误号定义*/


#define COM_FILE "/dev/ttySAC0"  //串口设备文件
#define PORT 8848
#define BACKLOG 5
#define MAXDATASIZE 128
#define BUFSIZE 512



void* net_proc(void* arg);//网络侦听服务

void* net_recv(void* arg);//接收网络客户端数据

void* net_send(void* arg);//发送数据到网络客户端数据

void* com_recv(void* arg);//串口接收处理

void* com_send(void* arg);//串口发送处理

int init_com(void);//初始化串口参数



struct ARG {
       int connfd;
       struct sockaddr_in client;
       };



static char net_buff[BUFSIZE];
static char com_buff[BUFSIZE];
int wr_index = 0;
int re_index = 0;

/**********************************
主函数
**********************************/
int main(void)
{

    int fd = 0;
    pthread_t net_th, com_r,com_s;

    memset(net_buff,0,BUFSIZE);
    memset(com_buff,0,BUFSIZE);


    if((fd = init_com())<=0){
      perror("init_com() error");
      exit(1);
    }       

    //网络服务器线程   

    if(pthread_create(&net_th, NULL, net_proc, NULL)){
      perror("pthread_creat() error");
      exit(1);
    } 

    //串口接收线程    

    if(pthread_create(&com_r, NULL, com_recv, (void*)&fd)){
      perror("pthread_creat() error");
      exit(1);
    }   

    //串口发送线程

    if(pthread_create(&com_s, NULL, com_send, (void*)&fd)){
      perror("pthread_creat() error");
      exit(1);
    }   

    pthread_join(net_th,NULL);
    pthread_join(com_r,NULL);
    pthread_join(com_s,NULL);       

}


/**********************************
网络服务端线程
**********************************/

void* net_proc(void* arg)

{

      int listenfd, connectfd;

      pthread_t thread;         //id of thread

      struct ARG *acc_arg;

      struct sockaddr_in server; //server's address info

      struct sockaddr_in client; //client's

      int sin_size;

//    int opt = SO_REUSEADDR;



      //create tcp socket

      printf("socket.... ");

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

          perror("creating socket failed.");

          exit(1);

      }



//    setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));      

      bzero(&server,sizeof(server));

      server.sin_family = AF_INET;

      server.sin_port = htons(PORT);

      server.sin_addr.s_addr = htonl(INADDR_ANY);

      printf("bind.... ");



      if(bind(listenfd,(struct sockaddr *)&server,sizeof(struct sockaddr)) == -1){

      perror("bind error.");

          exit(1);

      }  



      printf("listen.... ");

      if(listen(listenfd,BACKLOG) == -1) {

          perror("listen() error ");

          exit(1);

      }

      sin_size = sizeof(struct sockaddr_in);

      sleep(1);



      while(1){

          printf("accepting....\n ");

          if((connectfd = accept(listenfd,(struct sockaddr *)&client,(socklen_t*)&sin_size)) == -1) {

              perror("accept() error ");

              exit(1);

          }

          acc_arg =  malloc(sizeof(struct ARG));

          acc_arg->connfd = connectfd;

          memcpy((void *)&acc_arg->client, &client, sizeof(client));
          // 服务端接收客户端数据
          if(pthread_create(&thread, NULL, net_recv, (void*)acc_arg)){
              perror("pthread_creat() error");
              exit(1);
          }

          // 服务端向客户端发送数据
          if(pthread_create(&thread, NULL, net_send, (void*)acc_arg)){
              perror("pthread_creat() error");
              exit(1);
          }                         
      }

      close(listenfd);    

      return (0);

}

/**********************************
网络数据接收线程
**********************************/

void* net_recv(void* arg)

{   

    int connectfd;  

    int nbyte;

    char recvbuf[MAXDATASIZE];

    struct sockaddr_in client;
    struct ARG * n_arg = arg;   
    connectfd = n_arg->connfd;
    client = n_arg->client;  



    printf("IP: %s. \n",inet_ntoa(client.sin_addr) );

    //get client's name from client

    while(1){

        memset(recvbuf,0,MAXDATASIZE);  

        nbyte = recv(connectfd, recvbuf, MAXDATASIZE, 0);

        if(nbyte== 0 || nbyte == -1) {

            close(connectfd);

            perror("Client disconnected. ");

            break;

        }

        recvbuf[nbyte] = '\0';

        printf("fd=%d  nbyte=%d net recv: %s \n", connectfd,nbyte,recvbuf );

//      send(connectfd, recvbuf, strlen(recvbuf), 0);   //回传到客户端        

        //网络收到的数据,存到全局缓冲区

        strcat(net_buff,recvbuf);       

     }

}



/**********************************
网络数据发送线程
**********************************/

void* net_send(void* arg)

{   

    int connectfd;  

    int nbyte;

    struct ARG * n_arg = arg;   

    connectfd = n_arg->connfd;



    while(1){
        //发送串口收到的数据到网络客户端

        if(strlen(com_buff)>0)
        {
            nbyte = send(connectfd, com_buff, strlen(com_buff), 0);
            printf("net send nbyte=%d\n",nbyte);
            memset(com_buff, '\0', BUFSIZE);    
        }   

     }

}


/**********************************
串口初始化
**********************************/

int init_com(void)
{

    int fd_com;

    struct termios initial_settings, new_settings;  

    fd_com = open(COM_FILE, O_RDWR | O_NOCTTY );

    if(-1 == fd_com)
    {
        perror("Can't Open Serial Port");
        return -1;
    }


    //获取终端属性

    tcgetattr(fd_com,&initial_settings);
    new_settings = initial_settings;

    //设置速度

    cfsetispeed(&new_settings, B115200);//波特率115200
    cfsetospeed(&new_settings, B115200);

    /*控制模式设置*/

//  new_settings.c_cflag &= ~CSIZE;        //数据位8

    new_settings.c_cflag |= CS8;        //数据位8  

    new_settings.c_cflag &= ~CSTOPB;   //停止位1          

    new_settings.c_cflag &= ~PARENB;    //无校验

    /*输入模式设置*/  
    new_settings.c_iflag &= ~INPCK;    //取消校验      

    new_settings.c_iflag |= IGNPAR;     //忽略奇偶校验错误的字符

    new_settings.c_iflag |= ICRNL;      //收到的回车符转成换行符

    /*输出模式设置*/  

    new_settings.c_oflag = 0; 

    /*本地模式设置*/
       new_settings.c_lflag &= ~ICANON;    //启用非标准输入
   //  new_settings.c_lflag &= ~ECHO;      //关闭回显功能

       new_settings.c_lflag &= ~ISIG;      //禁用信号    

    /*控制字符设置*/
    new_settings.c_cc[VMIN]     = 1;    //有字符立即读取
    new_settings.c_cc[VTIME]    = 0;

    //启用新的终端设置
    if(tcsetattr(fd_com, TCSANOW, &new_settings) != 0) {
        fprintf(stderr,"could not set attributes\n");
    }

//  tcsetattr(fd_com,TCSANOW,&initial_settings);    //恢复原有设置
    return fd_com;  

}   

/**********************************
串口数据发送
**********************************/

void* com_send(void* arg)
{
    int fd;
    int nbyte;
    fd = *(int*)arg;

    while(1)
    {   
        if(strlen(net_buff)>0)
        {
            nbyte = write(fd,net_buff,strlen(net_buff));
            printf("com send nbyte=%d\n",nbyte);
            memset(net_buff, '\0', sizeof(net_buff));               
        }
    }   

}


/**********************************
串口数据接收
**********************************/

void* com_recv(void* arg)

{   

    int fd;

    int nbyte = 0;

    fd = *(int*)arg;

    char recvbuf[MAXDATASIZE];

    while(1)
    {       

        //读取串口数据到缓冲区    

        memset(recvbuf,'\0',MAXDATASIZE);

        nbyte = 0;              
        nbyte = read(fd,recvbuf,MAXDATASIZE);

        recvbuf[nbyte] = '\0';  

        printf("nbyte=%d com recv:%s\n",nbyte,recvbuf);

        strcat(com_buff,recvbuf);
    }   

}

PC客户端源程序

/* cthread.c */

#include <stdio.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <netdb.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
#include <errno.h>
#include <stdlib.h>
#include <pthread.h>

#define PORT 8848
#define MAXDATASIZE 128

void* net_recv(void* arg);
void* net_send(void* arg);
int get_line(char *msg);
int init_net(int argc, char *argv[]);

/**********************************

主函数

**********************************/

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

    int net_fd;
    pthread_t recv_th,send_th;

    net_fd = init_net(argc,argv);

    pthread_create(&send_th,NULL,net_send,(void*)&net_fd);
    pthread_create(&recv_th,NULL,net_recv,(void*)&net_fd);
    pthread_join(recv_th,NULL);
    pthread_join(send_th,NULL); 

    return 0;
}   


/**********************************

网络接收线程

**********************************/

void* net_recv(void* arg)
{

    char recvline[MAXDATASIZE]; 
    int *sockfd;
    int numbytes;
    sockfd = (int*)arg;

    while(1){
        printf("@\n");

        if((numbytes = recv(*sockfd, recvline, MAXDATASIZE, 0)) == 0){
        printf("serial not data. \n");
        }

        //recevie message form server echo
        recvline[numbytes] = '\0';

        printf("[com data] %s\n", recvline);
        //clean output buffer
        memset(recvline, '0', strlen(recvline)-1);      
    }       

}


/**********************************

网络初始化,连接到服务端

**********************************/ 

int init_net(int argc, char *argv[])
{   
    int fd;
    struct hostent *he;
    struct sockaddr_in server; //server's address info
    char *defaultIP = "127.0.0.1";


    if(argc != 2) {
        if((he = gethostbyname(defaultIP)) == NULL){
            perror("gethostbyname() error");
            exit(1);
        }
    }else{
       if((he = gethostbyname(argv[1])) == NULL){
            perror("gethostbyname() error");
            exit(1);
            }
    }

    if((fd = socket(AF_INET, SOCK_STREAM, 0)) == -1){
        perror("socket() error");
        exit(1);

    }

    bzero(&server , sizeof(server));
    server.sin_family = AF_INET;
    server.sin_port = htons(PORT);
    server.sin_addr = *((struct in_addr *)he->h_addr);

    if(connect(fd, (struct sockaddr *)&server,sizeof(struct sockaddr)) == -1){
        perror("connect() error");
        exit(1);
    }

    return fd;

}


/**********************************

网络发送数据线程

**********************************/
void* net_send(void* arg)
{

    char sendline[MAXDATASIZE],recvline[MAXDATASIZE];
    int numbytes;
    int len;
    int * sock_fd;

    sock_fd = (int*)arg;
    printf("connected to server. \n");

    //send message to server
    //when the string is not NULL , send another!

    while(1){
        while((len =get_line(sendline)) != 0){
            sendline[len] = '\0';
            send(*sock_fd, sendline, strlen(sendline), 0);
        }
    }

}


/**********************************

接收命令行输入的数据

**********************************/

int get_line(char *msg)
{
    int i=0;
    char temp;

    printf("Input message:");   
    fflush(stdout);

    while (1) { 
        temp = getchar();
        if (temp == '\r' || temp == '\n') {return i ;}  
        msg[i]=temp;        
        if(msg[i]==13){
            msg[i]=0;
            break;
        }
        fflush(stdout);
        i++;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值