CPAL脚本自动化测试 ———— UDP 系列函数

 UDP 是 User Datagram Protocol 的简称, 中文名是用户数据报协议,是 OSI(Open System Interconnection,开放式系统互联) 参考模型中一种无连接的传输层协议,提供面向事务的简单不可靠信息传送服务,IETF RFC 768 是UDP的正式规范。UDP 在 IP 报文的协议号是17。UDP 协议与 TCP 协议一样用于处理数据包,在 OSI 模型中,两者都位于传输层,处于 IP 协议的上一层。UDP 有不提供数据包分组、组装和不能对数据包进行排序的缺点,也就是说,当报文发送之后,是无法得知其是否安全完整到达的。UDP 用来支持那些需要在计算机之间传输数据的网络应用。包括网络视频会议系统在内的众多的客户/服务器模式的网络应用都需要使用 UDP 协议。UDP 报文没有可靠性保证、顺序保证和流量控制字段等,可靠性较差。但是正因为 UDP 协议的控制选项较少,在数据传输过程中延迟小、数据传输效率高,适合对可靠性要求不高的应用程序,或者可以保障可靠性的应用程序,如 DNS、TFTP、SNMP 等。


 UDP API 用于 UDP 通信。 它为实现无连接、面向数据报的通信提供了一个高级接口。具体的函数信息可以从下方得到:

  1. UdpClose 函数
     主要是关闭 UDP Socket。函数成功执行后,传递的 socket 不再有效。具体的使用范例请在文章末尾查看。具体的使用结构如下:
    在这里插入图片描述
     函数的返回值的情况如下:
      0: 函数执行成功
      WSA_INVALID_PARAMETER (87): 指定的 socket 无效
      SOCKET_ERROR (-1): 函数执行失败。错误内容使用函数 IpGetLastError 查询

  2. UdpConnect 函数
     主要是将此 socket 连接到给定的远程端点。socket 连接后,必须使用 UdpSend 而不是 UdpSendTo。在服务器端,当第一次在 socket 上接收数据时,可以连接到远程端点。 之后,可以创建一个新的未连接的 Socket 以等待下一个传入的 udp 连接。具体的使用结构如下:
    在这里插入图片描述
     函数的返回值的情况如下:
      0: 函数执行成功
      WSA_INVALID_PARAMETER (87): 指定的 socket 无效
      SOCKET_ERROR (-1): 函数执行失败。错误内容使用函数 IpGetLastError 查询


    示例

// Client.can
variables
{
  UdpSocket gSocket1;
  UdpSocket gSocket2;
  char gBuffer[1500];
}

on start
{
  gSocket1 = UdpSocket::Open( IP_Endpoint(0.0.0.0:0) );
  gSocket2 = UdpSocket::Open( IP_Endpoint(0.0.0.0:0) );
  gSocket1.Connect(IP_Endpoint(192.168.1.3:40002));
  gSocket2.Connect(IP_Endpoint(192.168.1.3:40002));
}

on key '1'
{
  // send on the connected socket
  SendCommand(gSocket1, "Request");

  // wait for response
  gSocket1.ReceiveFrom(gBuffer, elcount(gBuffer));
}

on key '2'
{
  // send on the connected socket
  SendCommand(gSocket2, "Request");

  // wait for response
  gSocket1.ReceiveFrom(gBuffer, elcount(gBuffer));
}

on key 'c'
{
  SendCommand(gSocket1, "End");
  gSocket1.Close();

  SendCommand(gSocket2, "End");
  gSocket1.Close();
}

SendCommand(UdpSocket socket, char command[])
{
  socket.Send(command, strlen(command));
}

OnUdpReceiveFrom(dword socket, long result, IP_Endpoint remoteEndpoint, char buffer[], dword size)
{
  // handle the response from the server here
}

//Server.can
variables
{
  // context to handle the state of the different connections
  struct connectionContext
  {
    int connectionNumber;
  };

  dword gListeningSocket;
  struct connectionContext connections[long];
  char gBuffer[1500];
  dword gConnectionCount;
}

on start
{
  gConnectionCount = 0;
  // open a socket and wait for the first data
  gListeningSocket = UdpOpen( IP_Endpoint(0.0.0.0:40002) );
  UdpReceiveFrom(gListeningSocket, gBuffer, elcount(gBuffer));
}

OnUdpReceiveFrom(dword socket, long result, IP_Endpoint remoteEndpoint, char buffer[], dword size)
{
  if(socket == gListeningSocket)
  {
    // create a context for this connection and open a new socket for the
    // next connection

    UdpConnect(socket, remoteEndpoint);
    connections[socket].connectionNumber = ++gConnectionCount;
    gListeningSocket = UdpOpen( IP_Endpoint(0.0.0.0:40002) );
    UdpReceiveFrom(gListeningSocket, gBuffer, elcount(gBuffer));
  }
  AnswerRequest(socket, buffer, size);
}

