使用ABAP实现TCP Socket编程(客户端部分)
使用ABAP实现TCP Socket编程(客户端部分)
本文将介绍如何使用ABAP实现TCP Socket编程,重点讲解如何使用ABAP Push Channel框架实现TCP客户端编程。文章将通过一个实际的DEMO报表DEMO_APC_TCP_CLIENT来演示如何实现TCP客户端和服务器端的通信。
TCP协议基础
传输控制协议(Transmission Control Protocol,简称TCP)是一种面向连接的、可靠的传输层协议。它确保了数据在网络中可靠地传输,不会出现丢包、重复或者顺序错误的问题。
TCP协议通过建立连接、数据传输、流量控制、拥塞控制等机制来保证通信的可靠性。它为应用层提供了一种可靠的字节流服务。
Socket概念
套接字(Socket)是计算机网络中用于进程间通信的一种抽象概念。它为程序提供了一种网络通信的接口,使得应用程序能够通过它发送和接收数据。
套接字有多种类型,包括面向连接的套接字(如TCP套接字)和无连接的套接字(如UDP套接字)。
ABAP Push Channel框架
ABAP Push Channel框架提供的工具类,对TCP Socket的概念进行了高度封装。ABAP开发人员不需要了解TCP协议的底层技术细节。使用ABAP进行TCP客户端的开发,只需要调用ABAP Channel框架提供的对应方法,实现建立连接,发送数据到服务器端,以及从服务器端接收数据这三大块需求就可以了。
ABAP Channel是一种ABAP应用服务器与Internet通过Event-Driven即事件驱动方式进行交互的机制和技术。ABAP Channel分为ABAP Messaging Channel和ABAP Push Channel(以下简称APC)两类。本文使用的是ABAP Push Channel提供的工具类。
SAP系统已经自带了一个用APC实现的ABAP TCP Client的报表:DEMO_APC_TCP_CLIENT,总共一百多行的代码。
TCP服务器端的搭建
既然有客户端,那么一定需要对应的服务器端。该报表使用了一个网络工具领域的瑞士军刀NCAT,可以在其官网下载:
该下载到本地后是一个.exe文件,可以通过命令行指定不同的启动参数,扮演网络客户端和服务器端的不同角色。
如下图所示,报表首先使用cl_gui_frontend_services的get_ip_address方法,获取本地电脑的IP地址。然后在第14行,使用cl_gui_frontend_services的execute方法,调用操作系统的cmd.exe命令行工具,启动刚刚下载好的NCAT工具的exe文件。
-l参数代表NCAT以服务器模式启动,-l后面的参数值,内容为该服务器监听的IP地址。-p参数指定服务器监听的端口号。
ABAP TCP客户端的实现
使用cl_apc_tcp_client_manager的create方法,创建一个新的客户端实例。
该方法需要传递服务器端的IP地址和端口号,以及一个TCP Frame参数。Frame的意思是帧,其主要任务是提供有关在即将创建的TCP连接上发送和接收的数据结构的信息。
接收数据时,APC框架通过该结构的信息,能够将服务器返回的数据,拆分为将要传送给客户端的TCP包。当客户端发送数据到服务器端时,APC将根据create方法指定的帧信息,检查客户端发送的数据格式是否有效。
本例使用了IF_APC_TCP_FRAME_TYPES=>CO_FRAME_TYPE_TERMINATOR作为帧类型,意思是由ABAP开发人员自行指定一个TCP帧的结束符号(Terminator)。
上图第六行的terminator变量,值为硬编码的0A,这是换行符LF(Line Feed)的Unicode编码值。
既然APC是一种基于事件驱动的通信机制,必然少不了EventHandler的实现。
上图第7行代码,调用create创建TCP客户端实例时,还需要给其维护一个事件处理类的实例。
这个事件处理类的实现,语义也很清晰,如上图所示。
- 基于ABAP Push Channel机制实现的事件处理类,需要实现标准接口if_apc_wsp_event_handler.
- 该接口声明的on_open方法,会在客户端和服务器端成功建立TCP连接后自动触发。这个方法内,可以通过输入参数I_CONTEXT,获得更多的关于成功建立的TCP连接上下文信息。
- 该接口声明的on_message方法,在服务器端有数据推送到客户端时自动触发。上图通过i_message的get_text方法,将服务器端发送回来的字符串数据,存储到类实例的message成员变量里。
客户端实例创建成功之后,调用其connect方法,即可与服务器建立TCP连接。
客户端发送数据到服务器端
下面的代码都是自描述的,语义很容易理解。
- 调用client实例的get_message_manager方法,拿到客户端的消息管理器实例。
- 调用消息管理器的create_message方法,生成一条新的空白消息。
- 将硬编码的TCP帧终止符,即换行符的Unicde Code 0A, 转换成二进制格式。
- 将用户硬编码的
Hello TCP, answer me!
字符串转换成二进制格式。将第三步换行符的二进制格式添加到其尾部,组装成一个完整的TCP Frame. - 将上一步骤组装好的TCP Frame,调用消息管理器的send方法发送给服务器。
客户端从TCP连接读取服务器端发送的响应数据
客户端调用WAIT FOR PUSH CHANNELS
语句,等待服务器端写入数据到TCP连接中。
当服务器端写入数据后,会触发之前提到的客户端事件处理类的ON_MESSAGE方法,这个方法会将服务器端响应的字符串内容,保存到事件处理类实例的message成员变量中。
这个操作导致逻辑表达式UNTIL event_handler->message
的值变为true,因此ABAP客户端继续从WAIT语句的下一行开始执行。
引入UP TO 10 SECONDS即指定WAIT的等待时长,最多维持10秒。
根据WAIT语句的返回值sy-subrc判断客户端读取TCP连接中的数据是否成功。
- 0说明成功读取。
- 4说明当前并没有为APC注册事件处理。
- 8说明UP TO指定的10秒超时已经到达。
至此这个用ABAP编写的TCP客户端已经完成,简单测试一下。
执行DEMO_APC_TCP_CLIENT报表之后,会看到如下对话框。
TCP_SERVER显示的是NCAT工具的本地路径,然后是本地IP地址和端口号。该报表会启动操作系统的CMD命令提示行工具,加载NCAT工具并监听在这个IP地址和端口号,充当TCP服务器的角色。
TERMINATOR 0A即TCP Frame终结符的Unicode编码,本例我们采用换行符Line Feed作为终结符,值为0A.
MSG即客户端发送给服务器端的字符串内容。
点击Enter按钮,看到CMD命令提示行窗口内,已经成功打印出客户端发送过来的Hello TCP的字符串,说明通信成功。
此时在NCAT的CMD窗口内,手动输入一些内容,作为服务器端发送回客户端的数据,比如输入this is data sent by server.
随即我们在SAPGUI的客户端弹出对话框里,收到了这条来自服务器的消息。
如果我们在事件处理类的on_message里设置断点,会发现当服务器发送响应数据时,该方法会被APC框架触发,并且在调试器里观察收到的数据,确实是以0A这个终结符结尾。
后续将介绍更多关于ABAP Push Channel的系列内容。