数据报(UDP)套接字客户端/服务器编程

实现一个基本的数据报套接字客户端/服务器通信程序,客户端和服务器按如下步骤交互:

(1)客户端向服务器发出日期时间请求字符串,如:%D %Y %A %T等。

(2)服务器从网络接收到日期时间请求字符串后,根据字符串格式生成对应的日期时间值返回给客户端。


  1. /*

     UPD服务器

     说明:数据报服务器,用于接收来自数据报客户端发来的请求

     注意:本程序通过命令行参数获取服务器的IP地址和端口

     用法:./server ip port

     

    */

    #include <stdio.h>

    #include <unistd.h>

    #include <stdlib.h>

    #include <errno.h>

    #include <string.h>

    #include <time.h>

    #include <sys/socket.h>

    #include <sys/types.h>

    #include <arpa/inet.h>

    #define BUFSIZE 1024

    static void bail(constchar *on_what)

    {

        fputs(strerror(errno),stderr);

        fputs(": ",stderr);

        fputs(on_what, stderr);

        fputc('\n',stderr);

        exit(1);

    }

    int main(int argc,char **argv)

    {

        long z;

        int sockfd;

        char *srvr_addr=NULL;

        struct sockaddr_in server_addr;//服务器

        struct sockaddr_in client_addr;//客户端

        int portnumber;

        

        char dgram[BUFSIZE];//应用接收缓冲

        char dtfmt[BUFSIZE];//日期时间结果

        time_t td;          //当前日期和时间

        struct tm tm;      //日期时间值

        

       //从命令行获得服务器

        srvr_addr=argv[1];

        if ((portnumber=atoi(argv[2]))<0)

        {

            fprintf(stderr,"port error");

            exit(1);

        }

        

        

        //创建UPD套接字

        sockfd=socket(AF_INET,SOCK_DGRAM,0);

        if (sockfd==-1)

            bail("socket()");

        

        

       //创建UDP服务器地址

        memset(&server_addr, 0, sizeof(server_addr));

        server_addr.sin_family=AF_INET;

        server_addr.sin_port=htons(portnumber);

        if (!inet_aton(srvr_addr, &server_addr.sin_addr))

            bail("bad address...");

        

       //绑定服务器UDP套接字到指定地址和端口

        z=bind(sockfd, (structsockaddr *)&server_addr,sizeof(server_addr));

        if (z==-1)

            bail("bind()");

        

        

       //主循环等待客户端请求

        printf("server is waiting for client request.\n");

        for (; ; )

        {

            socklen_t size=sizeof(client_addr);

            z=recvfrom(sockfd,dgram, sizeof(dgram), 0, (structsockaddr *)&client_addr,&size);

            if (z<0)

                bail("recvfrom()");

            

            //处理客户端请求

            dgram[z]=0;

            if (!strcasecmp(dgram,"QUIT"))

                continue;

           //获取当前日期和时间

            time(&td);

            tm=*localtime(&td);

           //根据输入请求字符串格式产生结果字符串

            strftime(dtfmt, sizeof(dtfmt), dgram, &tm);

            

            //向客户端发回结果

            z=sendto(sockfd, dtfmt, strlen(dtfmt), 0, (structsockaddr*)&client_addr,sizeof(client_addr));

            if (z<0)

                bail("sendto()");

        }

        close(sockfd);

        return 0;

    }



对于数据报服务器,因为没有连接的概念,所以服务器代码不像流试套接字服务器那样分为主进程和子进程,并且每个子进程独立为一个客户端提供服务,而是每收到一个数据报就立即进行处理,处理完后在接收下一个数据报进行同样的处理。


  1. /*

    UDP客户端

    用法:./client ip port

    */

    #include <stdio.h>

    #include <unistd.h>

    #include <stdlib.h>

    #include <errno.h>

    #include <string.h>

    #include <time.h>

    #include <sys/socket.h>

    #include <sys/types.h>

    #include <arpa/inet.h>

    #define BUFSIZE 1024

    static void bail(const char *on_what)

    {

        fputs(strerror(errno),stderr);

        fputs(": ",stderr);

        fputs(on_what, stderr);

        fputc('\n',stderr);

        exit(1);

    }

    int main(int argc,char **argv)

    {

        long z;

        int sockfd;

        char *srv_addr=NULL;

        struct sockaddr_in server_addr;//服务器地址

        struct sockaddr_in _addr;

        int portnumber;

        char dgram[BUFSIZE];

        

       //从命令行获取服务器地址字符串

        srv_addr=argv[1];

        

        if((portnumber=atoi(argv[2]))<0)

        {

            fprintf(stderr,"error");

            exit(1);

        }

        

       //创建服务器地址

        memset(&server_addr, 0, sizeof(server_addr));

        server_addr.sin_family=AF_INET;

        server_addr.sin_port=htons(portnumber);

        if (!inet_aton(srv_addr, &server_addr.sin_addr))

            bail("bad address");

        

        //创建UDP套接字

        sockfd=socket(AF_INET,SOCK_DGRAM,0);

        if (sockfd==-1)

            bail("socket()");

        

        

        for (; ; )

        {

            fputs("\nEnter format string:",stdout);

            if (!fgets(dgram,sizeof(dgram),stdin))

                break;

            

            

            z=strlen(dgram);

            if (z>0 && dgram[--z]=='\n')

                dgram[z]=0 //添加NULL结束标记

            

            

            if(z==0)

                continue;

            

            //发送请求字符串

            z=sendto(sockfd, dgram, strlen(dgram), 0, (struct sockaddr*)&server_addr,sizeof(server_addr));

            if (z<0)

                bail("sendto()");

            

            printf("send over...ans dgram=%s\n",dgram);

            

           //如果输入了退出命令‘quit’

            if (!strcasecmp(dgram,"QUIT"))

                break;

            

            //等待服务器应答

            socklen_t size=sizeof(_addr);

            z=recvfrom(sockfd, dgram, sizeof(dgram), 0, (struct sockaddr*)&_addr, &size);

            if (z<0)

                bail("recvfrom()");

            

            dgram[z]=0;

            printf("result from %s port %u:\n\t '%s'\n",inet_ntoa(_addr.sin_addr),ntohs(_addr.sin_port),dgram);

        }

        printf("\n exits from loop.\n");

        close(sockfd);

        return 0;

    }




  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值