zoukankan      html  css  js  c++  java
  • udp-->socket通信原理

    UDP数据通讯原理
         UDP数据通讯分服务端(软件)和客户端端:
         服务端(软件)(服务器)先运行,服务端,不需要事先知道客户端IP和port
         客户端(软件)(客户端机器)后运行,一定是客户端先给服务端发包,客户端一定先知道服务端的IP和port
         
     UDP通信实现
         1. 头文件
            #include <sys/types.h>     
            #include <sys/socket.h>
           
         2. 数据结构
            // Internet协议地址结构
            struct sockaddr{
                // 地址的通信领域
                unsigned short int sa_family;  
                
                // ip(4B) 和 port(2B) 
                char sa_data[14];
            };
            
            // 通用数据结构
            struct sockaddr_in {
                unsigned short int sin_family;
                unsigned short int sin_port;     // port
                struct in_addr sin_addr;         // ip地址
            
                // 填充0 (8B)
                unsigned char sin_zero[sizeof (struct sockaddr) -
                           (sizeof (unsigned short int)) -
                           sizeof (unsigned short int) -
                           sizeof (struct in_addr)];
            };      

         

    3. 函数

            服务端流程
            (1) 创建套接字(创建并且打开套接字)
                /*
                 * @param[in] domain 通信领域
                 * @li AF_UNIX, AF_LOCAL       unix域套接字通信(本机进程间)
                 * @li AF_INET                 IPv4协议通信
                 * @li AF_INET6                IPv6协议通信
                 * @param[in] type 套接字类型
                 * @li SOCK_STREAM 流式套接字
                 * @li SOCK_DGRAM 报文套接字
                 * @li SOCK_RAW  网络层的协议访问
                 * @param[in] protocol 协议标识
                 * @li 0 使用默认协议
                 *                      
                 * @return 文件描述符
                 * @li -1 创建失败(错误码见errno)
                 */
                int socket(int domain, int type, int protocol);
                
            (2) 绑定ip地址和port(到socket(一定一个进程创建))
                /*
                 * @param[in] sockfd socket
                 * @param[in] addr 绑定地址(ip地址和port)
                 * @param[in] addrlen addr的字节数                      
                 * @return @li 0 绑定成功
                 * @li -1 创建失败(错误码见errno)
                 */
                int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
                
            (3) 接收数据包
                /*
                 * @param[in] sockfd socket
                 * @param[out] buf  接收数据包的buf
                 * @param[in] len buf的字节数 
                 * @param[in] flags 0
                 * @param[out] src_addr 源地址(IP和Port)
                 * @NULL 不接收源地址,此时addrlen也必须为NULL   
                 * @param[in | out] addrlen(输入) src_addr缓冲区字节数
                 *                      addrlen(输出)  实际地址大小             
                 * @return @li >= 0 实际接收的字节数
                 * @li -1 创建失败(错误码见errno)
                 */
                ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);
                
            (4) 发送数据包
                /*
                 * @param[in] sockfd socket
                 * @param[out] buf  发送数据包的buf
                 * @param[in] len 发送数据的字节数 
                 * @param[in] flags 0
                 * @param[out] dest_addr 目标地址(IP和Port)
                 * @param[in] addrlen dest_addr字节数            
                 * @return @li >= 0 实际发送的字节数
                 * @li -1 发送失败(错误码见errno)
                 */
                ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);
                
            (5) 关闭socket
                int close(int sockfd);
            
            客户端流程
            (1) 创建套接字(创建并且打开套接字)
            (2) 发送数据包
            (3) 接收数据包
            (4) 关闭socket
            /*
     * 实现目标:
     * udp客户端
     *
     * 实现步骤:
     * 1. socket
     * 2. 获取用户输入
     * 3. sendto用户输入的内容
     * 4. recvfrom服务器发送过来的内容,并显示
     * 5. close
     */
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <errno.h>
    #include <strings.h>


    // net
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>


    // ./client 192.168.0.249 8888
    int main(int argc, const char *argv[])
    {
    int ret = 0;
    int sockfd;
    char packet[1024];
    struct sockaddr_in server_addr;
    struct sockaddr_in peer_addr;
    socklen_t addrlen = sizeof(peer_addr);

    if (argc < 3){
    fprintf(stderr, "Usage: %s <server ip> <server port> ", argv[0]);
    exit(EXIT_FAILURE);
    }


    // 1. socket
    sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (-1 == sockfd){
    perror("Fail to socket.");
    exit(EXIT_FAILURE);
    }


    // 填充地址结构
    bzero(&server_addr, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(atoi(argv[2]));
    server_addr.sin_addr.s_addr = inet_addr(argv[1]);

    while (1){
    // 2. 获取用户输入
    putchar('>');
    fgets(packet, sizeof(packet), stdin);
    packet[strlen(packet) - 1] = '';

    // 3. sendto用户输入的内容
    ret = sendto(sockfd, packet, strlen(packet), 0, (struct sockaddr *)&server_addr, sizeof(server_addr));
    if (-1 == ret){
    perror("Fail to sendto");
    break;
    }

    // 4. recvfrom服务器发送过来的内容,并显示
    ret = recvfrom(sockfd, packet, sizeof(packet), 0, (struct sockaddr *)&peer_addr, &addrlen);
    if (-1 == ret){
    perror("Fail to recvfrom.");
    break;
    }
    packet[ret] = '';

    printf("recv : %s ", packet);
    if (strcmp(packet, "bye") == 0) break;
    }

    // 5. close
    close(sockfd);

    return 0;
    }


    /*
     * 实现目标:
     * udp服务端
     *
     * 实现步骤:
     * 1. socket
     * 2. bind
     * 3. recvfrom客户发送的内容
     * 4. sendto相同的内容客户端
     * 5. close
     */
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <errno.h>


    // bzero
    #include <strings.h>


    // net
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>


    // ./server 192.168.0.249 8888
    int main(int argc, const char *argv[])
    {
    int ret = 0;
    int sockfd;
    struct sockaddr_in server_addr;
    struct sockaddr_in peer_addr;
    socklen_t addr_len = sizeof(peer_addr);
    char packet[1024];

    if (argc < 3){
    fprintf(stderr, "Usage: %s <ip> <port> ", argv[0]);
    exit(EXIT_FAILURE);
    }

    // 1. socket
    sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (-1 == sockfd){
    perror("Fail to socket.");
    exit(EXIT_FAILURE);
    }


    // 2. bind
    bzero(&server_addr, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(atoi(argv[2]));
    server_addr.sin_addr.s_addr = inet_addr(argv[1]);

    ret = bind(sockfd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr));
    if (-1 == ret){
    perror("Fail to bind.");
    exit(EXIT_FAILURE);
    }


    while (1) {
    // 3. recvfrom客户发送的内容
    ret = recvfrom(sockfd, packet, sizeof(packet), 0, (struct sockaddr *)&peer_addr, &addr_len);
    if (-1 == ret){
    perror("Fail to recvfrom.");
    break;
    }
    packet[ret] = '';

    printf("---------------------------------------- ");
    printf("ip   : %s ", inet_ntoa(peer_addr.sin_addr));
    printf("port : %d ", ntohs(peer_addr.sin_port));
    printf("recv : %s ", packet);
    printf("---------------------------------------- ");

    // 4. sendto相同的内容客户端
    ret = sendto(sockfd, packet, ret, 0, (struct sockaddr *)&peer_addr, sizeof(struct sockaddr));
    if (-1 == ret){
    perror("Fail to sendto.");
    break;
    }

    if (strcmp(packet, "bye") == 0) break;
    }

    // 5. close
    close(sockfd);

    return 0;
    }

  • 相关阅读:
    【Android测试】Android截图的深水区
    【Android测试】UI自动化代码优化之路
    网页爬虫小试牛刀
    【Android测试】【第十九节】Espresso——API详解
    【iOS测试】【随笔】帧率FPS评测
    【iOS测试】【随笔】崩溃日志获取
    【后台测试】Linux下小试jmeter
    【后台测试】手把手教你jmeter压测
    【行业交流】2016 TiD质量竞争力大会——移动互联网测试到质量的转变之路
    【Android测试】【第十八节】Espresso——环境搭建
  • 原文地址:https://www.cnblogs.com/dpf-learn/p/6223215.html
Copyright © 2011-2022 走看看