串口转socket通信

何为串口:
串行接口简称串口,也称串行通信接口或串行通讯接口(通常指COM接口),是采用串行通信方式的扩展接口。串行接口 (Serial Interface) 是指数据一位一位地顺序传送,其特点是通信线路简单,只要一对传输线就可以实现双向通信(可以直接利用电话线作为传输线),从而大大降低了成本,特别适用于远距离通信,但传送速度较慢。一条信息的各位数据被逐位按顺序传送的通讯方式称为串行通讯。串行通讯的特点是:数据位的传送,按位顺序进行,最少只需一根传输线即可完成;成本低但传送速度慢。串行通讯的距离可以从几米到几千米;根据信息的传送方向,串行通讯可以进一步分为单工、半双工和全双工三种。


何为socket:
Socket的英文原义是“孔”或“插座”。作为BSD UNIX的进程通信机制,取后一种意思。通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄,可以用来实现不同虚拟机或不同计算机之间的通信。在Internet上的主机一般运行了多个服务软件,同时提供几种服务。每种服务都打开一个Socket,并绑定到一个端口上,不同的端口对应于不同的服务。


综上所诉,socket即用来连接网络的接口,只有当socket有正确的配置后,才可以和网络有数据的交换。




实现思路:其实非常简单,将串口接收到的数据读到buffer中,再将buffer中的数据写到socket中。


本文主要根据代码加注释来说明实现过程。




打开串口及配置(主要就是写了两个函数):


#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<termios.h>
#include<errno.h>
#include<fcntl.h>
#include<stdio.h>
#include<string.h>


int opentty(void)
{
    int ttyfd;
    if((ttyfd=open("/dev/ttyS1",O_RDWR))<0)
    {
        printf("open failure:%s\n",strerror(errno));
        close(ttyfd);
    }
    return ttyfd;
}//由于linux中所有设备都是文件,所以可以用open打开串口这个块设备,并设置为O_RDWR(注意不要设置为非阻塞模式)


int setttyinfo(int fd)
{
    int                              i,k;
    struct termios                   opt;//termios结构体定义在termios.h这个头文件里,主要用于存储串口的基本属性(波特率,数据位,停止位,奇偶校验等参数)


    tcgetattr(fd,&opt);//该函数用于取得当前串口配置   
    
    i=cfsetispeed(&opt,B115200);//设置input波特率
    k=cfsetospeed(&opt,B115200);//设置output波特率        
    
    if(i==-1|k==-1)
    {   
    printf("speed failure:%s\n",strerror(errno));
    close(fd);
    return -1;
    }
     opt.c_cflag &= ~CSIZE;
     opt.c_cflag |= CS8;//这两行用于设置8位数据位    


     opt.c_cflag &= ~PARENB;
     opt.c_iflag &= ~INPCK;//设置为无奇偶校验     
 
     opt.c_cflag &= ~CSTOPB;//设置一位停止位     


    if(0!=tcsetattr(fd,TCSANOW,&opt))//将设置写入串口
    {
    printf("write fd failure:%s\n",strerror(errno));
    close(fd);
    return -2;
    }
    tcflush(fd,TCIOFLUSH);
}


以上就是对串口的打开及简单配置,termios结构体比较复杂,各成员有很多选项值可供选择,可自行研究。




以下为server端程序(主要用于实现socket通信,调用上述函数):


#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>


#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>


#include <errno.h>
#include <time.h>


#define       DEFAULT_PORT    8888
#define       MAX_SIZE               1024
#define       LISTENQ                  1024
#define       BUFFSIZE                1024


int opentty(void);
int setttyinfo(int);


