何为串口:
串行接口简称串口,也称串行通信接口或串行通讯接口(通常指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 <errno.h>
#include <arpa/inet.h>
#include<netinet/in.h>
#define DEFAULT_PORT 8888
#define MAX_BUF_SIZE 1024
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);
{
printf("read server data failure: %s\n",strerror(errno));
goto finsh;
finsh:
close(sockfd);
return 0;
串行接口简称串口,也称串行通信接口或串行通讯接口(通常指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);
}
{
printf("read server data failure: %s\n",strerror(errno));
goto finsh;
}
close(sockfd);}
finsh:
close(sockfd);
return 0;
}
以上便可实现串口转socket,但传输的数据并未加密,若要加密,可研究ssl(安全套接层),此处不多说。