文章大纲
TCP\IP 协议
TCP\IP协议的建立,通过服务器与客户端的三次握手建立。客户端首先向服务器端口发送SYN连接请求后,等待接收从服务器端口传来的SYN和ACK报文,客户端接收到后回应服务器ACK报文,此时服务器和客户端连接成功。
服务器端先初始化Socket,然后与端口绑定(bind),对端口进行监听(listen),调用accept阻塞,等待客户端连接。在这时如果有个客户端初始化一个Socket,然后连接服务器(connect),如果连接成功,这时客户端与服务器端的连接就建立了。客户端发送数据请求,服务器端接收请求并处理请求,然后把回应数据发送给客户端,客户端读取数据,最后关闭连接,一次交互结束。
本次实验采用的是Matlab作为服务器端,树莓派(Linux系统)作为客户端。流程图大致如下:
Matlab 作为服务器端,调用服务器端接口代码如下:
%与第一个请求连接的客户机建立连接,端口号为6668,类型为服务器。
t_server=tcpip('192.168.1.100',6666,'NetworkRole','server');
t_server.InputBuffersize=1024;%缓冲区放大到1024
t_server.Timeout=20;% 设置超时时间
fclose(t_server);
set(t_server,'RemoteHost','192.168.1.105');
fopen(t_server);%打开服务器,直到建立一个TCP连接才返回;
fprintf("Accept connect from %s \n",t_server.RemoteHost);
其中要注意的一点是,要设定与服务器相连接的客户端的IP地址,才能够进行通信,否则Matlab端并不会和客户端建立联系,从而一直堵塞在等待连接状态,一直到超时,才能退出。
树莓派作为客户端,用C语言编写,代码如下:
// socket 包括 协议,地址,端口
server_addr.sin_family =AF_INET;// IPV4 协议
server_addr.sin_addr.s_addr = inet_addr(server_ip);
server_addr.sin_port =htons(server_port);
int sfd;
// socket 套接字函数
// socket(int domain ,int type ,int protocal)
// domain 地址类型 ,AF_INET 为 IPV4 类型
// type 数据流,SOCK_STREAM为 TCP数据流
// protocal 一般设置为0
// 失败返回-1 ,成功返回socket 代码
sfd = socket(AF_INET,SOCK_STREAM,0);
if(sfd<0)
{
printf("socket error: %s(errno : %d)\n",strerror(errno),errno);
exit(0);
}
// 常用于客户端建立TCP链接
// 第一个参数为 套接字,
// 第二个参数为 连接的主机地址和端口
// 缓冲区长度
if(connect(sfd,(struct sockaddr*)&server_addr,sizeof(server_addr)) < 0 )
{
printf("Can not connect to %s\n",argv[1]);
exit(1);
}
printf("连接成功\n\n");
Matlab 发送给客户端采用fprintf(t_server,'%s','Content')
其中,第一个参数为服务器的套接字,第二个参数为发送的类型,第三个参数为发送的内容。
Matlab 从客户端接收采用fread(t_server,Size)
其中,第一个参数为服务器的套接字,第二个参数为接收的大小。注意!!当服务器没有从客户端接收到这么大的字节时,会一直堵塞,直到超时。
树莓派发送给服务器采用send(sfd,buffer,length,0)
其中第一个参数为套接字,第二个参数为发送的字符串数组,第三个参数为字符串的长度,第四个参数默认为0。
树莓派从服务器接收采用recv(sdf,buffer,length,0)
,参数同发送。
注意!由于Matlab的接收的特殊性,一定要确定好Size大小。因此,一般树莓派先发送文件的大小,让Matlab端知道要定义多大的存储空间,然后在发送内容。
文件流的传输
就如刚才所说的,一定要确定好文件的大小。采用下面的代码获取文件的大小。
if((stream=fopen(Filename,"r"))==NULL)
{
printf("open failed \n" );
exit(1);
}
long size = 0;
char tmp;
while(fread(&tmp,1,1,stream))
{
size++;
}
注意!!文件流使用过一遍,就会是失效(我也不知道为啥),要重新再赋值一遍才可以,即在此执行一遍fopen
,然后再传输文件,代码如下
stream=fopen(Filename,"r");
while((len=fread(buffer,1,1024,stream))>0)
{
printf("正在传输\n");
if(send(sfd,buffer,len,0)<0)
{
printf("send failed\n");
break;
}
bzero(buffer,BUFFER_SIZE);
}
printf("传输完毕\n\n");