int main (int argc, char **argv)

    int                                        serv_port;
    int                                        listenfd;
    struct sockaddr_in           servaddr;
    time_t                                 tick;
    int                                        connfd;
    int                                        ttyfd;
    int                                        n,re;
    char                                    buffer[BUFFSIZE];


    ttyfd=opentty(); 
    re=setttyinfo(ttyfd);//调用函数打开并配置串口
    if(re<0)
    {
        goto finsh;
    }
    printf("******************open ttyS1 success******************\n");
    memset(&buffer,0,sizeof(buffer));


    if (2 == argc)
    {
        serv_port = atoi(argv[1]);
    }
    else
    {
        serv_port = DEFAULT_PORT;
    }


    if ((listenfd = socket(AF_INET,SOCK_STREAM,0))< 0)//起一个listenfd,用于监听server端是否有连接请求。配置为ipv4,tcp协议。
    {
        printf("create listenfd failure: %s\n",strerror(errno));
        goto finsh;
    }


    memset(&servaddr,0,sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr=htonl(INADDR_ANY);
    servaddr.sin_port = htons(serv_port);//清空并设置地址格式的结构体


    int on=1;
    if((setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on)))<0)//由于server端在强制结束时,未释放套接字资源,此处指定可支持快速重新建立server端,不需要等待系统关闭之前的listenfd
    {
        printf("setsockopt failed:%s\n",strerror(errno));
        goto finsh;
    }


    if (bind(listenfd, (struct sockaddr *) &servaddr,sizeof(servaddr))<0)//将listenfd和地址格式绑定,即将地址格式里的信息赋给listenfd
    {
        printf("servaddr bind listenfd failure: %s\n",strerror(errno));
        goto finsh;
    }


    if (listen(listenfd,LISTENQ) < 0)//开始监听套接字listenfd,LISTENQ用于表示server可接受的最大请求数量
    {
        printf("server turn into listen failure: %s\n",strerror(errno));
        goto finsh;
    }
    printf("start to listen port:[%d]\n",serv_port);
    
    for( ; ; )
    {
        n=read(ttyfd,buffer,BUFFSIZE);//从串口ttyfd中读取BUFFSIZE大小的数据放入buffer中
        if(n<=0)
        {
            printf("read failure:%s\n",strerror(errno));
            goto finsh;
        }
        buffer[n]='\0';//将实际读到的数据后一位设置为结束字符,便于打印
        printf("%s\n",buffer);
        if(0==strncmp(buffer,"quit",4))//比较buffer中前4个字符是否与quit相同,相同返回0,不同返回差值
        {
              printf("***********************quit tty***********************\n");
              goto finsh;
        }


        if((connfd=accept(listenfd,(struct sockaddr *)NULL,NULL))<0)//之前开启了监听,当监听到请求时,使用accept获得连接请求并建立连接,创建新的连接套接字connfd
        {
            printf("accept client failure:%s\n",strerror(errno));
        }
        if (write(connfd,buffer,strlen(buffer))<0)//将buffer中的数据写到connfd中
        {
            printf("write connfd failure: %s\n",strerror(errno));
            goto finsh;
        }
close(connfd);
    }
finsh:
    close(ttyfd);
    close(listenfd);
    close(connfd);//程序最后记得关闭所有套接字,释放资源。程序出错时,也要关闭相应套接字

    return 0;
}



以下为客户端程序(主要就是发出请求,接受server端数据)
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

#include <sys/socket.h>

#include <sys/types.h>
#include <errno.h>
#include <arpa/inet.h>
#include<netinet/in.h>


#define DEFAULT_PORT           8888
#define MAX_BUF_SIZE           1024

int main (int argc, char **argv)

{
    int                                      sockfd;
    int                                      len;
    char                                  ipaddr[20];
    char                                  recv_buf[MAX_BUF_SIZE];
    struct sockaddr_in         servaddr;


    printf("please input ipaddr: ");
    scanf("%s",&ipaddr);


    if (0>=ipaddr)
    {
        printf("input ipaddr failure: %s\n",strerror(errno));
        goto finsh;
    }


    for( ; ; )
    {

    if((sockfd=socket(AF_INET,SOCK_STREAM,0))<0)//创建sockfd套接字,用于发起请求和接受数据
    {
        printf("create socket failure: %s\n",strerror(errno));
        goto finsh;
    }


    memset(&servaddr,0,sizeof(servaddr));
    servaddr.sin_family=AF_INET;
    servaddr.sin_port=htons(DEFAULT_PORT);//清空servaddr,并设置ip4,指定端口
    
    
    if (inet_pton(AF_INET,ipaddr,&servaddr.sin_addr)<=0)//此处将输入的字符串格式转化为网络地址格式
    {   
        printf("set the Server IP address failure.\n");
        goto finsh;
    }


    printf("connect to %s:%d\n",ipaddr,DEFAULT_PORT);


    if (connect(sockfd,(struct sockaddr *) &servaddr,sizeof(servaddr))<0)//将sockfd套接字与地址格式绑定,并且发出连接请求
    {    
        printf("connect to server failure: %s\n",strerror(errno));
        goto finsh;
    }


    if((len = read(sockfd, recv_buf, MAX_BUF_SIZE))>0)//连接成功后,server发出的数据可从sockfd中读取
  {
      recv_buf[len] = '\0'; 

      printf("Get data from server %s:   %s\n", ipaddr, recv_buf);

  }


    if(len<0)
    {    
        printf("read server data failure: %s\n",strerror(errno));
        goto finsh;

    }

close(sockfd); 

}


finsh:
close(sockfd);

    return 0;

}


以上便可实现串口转socket,但传输的数据并未加密,若要加密,可研究ssl(安全套接层),此处不多说。

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值