如何编写UDP服务器

 

客户端逻辑(不需要绑定端口号)

1.用户输入数据,从标准输入输入一个字符串

2.把这个字符串发送给服务器

3.从服务器读取并返回结果

4.把响应写到标准输出上

 

服务器逻辑(绑定端口号)

1.启动(初始化)

2.进入死循环(事件循环)

    a)从socket中读取请求(Request)

    b)根据Request的内容计算生成Response

    c)把Response响应写回socket

 

 

服务器 server.c

int main(int argc, char* argv[])
{
    if(argc != 3)
    {
        printf("Usage: [ipaddr] [port]\n");
        exit(1);
    }

    //创建socket            IPV4      UDP                不关心置0
    int sockfd = socket(AF_INET,SOCK_DGRAM,0);    

  //创建addr_in结构体,并初始化
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(atoi(argv[2]));                    //服务器端口号  atoi函数把字符串转换成整型      htons函数把端口号从主机字节序转成网络字节序
    addr.sin_addr.s_addr = inet_addr(argv[1]);          //ip地址转换   将一个点分十进制的数转化为二进制的网络字节序的IPV4地址

    //将服务器ip和端口号进行绑定
    if(bind(sockfd,(struct sockaddr*)&addr,sizeof(addr)) < 0)
    {
        perror("bind");
        exit(2);
    }

    //申请缓存区收发数据
    char buf[1024];
    while(1)
    {
        struct sockaddr_in client;    //捕获数据发送源的地址,以便sendto发送
        socklen_t clientLen = sizeof(client);

        //recvfrom()函数:从套接字端口上接收数据,并解析出数据携带的客户端端口地址信息 ,然后放到定义好的client结构体中,
        //参数:sockfd 申请的套接字;buf 收到数据存放的缓存区 ;sizeof(buf)-1 最多存放的大小; 
                     0 操作方式,不关心置0; &clien 指向携带有数据源地址信息的缓冲区(指针); &clientLen 解析过程中clientLen大小可能会发生变化,所以传指针
        ssize_t s = recvfrom(sockfd, buf ,sizeof(buf)-1,0,(struct sockaddr*)&client,&clientLen);
        if(s > 0)
        {
            buf[s] ='/0';
            //把转化的数据再反转输出
            printf("IP: %s , Port : %d  : %s\n",inet_ntoa(client.sin_addr),ntohs(client.sin_port),buf);
            //sendto()函数:  向指定目的地发送数据
            //参数:同上,这里的client为装有发送数据的目的地址缓存区(指针); clientLen目的地址缓存区长度(整型)
            sendto(sockfd,buf,strlen(buf),0,(struct sockaddr*)&client,clientLen);
        }
    }
    close(sockfd);
    return 0;
}

客户端client.c

int main(int argc,char* argv[])
{
    if(argc != 3)
    {
       printf("Usage: [ipaddr] [port]\n");
       exit(1);
    }
   
    //创建socket            IPV4      UDP                指定协议 不关心置0
    int sockfd = socket(AF_INET,SOCK_DGRAM,0);
   

     //创建addr_in结构体并初始化
     struct sockaddr_in client;
     client.sin_family = AF_INET;
     client.sin_port = htons(atoi(argv[2]));        
     client.sin_addr.s_addr = inet_addr(argv[1]);

    //建立缓存区,准备向服务器发送数据
    printf("Please Enter : \n");
    char buf[1024];
    while(1)
    {
        printf("#client : ");
        fflush(stdout);
        //从标准输入读数据进buf
        ssize_t s = read(0,buf,sizeof(buf)-1);
        if(s < 0)
        {
            perror("read");
            exit(3);
        }
        buf[s-1] = '\0';
    
        //sendto()函数:  向指定目的地发送数据
        //参数:sockfd 申请的套接字;buf 收到数据存放的缓存区 ;strlen(buf) 已经写在缓存区的长度; 
                     0 操作方式,不关心置0;client为装有发送数据的目的地址缓存区(指针); clientLen目的地址缓存区长度(整型)
        s = sendto(sockfd,buf,strlen(buf),0,(struct sockaddr*)&client,sizeof(client));
        if(s < 0)
        {
            perror("sendto");
            exit(4);
        }
        
        //sendto()函数:创建一个接收对端ip&端口信息的addr_in结构体server
        struct sockaddr_in server;
        socklen_t len = sizeof(server);

        //recvfrom()函数:从套接字端口上接收数据,并解析出客户端的端口地址信息 ,然后放到定义好的client结构体中,
        //参数:sockfd 申请的套接字;buf 收到数据存放的缓存区 ;sizeof(buf)-1 最多存放的大小; 
                     0 操作方式,不关心置0; &clien 指向携带有数据源地址信息的缓冲区(指针); &clientLen 解析过程中clientLen大小可能会发生变化,所以传指针
        s = recvfrom(sockfd,buf,sizeof(buf)-1,0,(struct sockaddr*)&server,&len);
        if(s < 0)
        {
            perror("recvfrom");
            exit(5);
        }
        //
        buf[s] = '/0';
        //把转化的数据再反转输出
        printf("IP : %s , Port : %d  : %s\n",inet_ntoa(server.sin_addr),ntohs(server.sin_port),buf);
    }
    //关闭
    close(sockfd);
    return 0;
}

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值