UDP(user datagram protocol)用户数据报协议,属于传输层。

  UDP是面向非连接的协议,它不与对方建立连接,而是直接把数据报发给对方。UDP无需建立类如三次握手的连接,使得通信效率很高。因此UDP适用于一次传输数据量很少、对可靠性要求不高的或对实时性要求高的应用场景。

UDP协议 sendto 和 recvfrom 浅析与示例-LMLPHP

  UDP通信的过程如图所示:

    服务端:

      (1)使用函数socket(),生成套接字文件描述符;

      (2)通过struct sockaddr_in 结构设置服务器地址和监听端口;

      (3)使用bind() 函数绑定监听端口,将套接字文件描述符和地址类型变量(struct sockaddr_in )进行绑定;

      (4)接收客户端的数据,使用recvfrom() 函数接收客户端的网络数据;

      (5)向客户端发送数据,使用sendto() 函数向服务器主机发送数据;

      (6)关闭套接字,使用close() 函数释放资源;

    客户端:

      (1)使用socket(),生成套接字文件描述符;

      (2)通过struct sockaddr_in 结构设置服务器地址和监听端口;

      (3)向服务器发送数据,sendto() ;

      (4)接收服务器的数据,recvfrom() ;

      (5)关闭套接字,close() ;

  (关于 sockaddr sockaddr_in 的区别,可参考:https://blog.csdn.net/qingzhuyuxian/article/details/79736821

sendto()

  int sendto(int s, const void *buf, int len, unsigned int flags,
        const struct sockaddr *to, int tolen);

  返回值说明:

    成功则返回实际传送出去的字符数,失败返回-1,错误原因会存于errno 中。

  参数说明:

    s:      socket描述符;
    buf:  UDP数据报缓存区(包含待发送数据);
    len:   UDP数据报的长度;
    flags:调用方式标志位(一般设置为0);
    to:  指向接收数据的主机地址信息的结构体(sockaddr_in需类型转换);
    tolen:to所指结构体的长度;

recvfrom()

 int recvfrom(int s, void *buf, int len, unsigned int flags,
      struct sockaddr *from, int *fromlen);

  返回值说明:

    成功则返回实际接收到的字符数,失败返回-1,错误原因会存于errno 中。

  参数说明:

    s:          socket描述符;
    buf:       UDP数据报缓存区(包含所接收的数据); 
    len:       缓冲区长度。 
    flags:    调用操作方式(一般设置为0)。 
    from:     指向发送数据的客户端地址信息的结构体(sockaddr_in需类型转换);
    fromlen:指针,指向from结构体长度值。

示例代码

服务端

 #include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <iostream>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h> #define MAXLINE 4096
#define UDPPORT 8001
#define SERVERIP "192.168.255.129" using namespace std; int main(){
int serverfd;
unsigned int server_addr_length, client_addr_length;
char recvline[MAXLINE];
char sendline[MAXLINE];
struct sockaddr_in serveraddr , clientaddr; // 使用函数socket(),生成套接字文件描述符;
if( (serverfd = socket(AF_INET, SOCK_DGRAM, )) < ){
perror("socket() error");
exit();
} // 通过struct sockaddr_in 结构设置服务器地址和监听端口;
bzero(&serveraddr,sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
serveraddr.sin_port = htons(UDPPORT);
server_addr_length = sizeof(serveraddr); // 使用bind() 函数绑定监听端口,将套接字文件描述符和地址类型变量(struct sockaddr_in )进行绑定;
if( bind(serverfd, (struct sockaddr *) &serveraddr, server_addr_length) < ){
perror("bind() error");
exit();
} // 接收客户端的数据,使用recvfrom() 函数接收客户端的网络数据;
client_addr_length = sizeof(sockaddr_in);
int recv_length = ;
recv_length = recvfrom(serverfd, recvline, sizeof(recvline), , (struct sockaddr *) &clientaddr, &client_addr_length);
cout << "recv_length = "<< recv_length <<endl;
cout << recvline << endl; // 向客户端发送数据,使用sendto() 函数向服务器主机发送数据;
int send_length = ;
sprintf(sendline, "hello client !");
send_length = sendto(serverfd, sendline, sizeof(sendline), , (struct sockaddr *) &clientaddr, client_addr_length);
if( send_length < ){
perror("sendto() error");
exit();
}
cout << "send_length = "<< send_length <<endl; //关闭套接字,使用close() 函数释放资源;
close(serverfd); return ;
}

客户端

 #include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <iostream>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h> #define MAXLINE 4096
#define UDPPORT 8001
#define SERVERIP "192.168.255.129" using namespace std; int main(){
int confd;
unsigned int addr_length;
char recvline[MAXLINE];
char sendline[MAXLINE];
struct sockaddr_in serveraddr; // 使用socket(),生成套接字文件描述符;
if( (confd = socket(AF_INET, SOCK_DGRAM, )) < ){
perror("socket() error");
exit();
} //通过struct sockaddr_in 结构设置服务器地址和监听端口;
bzero(&serveraddr, sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = inet_addr(SERVERIP);
serveraddr.sin_port = htons(UDPPORT);
addr_length = sizeof(serveraddr); // 向服务器发送数据,sendto() ;
int send_length = ;
sprintf(sendline,"hello server!");
send_length = sendto(confd, sendline, sizeof(sendline), , (struct sockaddr *) &serveraddr, addr_length);
if(send_length < ){
perror("sendto() error");
exit();
}
cout << "send_length = " << send_length << endl; // 接收服务器的数据,recvfrom() ;
int recv_length = ;
recv_length = recvfrom(confd, recvline, sizeof(recvline), , (struct sockaddr *) &serveraddr, &addr_length);
cout << "recv_length = " << recv_length <<endl;
cout << recvline << endl; // 关闭套接字,close() ;
close(confd); return ;
}
05-11 21:54