MATLAB TCP 持续通信收发信息解决方案

前言

windows的进程间通信可能有很多途径,例如管道、tcp、udp、共享内存等方式,这些不同的方式各有优缺点,本文主要介绍TCP通信的使用方法,并且MATLAB作为 client 的方式向host持续通信收发信息,收发不同含义信息的解决方案。

背景

常见的博文中介绍了TCP通信的基本使用方法,这些都可以通过MATLAB帮助文档得到细致的描述,本文主要在基本使用方法的基础上,对MATLAB 使用 TCP做一些实际的使用方法,以及使用过程中遇到问题的解决方法和心得。

使用案例和方法

本文从使用tcp通信使用过程的顺序讲起,包括建立tcp通信、发送tcp消息,通信结束这三个过程说明:

建立tcp通信

在MATLAB中建立tcp通信非常简单,调用tcpip函数即可:

global tcp_client
tcp_client = tcpip('127.0.0.1',2021,'NetworkRole','client');

tcpip函数用返回一个tcpip文件对象标识符,用来通过操作该对象进而来操作tcp通信,收发信息等。由于在MATLAB中不同函数之间存在相互调用的关系,而且不同的函数均可能存在发送消息的情况,因此将该tcp文件对象标识符声明为全局变量,当某个函数想利用tcp发送消息时,直接通过全局变量获取到该对象,对其调用 fwrite 函数写入内容即可。

建立失败应对方法

当tcp通信异常等原因建立失败后,怎样才能在除了通信故障以外,保持其他代码不变的情况下继续维持整个代码运行呢?这里可以借鉴以下方案,当建立tcp对象失败时,可以将该对象赋给一个新的文件对象,这样就把所有消息传递给了文件,进而整个程序还能运行,只是其他函数发送tcp消息时并不是发送了tcp消息,而是写入信息到文件中了,这也是“一切皆文件”的设计思想吧。

try
    if ~isempty(tcp_client)
        fwrite(tcp_client,messageSend);
    else
        core.global.icp.client = tcpip('127.0.0.1',2021,'NetworkRole','client');
        fopen(tcp_client);
        fwrite(tcp_client,messageSend);
    end
catch
    lasterror('reset');
    tcp_client= fopen([run_dir,'ipc_send.txt'],'a');
    fwrite(tcp_client,messageSend);
    warning('无法建立ICP通信,将运行消息记录在 ipc_send.txt 文件中,可能缺少 Instrument Control Toolbox 工具箱');
end

以上程序中的run_dir为一个写入记事本文件的路径,需要提前给定。由于MATLAB程序对tcp的发送和接收消息采用的也是一切皆文件的思想,即 fwrite ,fread 等,这种调用方式和操作文本文件是完全相同的,因此当tcp创建失败时,直接创建文本对象用来替换掉原来创建未成功的tcp对象,其他发送消息操作tcp对象的函数所有操作均针对文本文件。

发送消息

中文发送

tcp通信时经常有中文发送的需求,需要通过 unicode2native 函数将字符串进行转换即可,例如:

messageSend = unicode2native(messages);

messages 为中文字符串消息,messageSend 转换后可直接调用:

fwrite(tcp_client,messageSend);

携带含义

发送的消息常常需要携带函数,如果单纯的发送一些简单的消息那就直接发送即可,本小节忽略即可。
需要发送携带含义的信息即是对字符串修整,例如在字符串加前缀,加分隔符,空格,或者加 xml 类型的 < > 修饰均可,这里提供两种案例供参考:

消息修饰包裹

将发送的消息层层包裹为 xml,最后得到修饰后的消息,该种方式针对解析 xml 的语言较为合适。
对消息修饰的函数为:

function tcp_send_messages(messages,varargin)
global tcp_client;
if nargin > 1
    assert( mod( length( varargin ), 2 ) == 0 );
    for i = 1:length( varargin )
        switch lower( varargin{ i } )
            case {'size','s'}
                messages = wrapper_message(messages,'size',num2str(varargin{ i + 1 }));
            case {'color','c'}
                messages = wrapper_message(messages,'color',varargin{ i + 1 });
            case {'image','i'}
                % 简化输入
                switch varargin{ i + 1 }
                    case {'error','e'}
                        png = 'error.png';
                    case {'warning','warn','w'}
                        png = 'warning.png';
                    case {'info','i'}
                        png = 'info.png';
                    otherwise   
                        png = 'info.png';
                end
                messages = wrapper_message(messages,'image',png);
            case {'backcolor','b'}
                messages = wrapper_message(messages,'backcolor',varargin{ i + 1 });
            case{'type','t'}
                if strcmp(varargin{ i + 1 },'g') || strcmp(varargin{ i + 1 },'global')
                    prefix = ['GlobalMsg',' ',project_windows,' '];
                else
                    prefix = [core.global.icp.type,' ',project_windows,' '];
                end
                % 注意: animate 必须在 type 后输入
            case {'animate','a'}
                prefix = [prefix,' ','animate',' '];
        end
    end
else
    % 采用默认值
    messages = wrapper_message(messages,'size','12');
    messages = wrapper_message(messages,'color','black');
    messages = wrapper_message(messages,'image','info.png');
end
% 消息修饰
function messageOut = wrapper_message(message,style,styleValue)
messageOut = ['<',style,'=',styleValue,'>',message,'</',style,'>'];
end

使用上述的函数发送消息时,可对消息进行灵活的配置输入, MATLAB中很多函数的输入和上述函数类似;与输入的配置类型和配置信息有关,例如,仅输入一种属性,或者想同时对消息配置三种属性,输入函数的参数个数不同即可达到目的,有感兴趣的可研究一下。在不想配置消息的属性时,不对属性输入即可,函数本身提供有设置消息的默认值;这种方式很大的方便的发送消息和修饰消息时使用的便捷性。

json 转换

也可将结构体转换为 json 的方式,让 host 解析 json 字符串即可,该种方式在能够解析 json 的地方应用较为方便。

% 利用 jsonencode 函数转 json 字符串来发送字符串
% jsonencode(struct)

messages.name = 'send message';
messages.num = '2';
jsonencode(messages);

另外,还可对消息进行前缀,后缀等修饰加工手段;也可对上述的方式灵活组合应用,发送出各式各样的消息。

结束通信

当通信结束时或者函数运行完后,需要对通信对象及时关闭和清理,记得调用 fclose 函数。

fclose(tcp_client);

结语

本文从tcp建立,发送消息,结束 这三个方面对 tcp 使用过程中的方法技巧,能够使用在一些小型的多函数相互调用发送消息的项目中,其中 MATLAB 作为 client 发送消息到 host的案例,以后也可开发分享作为接收的使用方法(可使用定时器timer监控接收缓冲区长度)。
注:作者在使用MATLAB tcp 通信时使用了 socket 调试助手,相比打开两个MATLAB 的发送方式方便不少,而且监控消息,连接等过程非常方便,调试tcp时最好使用专门的调试工具。 该小工具 在 csdn 很多, 需要的可以下载。
以上就是使用 tcp 通信时的经验分享,欢迎在评论区多多交流,共同学习。

调试工具下载入口:
1、简易调试工具(推荐)
2、socket调试工具

上一篇:mysql 创建分区表


下一篇:如何开启群组的-Auto-delete-messages