网络
网络为多个设备之间的数据交换提供了一种方式。它是一个主要组成部分,允许远程控制移动和平板设备应用程序中的一些参数,也用于使交互式项目在多台计算机上同步工作。在本章中,您将学习如何在openFrameworks项目中实现和使用OSC和TCP协议,具体如下:
网络基础
使用OSC协议
使用TCP协议处理流图像
网络基础
网络包括许多硬件和软件技术,它们提供数字设备之间甚至计算机内部应用程序之间的数据交换。目前最流行的网络模型是tcp/ip(传输控制协议/互联网协议)。它使用有线(LANー局域网)或无线(wlanー无线局域网)连接。所有的现代计算机和移动设备都支持tcp/ip协议。
注意:另一种网络技术是无线ZigBee网络,广泛应用于物理计算项目。只连接两个设备可以被认为是最简单的网络。旧的但仍然流行的有线连接技术是USB、串行端口(RS-232)、RS-485和I2C(用于微设备)。
在本章中,我们将考虑使用tcp/ip连接本地网络中的多个设备。本地网络是由网络路由器构建和控制的。网络路由器是一个特殊的网络节点,它作为一个独立的设备工作,或者集成在你的笔记本电脑中。
网络路由器给每个连接到网络的设备一个唯一标识符地址,称为网络地址。地址具有192.168.0.3这样的格式,或者可以是计算机名,如Mymachine。每个设备都可以使用地址localhost或其等价物127.0.0.1引用自身。查看网络适配器的属性以查找设备的网络地址。您还可以使用Terminal窗口请求网络信息,方法是输入ipconfig命令(用于Windows)或ifconfig命令(用于MacOSx和Linux)。
要测试具有已知地址的两台计算机之间的连接,可以使用ping命令,例如ping 192.168.0.3。如果连接没有建立,它可能被路由器或计算机的防火墙或防病毒软件阻止。在这种情况下,检查它们的设置。
注意:请注意,当重新启动设备和路由器时,网络地址可能会发生变化。因此,对于长期工作的交互式安装,您应该在其网络适配器的设置中修正计算机的地址,或者只使用计算机名称而不是编号地址。
为了将一些数据从一个设备发送到另一个设备,您应该指定目标设备的网络地址,以及端口号,端口号是介于0和65535之间的整数。有些端口是保留的,例如,端口80用于通过浏览器进行HTTP协议交换。在本章的例子中,我们将使用端口12345。
系统服务很少使用大数量(大于10,000)的端口,因此您最有可能使用它们。要查明您的系统中使用了哪些端口,可以使用来自终端的特殊软件或网络命令。对于连接设备,我们经常使用端口12345、12346、12347和12348。
在本章中,我们将学习如何使用以下两个协议来实现数据传输:
OSC:开放声音控制是非常简单和快速的。它适用于快速传输少量信息(例如更改参数和对象坐标的命令)。它是交互式安装和物理计算项目中使用的主要协议。它在所有与vj-相关的软件中都得到了支持。
最初,OSC作为MIDI的网络替代品,MIDI是连接乐器的有线协议。现在,OSC用于控制广泛的应用程序和设备,通常与音乐无关。
Tcp:传输控制协议可以轻松地传输大量数据。这是一个通用的协议。在本章中,我们将看到一个使用它进行图像流的例子。
让我们从OSC协议开始。
使用OSC协议
Osc是一个非常流行的协议,用于在设备和应用程序之间发送控制命令和参数。这是一个无法确认数据交换是否成功的协议,也就是说,发送方不知道接收方是否收到了数据,接收方也不知道是否有人向它发送了数据。因此,数据可能在没有通知发送方和接收方的情况下丢失。
但是,在本地网络中,这种情况非常罕见,而且只有在使用极快的帧速率发送数据时才会发生。
OSC是UDP协议上的一个薄层。有关更多信息,请阅读UDP规范。
要在openFrameworks项目中使用OSC功能,您需要使用ofxOsc插件。这是一个包含在openFrameworks发行版中的核心插件。
我们建议您第一次尝试OSC时,使用openFrameworks 例子oscSenderExample和oscReceiveExample,它们位于openFrameworks文件夹中的examples/addons中。在同一台PC上运行这两个命令,然后将鼠标移动到oscSenderExample窗口上。您将看到oscReceiveExample接收鼠标坐标并将它们写在屏幕上。
要在你的项目中使用插件,你有三个选择:
1.通过将oscSenderExample或oscReceiveExample复制到您的项目文件夹来启动一个新项目。这种方法对于OSC的首次试验来说是最简单也是最好的。
2.通过指定ofxOsc插件,使用ProjectGenerator向导创建一个新项目。详细信息请参阅附录a,使用插件工作。
3.将addons/ofxOsc文件夹中的所有文件链接到您的项目,并指定它们的路径。这是将OSC支持添加到现有项目的方法。
现在您已经有了带有链接的ofxOsc插件的项目,并且可以使用OSC协议发送和接收数据。
发送数据
要在项目中使用OSC发送数据,请执行以下步骤:
1.将#include“ofxOsc.h”行添加到testApp.h文件中#include“ofMain.h”行。
2.通过添加ofxOscSender sender方来声明将发送OSC数据的发送方对象;testApp类定义中的行。
3.在testApp::setup()函数中使用以下行初始化发送方:
sender.setup("localhost", 12345 );
Sender.setup()函数的第一个参数是包含接收方地址的字符串。Localhost是计算机本身的地址,因此,发送方将向运行在同一台计算机上的其他应用程序发送数据。要将数据发送到另一个设备,必须知道它的地址并指定它,例如,192.168.0.3。第二个整数参数是接收方的端口。我们使用12345是因为它通常不被操作系统用于任何特殊用途。
4.当您需要发送一些数据时,创建OSC消息作为ofxOscMessage类型的对象,指定它的地址,用参数或参数填充它,最后使用sender.sendMessage()发送消息:
ofxOscMessage m;
m.setAddress( "/volume" );
m.addFloatArg( 0.4f );
sender.sendMessage( m );
消息的地址不是接收者的网络地址。它只是接收者可以理解的参数的名称。地址以/开头,如果需要,可以包含多个/符号,例如:
/object1/velocity.
消息可以包含以下类型的几个参数之一:float、int和string。参数通过调用相应的函数依次附加到消息上:m.addFloatArg()、m.addIntArg()和m.addStringArg()。例如:
m.addFloatArg( 0.4f );
m.addIntArg( 1 );
m.addStringArg( "start" );
最常用的参数类型是范围[0,1]中的浮点值。它们通过软件平台(如VDMX和max/msp)自然地与VJ控制器和其他设备相连。此外,整数值用于表示按钮状态(0-disabled,1-enabled)。
您可以让多个发送方将数据发送到多个目的地。
我们建议将目的地址和端口号存储在外部.xml文件放在项目的数据文件夹中。我们称这个文件为settings.xml。将读取目标地址和端口号的值的操作添加到testApp::setup()函数,并使用这些值作为sender.setup()的参数。此方法使您可以灵活地在不同的网络配置中运行项目,而无需重新编译。
使用可以使用的ofxXmlSettings插件.xml文件。了解如何在openFrameworks示例中使用它:example/addons/xmlSettingsExample。
请注意以下规则:
1.小心不要发送信息太快,因为它们可能会丢失。正常情况下,发送30或60帧的效果很好。
2.如果您需要同时发送许多消息,一个好主意是使用ofxOscBundle对象将它们组合成一组。只需创建一个这种类型的对象,添加ofxOscMessage消息,然后发送:
ofxOscBundle bundle;
bundle.addMessage( m ); //First ofxOscMessage message
bundle.addMessage( m2 ); //Second message
//...
sender.sendBundle( bundle ); //Send bundle
OSC数据包的大小是有限的。最大大小取决于操作系统和网络设置,但通常不少于500字节。如果限制值超过,您的OSC数据包经常会丢失。因此,不要发送包含太多信息的消息和包。请注意,所有数据(包括数字)都以文本形式存储在OSC数据包中。
接收数据
要在项目中接收OSC的数据,请执行以下步骤:
1.将#include“ofxOsc.h”行添加到testApp.h文件中#include“ofMain.h”行。
2.通过添加ofxOscReceiver receiver来声明将接收OSC数据的接收器对象;testApp类定义中的行。
3.在testApp::setup()函数中使用下面的代码行启动接收器:
receiver.setup( 12345 );
receiver.setup()函数的参数是端口号的整数值。
注意:如果需要在一台计算机上使用多个接收器,则应为每个接收器指定不同的端口。
4.现在,您应该等待传入到接收方的消息并解析它们。最佳实践是在while循环中的testApp::update()函数中执行:
while ( receiver.hasWaitingMessages() ){
//Get the next message
ofxOscMessage m;
receiver.getNextMessage( &m );
//Parse message, for example:
if ( m.getAddress() == "/volume" ){
//Get first argument
float volume = m.getArgAsFloat( 0 );
//...
//Use volume value, for example:
sound.setVolume( volume )
}
};
你可以使用函数m.getArgAsFloat(index)、m.getArgAsInt32(index)和m.getArgAsString(index)获得消息m中的参数值,其中index是参数的索引、0-first、1-second等。要获取属性的数量,请使用m.getNumArgs()函数,该函数返回m中的属性值。
让我们看看通过使用OSC将项目与其他应用程序连接起来使用它们的一些典型方案。
Osc使用的典型方案
Osc的典型用法如下:
1.使用苹果iPad或者其他平板来发送命令,比如保存屏幕截图到磁盘或者控制粒子的速度等参数。
你需要在桌面上安装一个应用程序,比如TouchOSC,它会把OSC消息从你的设备发送到你的openFrameworks的项目中。
2.使用您的openFrameworks应用程序作为一个跟踪器,它从世界获取一些信息(例如,使用深度摄像机计算用户身体部位的坐标),并将其发送到max/msp、VDMX、QuartzComposer、TouchDesigner或Unity3D,以生成声音和视觉效果。
对于更复杂的方案,您需要使用OSC-manager应用程序,该应用程序路由OSC信号,如OSCulator。
尽管OSC得到了所有创造性编码和VJ软件的良好支持,但它不能轻松地传输图像等大数据。因此,让我们考虑如何使用另一个协议来实现它,例如TCP。
使用TCP协议处理流图像
Tcp是所有Internet协议的基础,例如HTTP。这是一个错误检查协议,它保证获取有效数据并通知错误。这使得它适合从计算机发送大量的数据,不仅在您的本地网络,而且在世界各地。
要在openFrameworks中使用TCP,您需要使用ofxNetwork插件。
注意:我们建议第一次尝试使用openFrameworks示例的TCP:networkTcpServerExample和networktcpcpcclientexample,位于openFrameworks的文件夹中的examples/addons。在同一台电脑上运行这两个命令,然后激活networktcpcclientexample窗口并按下一些键。您将看到这些键将被发送到networkTcpServerExample并打印在其屏幕上。
对于链接ofxNetwork插件,有三个类似于ofxOsc插件的选项。有关详细信息,请查看“使用OSC协议”部分的开头。
基于客户-服务器技术的TCP协议实现方案。在一个应用程序中,您需要使用ofxTCPServer对象创建并启动服务器。在另一个应用程序中,您需要使用ofxTCPClient客户机对象创建一个客户机,并与服务器建立连接。在此之后,您可以将字符串消息和原始数据字节从客户机发送到服务器,从服务器发送到客户机。可以有多个客户端连接到一个服务器。
原则上,使用ofxNetwork插件,您可以实现自己的HTTP或FTP服务器,并做任何事情,如从互联网下载文件。但是,对于严肃的项目,我们强烈建议不要自己这样做,因为TCP是一个非常低级的协议。相反,可以使用一些现成的插件或者特殊的库。此外,openFrameworks核心包含几个类,这些类可能对您的需求非常有用:
1.如果你需要从网上下载图片,你可以使用image.loadImage(url)函数,其中URL是指定图像URL的字符串。注意,它会暂停应用程序的执行,直到下载图像。因此,要不停顿地下载图像(称为
异步),请参阅openFrameworks示例:examples/graphics/imageaderwebexample。
2.要下载任意文件,可以使用ofURLFileLoader类。我们不会在这本书中考虑它。
3.要处理HTTP请求和响应,请参阅libs/openframeworks/utils/ofurlfileload.h文件中的函数。这也超出了本书的范围。
我们不会详细考虑ofxTCPServer和ofxTCPClient类,但是我们将包括一个非常有用的例子,通过在同一台或不同的计算机上工作,在应用程序之间使用它来流动图像。
流图像示例
让我们考虑一个演示如何使用TCP在应用程序之间发送图像的示例。它由发送者和接收者两个项目组成。
注意:这个示例包含两个项目,networkImageSender和networkImageReceiver。它们位于文件夹中
11-Networking/networkimageender和11-Networking/networkimagereiver本书的示例。
这两个示例项目是由一些来源提出的.h和.cpp文件。有关如何从这些源创建openFrameworks项目的详细说明,请阅读testApp.h文件的开头。
编译并运行这两个项目。发送者将获取相机图像并将其发送到接收者。两个项目都在屏幕上绘制当前图像,并显示当前帧的ID。此外,接收器显示接收到的图像的帧速率(这不仅取决于网络,还取决于相机的实际帧速率):
发送方和接收方使用ofxTCPServer和ofxTCPClient类将图像作为未压缩的数组发送和接收。在pbNetwork.h和pbNetwork.cpp文件中查看其实现的详细信息,这些文件包含在每个示例的项目中。
当您需要在应用程序之间发送大量信息时,可以将此示例用作您自己项目的草图。
注意:我们经常在我们的互动装置和表演中使用这种技术。我们安装了两个pc,一个是可以和深度摄像机一起工作的Tracker,另一个是渲染,渲染安装的视觉效果。跟踪器从几个深度相机获取数据,将它们粘贴到一个更大的深度图像中,并通过TCP发送到Render。这种跟踪和渲染的分离提高了系统的整体稳定性,并且从深度数据分析中卸载了Render,从而可以进行更多的处理,获得更丰富的可视化效果。
通常你可以用100mbps的有线连接以30fps的速度发送320240的灰度图像。为了发送更大的图像,使用更快的网络设备,如1gbp或更高。请注意,我们从来没有使用无线连接在严重的音乐会和演出,因为可能会导致观众的移动设备的不稳定性。
如果您需要在Mac计算机上将图像从一个应用程序发送到另一个应用程序,则不需要使用网络。在这种情况下,最好的选择是使用一个名为Syphon的开放库,方法是下载和安装ofxSyphon插件。这个插件允许openFrameworks和其他应用程序在OpenGL级别上交换映像,因此它比网络工作得更快。
摘要
在本章中,我们学习了如何使用OSC和TCP协议将应用程序与其他应用程序和设备连接起来。它使我们能够创建复杂的分布式交互系统,其可能性远远超过单个openFrameworks项目。
这是这本书的最后一章。在这本书中,我们学习了一些交互式多媒体的基础知识。我们希望您继续您的调查,实现您自己的项目,并打破交互体验的界限!