技术分析:基本 UDP 套接字编程(1)


技术分析:基本 UDP 套接字编程

UDP 协议和 TCP 协议不同,它是一种面向无连接、不可靠的传输层协议。在基于 UDP 套接字编程中,数据传输可用函数 sendto 和 recvfrom。以下是基本 UDP 套接字编程过程:

sendto 与 recvfrom 函数

这两个函数的功能类似于 write 和 read 函数,可用无连接的套接字编程。其定义如下:

  1. /* 函数功能:发送数据;  
  2.  * 返回值:若成功则返回已发送的字节数,若出错则返回-1;  
  3.  * 函数原型:  
  4.  */   
  5. #include <sys/socket.h>   
  6.    
  7. ssize_t sendto(int sockfd, void *buff, size_t nbytes, int flags,   
  8.                 const struct sockaddr *destaddr, socklen_t addrlen);   
  9.    
  10. /* 说明:  
  11.  * 该函数功能类似于write函数,除了有标识符flags和目的地址信息之外,其他参数一样;  
  12.  *  
  13.  * flags标识符取值如下:  
  14.  * 1)MSG_DONTROUTE   勿将数据路由出本地网络  
  15.  * 2)MSG_DONTWAIT    允许非阻塞操作  
  16.  * 3)MSG_EOR         如果协议支持,此为记录结束  
  17.  * 4)MSG_OOB         如果协议支持,发送带外数据  
  18.  *  
  19.  * 若sendto成功,则只是表示已将数据无错误的发送到网络,并不能保证正确到达对端;  
  20.  * 该函数通过指定目标地址允许在无连接的套接字之间发送数据例如UDP套接字);  
  21.  */   
  22.    
  23.  /* 函数功能:接收数据;  
  24.   * 返回值:以字节计数的消息长度,若无可用消息或对方已经按序结束则返回0,若出错则返回-1;  
  25.   * 函数原型:  
  26.   */   
  27. #include <sys/socket.h>   
  28.    
  29. ssize_t recvfrom(int sockfd, void *buff, size_t nbytes, int flags,   
  30.                 struct sockaddr *addr, socklen_t *addrlen);   
  31.  /* 说明:  
  32.   * 该函数功能与read类似;  
  33.   * 若addr为非空时,它将包含数据发送者的套接字地址;  
  34.   *  
  35.   * flags标识符取值如下:  
  36.   * 1)MSG_WAITALL     等待所有数据可用  
  37.   * 2)MSG_DONTWAIT    允许非阻塞操作  
  38.   * 3)MSG_PEEK        查看已读取的数据  
  39.   * 4)MSG_OOB         如果协议支持,发送带外数据  
  40.   */   

基于 UDP 套接字编程

下面我们使用 UDP 协议实现简单的功能,客户端从标准输入读取数据并把它发送给服务器,服务器接收到数据并把该数据回射给客户端,然后客户端收到从服务器回射的数据把它显示到标准输出。其功能实现如下图所示:

服务器程序

  1. /* UDP 服务器 */   
  2. #include <string.h>   
  3. #include <stdio.h>   
  4. #include <unistd.h>   
  5. #include <stdlib.h>   
  6. #include <sys/socket.h>   
  7. #include <netinet/in.h>   
  8.    
  9. #define SERV_PORT 9877 /* 通用端口号 */   
  10.    
  11. extern void err_sys(const char *, ...);   
  12. extern void dg_echo(int sockfd, struct sockaddr *addr, socklen_t addrlen);   
  13.    
  14. int main(int argc, char **argv)   
  15. {   
  16.     int sockfd;   
  17.     int err;   
  18.     struct sockaddr_in servaddr, cliaddr;   
  19.    
  20.     /* 初始化服务器地址信息 */   
  21.     bzero(&servaddr, sizeof(servaddr));   
  22.     servaddr.sin_family = AF_INET;   
  23.     servaddr.sin_port = htons(SERV_PORT);   
  24.     servaddr.sin_addr.s_addr = htonl(INADDR_ANY);   
  25.    
  26.     /* 创建套接字,并将服务器地址绑定到该套接字上 */   
  27.     if( (sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)   
  28.         err_sys("socket error");   
  29.     err =bind(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr));   
  30.     if(err < 0)   
  31.         err_sys("bind error");   
  32.     /* 服务器处理函数:读取套接字文本行,并把它回射给客户端 */   
  33.     dg_echo(sockfd, (struct sockaddr*) &cliaddr, sizeof(cliaddr));   
  34.    
  35. }   

处理函数

  1. #include    "unp.h"   
  2.    
  3. void   
  4. dg_echo(int sockfd, SA *pcliaddr, socklen_t clilen)   
  5. {   
  6.     int         n;   
  7.     socklen_t   len;   
  8.     char        mesg[MAXLINE];   
  9.    
  10.     for ( ; ; ) {   
  11.         len = clilen;   
  12.         n = Recvfrom(sockfd, mesg, MAXLINE, 0, pcliaddr, &len);   
  13.    
  14.         Sendto(sockfd, mesg, n, 0, pcliaddr, len);   
  15.     }   
  16. }   




相关内容