UDP客户/服务器程序示例

简介

UDP是无连接不可靠的数据报协议,不需要建立连接。

/*
fd,buf,n分别是描述符,缓冲区,读写字节数。
flag:暂时为0
__addr:接收者数据报协议地址结构,告诉往哪里发,类似connect后面参数。
__addr_len:结构地址长度
*/
ssize_t sendto (int __fd, const void *__buf, size_t __n,
               int __flags, __CONST_SOCKADDR_ARG __addr,
               socklen_t __addr_len);

/*
fd,buf,n分别是描述符,缓冲区,读写字节数。
flag:暂时为0
__addr:返回发送者协议地址结构,告诉哪个连接了我,类似accept后面参数。
__addr_len:值-结果参数。
addr和len都可以为NULL,表示不关心发送者协议地址。
*/
ssize_t recvfrom (int __fd, void *__restrict __buf, size_t __n,
             int __flags, __SOCKADDR_ARG __addr,
             socklen_t *__restrict __addr_len);

UDP回射程序

client:

void client_echo(FILE *fp , int sockfd , SA *servaddr , socklen_t servlen)
{
    int n;
    char sendline[MAXLINE] , recvline[MAXLINE + 1];
    while(fgets(sendline , MAXLINE , fp) != NULL){
        Sendto(sockfd , sendline , strlen(sendline) , 0 , servaddr , servlen);
        n = Recvfrom(sockfd , recvline , MAXLINE , 0 , NULL , NULL);//接收服务器数据,并不关心服务器地址
        recvline[n] = 0;
        fputs(recvline , stdout);
    }
}
int main(int argc, char **argv)//客户程序
{
    int                 sockfd;
    struct sockaddr_in  servaddr;

    if (argc != 2)
        err_quit("usage: a.out ");
    sockfd = Socket(AF_INET, SOCK_DGRAM, 0);//创建UDP套接字
    bzero(&servaddr, sizeof(servaddr));//地址结构清0
    servaddr.sin_family = AF_INET;
    servaddr.sin_port   = htons(4099);//服务器端口
    inet_pton(AF_INET, argv[1], &servaddr.sin_addr);//服务器IP地址
    client_echo(stdin , sockfd , (SA *)&servaddr , sizeof(servaddr));//处理
    exit(0);
}

server:
UDP层含有一个FIFO数据报缓冲队列,进程revfrom时,缓冲区以将数据报FIFO方式返回给进程,这样,进程就可以以此从缓冲区读好缓冲的数据。所以UDP服务器是迭代服务器,内核为你做了好多事情,排好队等着你调用系统函数读取为你准备好的数据。

void server_echo(int sockfd , SA *cliaddr , socklen_t clilen)
{
    int n;
    socklen_t len;
    char mesg[MAXLINE];//缓冲区
    while(1){
        len = clilen;//记录长度
        n = Recvfrom(sockfd , mesg , MAXLINE , 0 , cliaddr , &len);//接受数据,返回填写了cliaddr结构
        Sendto(sockfd , mesg , n , 0 , cliaddr , len);//发送出去
    }
}
int main(int argc, char **argv)//UDP服务器程序
{
    int                 sockfd;//服务器fd
    struct sockaddr_in  servaddr , cliaddr;

    /*×××××××××××××××××××服务器端套路开始××××××××××××××××××××*/
    sockfd = Socket(AF_INET, SOCK_DGRAM, 0);//创建UDP套接字创建

    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family      = AF_INET;//服务器IP地址为网卡IP地址
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port        = htons(4099);
    Bind(sockfd, (SA *) &servaddr, sizeof(servaddr));//绑定本机IP地址和端口,设置结构体成员而已
    /********************UDP服务器端套路结束*********************/
    server_echo(sockfd , (SA *)&cliaddr , sizeof(cliaddr));//强制转换是因为历史原因。
    exit(0);
}

问题

1、数据报丢失:UDP是不可靠的,数据报丢失之后,客户或者服务器都将阻塞在recvfrom函数,可以暂时给recvfrom设置超时处理。但是假如是银行转账,那么这种简单的处理显然不可靠。
2、验证接收到的响应:

你可能感兴趣的:(UNPV1)