?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 通信。 它為實現無連接、面向數據報的通信提供了一個高級接口。具體的函數信息可以從下方得到:
UdpClose 函數
?主要是關閉 UDP Socket。函數成功執行后,傳遞的 socket 不再有效。具體的使用范例請在文章末尾查看。具體的使用結構如下:
?函數的返回值的情況如下:
??0: 函數執行成功
??WSA_INVALID_PARAMETER (87): 指定的 socket 無效
??SOCKET_ERROR (-1): 函數執行失敗。錯誤內容使用函數 IpGetLastError 查詢
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 socketSendCommand(gSocket1, "Request");// wait for responsegSocket1.ReceiveFrom(gBuffer, elcount(gBuffer));
}on key '2'
{// send on the connected socketSendCommand(gSocket2, "Request");// wait for responsegSocket1.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 connectionsstruct 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 datagListeningSocket = 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 connectionUdpConnect(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);}
}
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 );
}
UdpReceiveFrom 函數
?主要是接收數據到指定的緩沖區。 如果接收操作沒有立即完成,操作將異步執行,函數將返回 SOCKET_ERROR (-1)。 使用 IpGetLastSocketError 獲取更具體的錯誤代碼。 如果特定的錯誤代碼是 WSA_IO_PENDING (997),則 CAPL 回調 OnUdpReceiveFrom 將在完成時調用(成功與否),前提是它在同一個 CAPL 程序中實現。具體的使用范例請在文章末尾查看。具體的使用結構如下:
?函數的返回值的情況如下:
??0: 函數執行成功
??WSA_INVALID_PARAMETER (87): 指定的 socket 無效
??SOCKET_ERROR (-1): 函數執行失敗。錯誤內容使用函數 IpGetLastError 查詢
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) );}
}
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) );}
}
OnUdpSendTo 函數
?主要是當 UDP 套接字上的異步發送操作完成時調用。具體的使用格式如下
? 示例
// ---------------------------------------------------
// node global variables.
// ---------------------------------------------------
variables
{const int gMTU = 1500; // tcp mtuconst 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 sizeconst dword gINVALID_SOCKET = ~0; // invalid socket constantdword gListenPort = 12345; // port to send udp to.dword gListenSocket = gINVALID_SOCKET; // server side: server listen socketdword gServerClientSocket = gINVALID_SOCKET; // server side: a client's socketchar 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{// failurewriteLineEx( 1, 3, "S: TcpReceive error %d", result);}}else if (result != 0) // synchronous sending failed{// failurewriteLineEx( 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);}}
}
總結
以上是生活随笔為你收集整理的CPAL脚本自动化测试 ———— UDP 系列函数的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。