AnswerRequest(dword socket, char buffer[], dword size)
{
  char response[100];

  if(strncmp(buffer, "Request", size) == 0)
  {
    snprintf(response, elcount(response), "Response for connection #%d", connections[socket].connectionNumber);
    UdpSend(socket, response, strlen(response));
    UdpReceiveFrom(socket, gBuffer, elcount(gBuffer));
  }
  else if(strncmp(buffer, "End", size) == 0)
  {
    connections.remove(socket);
    UdpClose(socket);
  }
}

  1. UdpSend 函数
     主要是在连接的 UDP socket 上发送数据。 调用这个函数前需要先用 UdpConnect 连接socket。具体的使用结构如下:
    在这里插入图片描述
     函数的返回值的情况如下:
      0: 函数执行成功
      WSA_INVALID_PARAMETER (87): 指定的 socket 无效
      SOCKET_ERROR (-1): 函数执行失败。错误内容使用函数 IpGetLastError 查询


    示例
variables
{
  UdpSocket gSocket;
}

on start
{
  gSocket = UdpSocket::Open( IP_Endpoint(0.0.0.0:0) );
  gSocket.Connect(ip_Endpoint(192.168.1.3:40002));
  gSocket.Send( "Request", 7 );
}

  1. UdpReceiveFrom 函数
     主要是接收数据到指定的缓冲区。 如果接收操作没有立即完成,操作将异步执行,函数将返回 SOCKET_ERROR (-1)。 使用 IpGetLastSocketError 获取更具体的错误代码。 如果特定的错误代码是 WSA_IO_PENDING (997),则 CAPL 回调 OnUdpReceiveFrom 将在完成时调用(成功与否),前提是它在同一个 CAPL 程序中实现。具体的使用范例请在文章末尾查看。具体的使用结构如下:
    在这里插入图片描述
     函数的返回值的情况如下:
      0: 函数执行成功
      WSA_INVALID_PARAMETER (87): 指定的 socket 无效
      SOCKET_ERROR (-1): 函数执行失败。错误内容使用函数 IpGetLastError 查询

  2. UdpSendTo 函数
     主要是将数据发送到指定位置。 如果发送操作没有立即完成,操作将异步执行,函数将返回 SOCKET_ERROR (-1)。 使用 IpGetLastSocketError 获取更具体的错误代码。 如果具体的错误代码是 WSA_IO_PENDING (997),并且在完成(成功与否)时会调用 CAPL 回调 OnUdpSendTo,前提是它是在同一个 CAPL 程序中实现的。如果操作已被同步处理,则不会调用 CAPL 回调 OnUdpSendTo。具体的使用格式如下:
    在这里插入图片描述
     函数的返回值的情况如下:
      0: 函数执行成功
      WSA_INVALID_PARAMETER (87): 指定的 socket 无效
      SOCKET_ERROR (-1): 函数执行失败。错误内容使用函数 IpGetLastError 查询


    示例
variables
{
  UdpSocket gSocket;
  char gRxBuffer[1000];
}

on start
{
  gSocket = UdpSocket::Open( IP_Endpoint(0.0.0.0:40001) );
  gSocket.SendTo( IP_Endpoint(192.168.0.2:40002), "Hello", 5 );
  gSocket.ReceiveFrom( gRxBuffer, elcount( gRxBuffer) );
}

OnUdpReceiveFrom( UdpSocket socket, long result, IP_Endpoint remoteEndpoint, char buffer[], dword size)
{
  if (result == 0)
  {
    write( "Received: %s", buffer );
    gSocket.ReceiveFrom( gRxBuffer, elcount( gRxBuffer) );
  }
}

  1. OnUdpReceiveFrom 函数
     主要是当 UDP socket 上的异步接收操作完成时调用。堆栈包含一个数据队列,一旦数据位于该队列中,该队列就会被 UdpReceiveFrom 减少。因此,为了将来从数据队列中接收额外的数据用于 socket,必须在回调中再次调用 UdpReceiveFrom。具体的使用格式如下:
    在这里插入图片描述
    示例
variables
{
  UdpSocket gSocket;
  char gRxBuffer[1000];
}

on start
{
  gSocket = UdpSocket::Open( IP_Endpoint(0.0.0.0:40001) );
  gSocket.SendTo( IP_Endpoint(192.168.0.2:40002), "Hello", 5 );
  gSocket.ReceiveFrom( gRxBuffer, elcount( gRxBuffer) );
}

