UDP通信

来源:互联网 发布:小鸡模拟器支持mac吗 编辑:程序博客网 时间:2024/05/22 15:36

  

    UDP 是User Datagram Protocol的简称, 中文名是用户数据包协议,是 OSI(开放式系统互联) 参考模型中一种无连接的传输层协议,提供面向事务的简单不可靠信息传送服务。

    在IP中,无连接通信是通过UDP/IP协议完成的。UDP不能确保可靠的数据传输,但能将数据发送到多个源数据。例如,如果一个客户机向一个服务器发送数据,则数据将立刻被传输,不管服务器是否准备接收这些数据。如果服务器接收来自客户机的数据,该服务器也不会发送消息确认数据已收到。数据的传输使用数据报,即离散信息包。

    图1.1给出了典型的UDP客户-服务器程序函数调用。客户不与服务器建立连接,它只管用函数sendto给服务器发送数据报,此函数要求目的地址(服务器)作为其参数,类似的。服务器不从客户接收连接,它只管调用函数recvfrom,等待来自某客户的数据到达,与数据报一起,recvfrom返回客户的协议地址,所以服务器可以响应给正确的客户。


                        图1.1UDP程序模型

接收端

对于在一个无连接套接字上接收数据的进程来说,步骤并不复杂。先用socketWSASocket建立套接字。再把这个套接字和准备接收数据的接口绑定在一起。这是通过bind函数(和面向会话的示例一样)来完成的。和面向会话不同的是,我们不必调用listenaccept。相反,只需等待接收数据。由于它是无连接的,因此始发于网络上任何一台机器的数据报都可被接收端的套接字接收。最简单的接收函数是recvfrom。它的定义如下:

int recvfrom(

    SOCKET s,

    char FAR* buf,

    int len,

    int flags,

    struct sockaddr FAR* from,

    int FAR* fromlen

);

    s:是准备用来接收数据的那个套接字。

    buf:是用于接收数据的字符缓冲区。

    len:是准备接收的字节数或buf缓冲区长度。

flags:调用操作方式,可以是下面的值:0、MSG_PEEK或MSG_OOB。0表示

       没有特殊行为。MSG_PEEK 查看当前数据,数据将被复制到缓冲区

       中,但并不从输入队列中删除。MSG_OOB 处理带外数据。

    from:(可选)指针,指向装有源地址的缓冲区。

fromlen:(可选)指针,指向from缓冲区长度值。

返回值:若无错误发生,recvfrom()返回读入的字节数。如果连接已中止,

        返回0。否则的话,返回SOCKET_ERROR错误,应用程序可通过

        WSAGetLastError()获取相应的错误代码。

发送端

要在一个无连接的套接字上发送数据,最简单的便是建立一个套接字,然后调用sendto或WSASendTo。它的定义是这样的:

int sendto (

    SOCKET s,

        const char FAR * buf,

        int len,

        int flags,

        const struct sockaddr FAR *to,

        int tolen

   );

        s:是准备用来发送数据的那个套接字。

        buf:是用于发送数据的字符缓冲区。

        len:是准备接发送的字节数或buf缓冲区长度。

        flags:调用操作方式,可以是下面的值:0、MSG_PEEK或MSG_OOB。

               0表示没有特殊行为。MSG_PEEK 查看当前数据,数据将被复制 

               到缓冲区中,但并不从输入队列中删除。MSG_OOB 处理带外数

               据。改变flags,将会改变sendto发送的形式。

        to:(可选) 指针,指向目的套接口的地址。


      tolen:to所指地址的长度。 

        返回值:为整型,如果成功,则返回发送的字节数,失败则返回

                SOCKET_ERROR。

附代码:

服务器端:

#include <winsock2.h>#include <stdio.h>#pragma comment(lib,"ws2_32.lib")void main(void){   WSADATA              wsaData;   SOCKET               ReceivingSocket;   SOCKADDR_IN          ReceiverAddr;   int                  Port = 5150;   char                 ReceiveBuf[1024];   int                  BufLength = 1024;   SOCKADDR_IN          SenderAddr;   int                  SenderAddrSize = sizeof(SenderAddr);   int                  Ret; if ((Ret = WSAStartup(MAKEWORD(2,2), &wsaData)) != 0)   {      printf("ERROR: WSAStartup failed with error %d\n", Ret);      return;   }   if ((ReceivingSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))       == INVALID_SOCKET)   {      printf("ERROR: socket failed with error %d\n", WSAGetLastError());      WSACleanup();      return;   }    ReceiverAddr.sin_family = AF_INET;   ReceiverAddr.sin_port = htons(Port);       ReceiverAddr.sin_addr.s_addr = htonl(INADDR_ANY);   if (bind(ReceivingSocket, (SOCKADDR *)&ReceiverAddr, sizeof(ReceiverAddr))       == SOCKET_ERROR)   {      printf("ERROR: bind failed with error %d\n", WSAGetLastError());      closesocket(ReceivingSocket);      WSACleanup();      return;   }   printf("We are ready to receive 1 datagram from any interface on port %d...\n",          Port);   if ((Ret = recvfrom(ReceivingSocket, ReceiveBuf, BufLength, 0,       (SOCKADDR *)&SenderAddr, &SenderAddrSize)) == SOCKET_ERROR)   {      printf("ERROR: recvfrom failed with error %d\n", WSAGetLastError());      closesocket(ReceivingSocket);      WSACleanup();      return;   }   printf("We successfully received %d bytes from address %s:%d.\n", Ret,          inet_ntoa(SenderAddr.sin_addr), ntohs(SenderAddr.sin_port));   closesocket(ReceivingSocket);   WSACleanup();}


客户端:

#include <winsock2.h>#include <stdio.h>#pragma comment(lib,"ws2_32.lib")void main(int argc, char **argv){   WSADATA              wsaData;   SOCKET               SendingSocket;   SOCKADDR_IN          ReceiverAddr;   int                  Port = 5150;   int                  Ret;   if (argc <= 1)   {      printf("USAGE: udpsender <receiver IP address>.\n");      return;   }    if ((Ret = WSAStartup(MAKEWORD(2,2), &wsaData)) != 0)   {           printf("ERROR: WSAStartup failed with error %d\n", Ret);      return;   }       if ((SendingSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))       == INVALID_SOCKET)   {      printf("ERROR: socket failed with error %d\n", WSAGetLastError());      WSACleanup();      return;   }   ReceiverAddr.sin_family = AF_INET;   ReceiverAddr.sin_port = htons(Port);       ReceiverAddr.sin_addr.s_addr = inet_addr(argv[1]);   if ((Ret = sendto(SendingSocket, "Hello", 5, 0,        (SOCKADDR *)&ReceiverAddr, sizeof(ReceiverAddr))) == SOCKET_ERROR)   {      printf("ERROR: sendto failed with error %d\n", WSAGetLastError());      closesocket(SendingSocket);      WSACleanup();      return;   }   printf("We successfully sent %d byte(s) to %s:%d.\n", Ret,          inet_ntoa(ReceiverAddr.sin_addr), htons(ReceiverAddr.sin_port));   closesocket(SendingSocket);   WSACleanup();}


本地调试成功结果:

ServerWe are ready to receive 1 datagram from any interface on port 5150.

       We successfully received 5 bytes from address 127.0.0.1:65532.

ClientWe successfully sent 5 byte(s) to 127.0.0.1:5150.