OnUdpReceiveFrom( UdpSocket socket, long result, IP_Endpoint remoteEndpoint, char buffer[], dword size)
{
  if (result == 0)
  {
    write( "Received: %s", buffer );
    gSocket.ReceiveFrom( gRxBuffer, elcount( gRxBuffer) );
  }
}
  1. OnUdpSendTo 函数
     主要是当 UDP 套接字上的异步发送操作完成时调用。具体的使用格式如下在这里插入图片描述
    示例
// ---------------------------------------------------
// node global variables.
// ---------------------------------------------------
variables
{
  const int gMTU = 1500;               // tcp mtu
  const int gSERVER_REPLY_WELCOME = 1; // server reply for welcome.
  const int gSERVER_REPLY_ANSWER = 2;  // server reply for answer.
  const dword gIPV4_STR_SIZE = 16;     // IPv4 string size
  const dword gINVALID_SOCKET = ~0;    // invalid socket constant
  dword gListenPort = 12345;           // port to send udp to.
  dword gListenSocket = gINVALID_SOCKET;       // server side: server listen socket
  dword gServerClientSocket = gINVALID_SOCKET; // server side: a client's socket
  char gServerTcpBuffer[gMTU];                 // tcp receive buffer of server
}

// ---------------------------------------------------
// Interaction: Server disconnects client...
// ---------------------------------------------------
on key 'x'
{
  serverDisconnectClient();
}

// ---------------------------------------------------
// on measurement start. (initialize and start demo)
// ---------------------------------------------------
on start
{
  serverStart();
}

// ---------------------------------------------------
// before measurement stops.
// ---------------------------------------------------
on preStop
{
  // close server ( this implies closing all server and client sockets. )
  serverClose();
}

// ---------------------------------------------------
// Callback when client connects to server's listen socket.
// ---------------------------------------------------
void OnTcpListen( dword socket, long result)
{
  dword errCode;
  writeLineEx(1, 1, " [ S: OnTcpListen called. (result: %d)]", result);
  if (gServerClientSocket != gINVALID_SOCKET)
  {
    writeLineEx(1, 2, "S: A client is already connected. Not accepting.");
    return;
  }
  if (result == 0)
  {
    if (socket == gListenSocket)
    {
      write("S: Incoming client.", socket);
      gServerClientSocket = TcpAccept( gListenSocket );
      if (gServerClientSocket == gINVALID_SOCKET)
      {
        errCode = IpGetLastSocketError(gListenSocket);
        if (errCode == 87)
        {
          writeLineEx( 1, 3, "S: TcpAccept: Invalid listen socket given.");
          // handle error...
        }
        else
        {
          writeLineEx( 1, 3, "S: TcpAccept: Socket error: %d", IpGetLastSocketError(gListenSocket) );
          // handle error...
        }
      }
      else
      {
        write("S: Accepted client on socket %d to socket %d.", gListenSocket, gServerClientSocket);
        // start to receive data on the server's client socket...
        startReceive(gServerClientSocket, gServerTcpBuffer);
        // do more stuff on server to initialize the incoming accepted client...
        // welcome client.
        serverSend(gSERVER_REPLY_WELCOME, gServerClientSocket);
      }
    }
    else
    {
      writeLineEx( 1, 3, "S: OnTcpListen: Unexpected connection on socket %d. (result:%d)", socket, result);
      // handle error...
    }
  }
}

// ---------------------------------------------------
// When asynchronous TcpSend completes...
// ---------------------------------------------------
void OnTcpSend( dword socket, long result, char buffer[], dword size)
{
  writeLineEx(1, 1, " [ S: OnTcpSend called. (result: %d)]", result);
  if (result == 0)
  {
    if (socket != gINVALID_SOCKET)
    {
      if (socket == gServerClientSocket)
      {
        write("S: Server sent %d bytes to client done. (socket %d, result: %d)", size, socket, result);
      }
    }
  }
}

// ---------------------------------------------------
// When receiving data on socket...
// ---------------------------------------------------
void OnTcpReceive( dword socket, long result, dword address, dword port, char buffer[], dword size)
{
  writeLineEx(1, 1, " [ S: OnTcpReceive called. (result: %d)]", result);
  if (result == 0)
  {
    if (socket == gServerClientSocket)
    {
      // server receives from client...
      write("S: Server received %d bytes from client: %s (result: %d)", size, buffer, result);
      // check client's request...
      if (strstr(buffer, "REQUEST") >= 0)
      {
        write("S: Client request OK, sending answer.");
        serverSend(gSERVER_REPLY_ANSWER, gServerClientSocket); // answer
      }
      // continue receiving data.
      startReceive(gServerClientSocket, gServerTcpBuffer);
    }
    else if (socket != gINVALID_SOCKET)
    {
      writeLineEx(1, 3, " [ S: UNIMPLEMENTED: Received %d bytes on socket %d from 0x%x:%d with data: %s (result: %d) ]", size, socket, address, port, buffer, result);
    }
  }
}

// ---------------------------------------------------
// TCP socket receives a close notification
// (remote closed)
// ---------------------------------------------------
void OnTcpClose( dword socket, long result)
{
  if (socket == gServerClientSocket)
  {
    TcpClose(gServerClientSocket);
    gServerClientSocket = gINVALID_SOCKET;
    writeLineEx(1, 1, " [ S: OnTcpClose called. (socket: %d, result: %d) ]", socket, result);
  }
}

// ---------------------------------------------------
// server disconnects client
// ---------------------------------------------------
void serverDisconnectClient()
{
  if (gServerClientSocket != gINVALID_SOCKET)
  {
    write("S: Server disconnects client. (socket %d)", gServerClientSocket);
    TcpClose(gServerClientSocket);
    gServerClientSocket = gINVALID_SOCKET;
  }
}

// ---------------------------------------------------
// start receiving on given socket into given buffer.
// ---------------------------------------------------
void startReceive ( dword socket, char buffer[] )
{
  long result;
  result = TcpReceive( socket, buffer, elcount(buffer) );
  if (result == -1)
  {
    result = IpGetLastSocketError(socket);
    if (result != 997) // not asynchronous
    {
      // failure
      writeLineEx( 1, 3, "S: TcpReceive error %d", result);
    }
  }
  else if (result != 0) // synchronous sending failed
  {
    // failure
    writeLineEx( 1, 3, "S: TcpReceive error %d", result);
  }
}

// ---------------------------------------------------
// start server
// ---------------------------------------------------
void serverStart()
{
  writeLineEx(1, 1, " [ S: Open TCP server socket at port %d... ]", gListenPort);
  gListenSocket = TcpOpen(0, gListenPort);
  if (gListenSocket == gINVALID_SOCKET)
  {
    writeLineEx( 1, 3, " [ S: TcpOpen: Error opening TCP Socket on port %d. (Error %d) ]", gListenPort, IpGetLastError() );
    // handle error...
  }
  else
  {
    if (TcpListen( gListenSocket ) != 0)
    {
      writeLineEx(1, 3, " [ S: TcpListen: Error listening on socket. ]");
      TcpClose(gListenSocket);
      gListenSocket = gINVALID_SOCKET;
      // handle error...
    }
    else
    {
      writeLineEx(1, 1, " [ S: Start listening on server socket %d... ]", gListenSocket);
    }
  }
}

// ---------------------------------------------------
// close server
// ---------------------------------------------------
void serverClose()
{
  if (gListenSocket != gINVALID_SOCKET)
  {
    writeLineEx(1, 1, " [ Server shutdown. ]");
    serverDisconnectClient();
    TcpClose(gListenSocket);
    gListenSocket = gINVALID_SOCKET;
  }
}

// ---------------------------------------------------
// server sends data to client
// ---------------------------------------------------
void serverSend(int replyNr, dword socket)
{
  if (socket != gINVALID_SOCKET)
  {
    writeLineEx(1, 1, "S: Sending data to client. (socket %d)", socket);
    switch(replyNr)
    {
      case gSERVER_REPLY_WELCOME:
      {
        sendTcpData( socket, " Server data: WELCOME.");
        break;
      }
      case gSERVER_REPLY_ANSWER:
      {
        sendTcpData(socket, "Server data: ANSWER.");
        break;
      }
      default:
      {
        writeLineEx(1, 3, " [ serverSend: UNSUPPORTED REPLY NR %d ]", replyNr);
        break;
      }
    }
  }
}

// ---------------------------------------------------
// send tcp data.
// ---------------------------------------------------
void sendTcpData( dword socket, char data[] )
{
  long result;
  dword size;
  size = elcount(data);
  result = TcpSend(socket, data, size);
  if (result == 0)
  {
    // sending took place immediately.
    writeLineEx(1, 1, " [ S: Synchronous sending: '%s' on socket %d ]", data, socket);
    OnTcpSend(socket, result, data, size); // trigger callback manually
  }
  else
  {
    if (result == -1)
    {
      result = IpGetLastSocketError(socket);
      if (result == 997)
      {
        // sending is done asynchronously.
        writeLineEx(1, 1, " [ S: Asynchronous sending: '%s' on socket %d ]", data, socket);
        // => OnTcpSend is called when done sending.
      }
      else
      {
        writeLineEx( 1, 3, " [ S: sendTcpData: Error sending data. (%d) ]", result);
      }
    }
    else
    {
      writeLineEx( 1, 3, " [ S: sendTcpData: Error sending data. (%d) ]", result);
    }
  }
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小趴菜_自动驾驶搬砖人

谢谢大爷赏饭吃

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值