socket网络编程实践要点

1、创建udp的socket句柄

// 当host_port为0时,则表示让操作系统自动分配
bool createUdpSocket(string host_ip,unsigned short host_port, int& sock_fd)
{
    sock_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if(sock_fd <= 0)
    {
        return false;
    }

    struct sockaddr_in client_addr= {0};
    inet_pton(AF_INET,host_ip.c_str(), &(client_addr.sin_addr));
    client_addr.sin_port =htons(host_port);
    client_addr.sin_family = AF_INET;

    if(::bind(sock_fd, (struct sockaddr*)&client_addr, sizeof(struct sockaddr_in))== -1)
    {
        close(sock_fd);
        sock_fd = -1;
        return false;
    }
    
    //获取操作系统分配的端口
    struct sockaddr_storage sock_addr;
    socklen_t addr_size = sizeof(struct sockaddr_storage);

    getsockname(sock_fd, (struct sockaddr*)&sock_addr, &addr_size);

    sockaddr_in sin ;
    memcpy(&sin,&sock_addr,addr_size);

    host_ip = inet_ntoa(sin.sin_addr);
    host_port = ntohs(sin.sin_port);

    // 设置socket为非阻塞
#ifdef WIN32
    unsigned long arg = 1;
    ioctlsocket(sock_fd, FIONBIO, &arg) ;
    ioctlsocket(sock_fd, FIONBIO, &arg) ;
#endif
#ifdef LINUX
    int arg = fcntl(sock_fd, F_GETFL, 0);
    fcntl(sock_fd, F_SETFL, arg | O_NONBLOCK);
#endif
    
    return true;

}

2、发送udp数据包

int sendUdpData(int socket_fd,char* buff,int buff_len,struct sockaddr* dest_addr)
{
    int count = 0 ;
    ssize_t send_len = 0;

    do
    {
        if(count > 0)
        {
            sleep_ms(5*count);
        }

        //考虑网络不好时,需要尝试发送多次
        send_len = sendto(socket_fd, buff, ssize_t(buff_len), 0, dest_addr, sizeof(struct sockaddr));
        count++;
    }while(send_len <0 && errno == EAGAIN && count<=5);
    return int(send_len);
}

3、发送udp广播包

int sendBroadUdpData(int sock_fd,char* buff,int buff_len)
{
    // 将端口设置为允许广播包
    int broadcast = 1;
#ifdef WIN32
    setsockopt(sock_fd, SOL_SOCKET, SO_BROADCAST, (const char *)&broadcast, sizeof(broadcast));
#else
    setsockopt(sock_fd, SOL_SOCKET, SO_BROADCAST, &broadcast, sizeof(broadcast));
#endif

    struct sockaddr_in svr_addr;
    memset(&svr_addr, 0, sizeof(svr_addr));
    svr_addr.sin_family = AF_INET;
    svr_addr.sin_port = htons(BROAD_CAST_PORT);

    int server_ip;
    inet_pton(AF_INET, "255.255.255.255", (void *)&server_ip);
    svr_addr.sin_addr.s_addr = server_ip;
    
    sendUdpData(sock_fd, buff, buff_len, (struct sockaddr*)&svr_addr);

}

4、接收udp的数据包
利用poll或epoll模型,当某个socket_fd有数据可读时,即可返回进行相应的处理

{
    struct sockaddr_in client_addr;
    int len = sizeof(struct sockaddr);
    char recv_buff[1024];
    int recv_len = 0;
    
    
    recv_len = recvfrom(socket_fd, recv_buff, sizeof(recv_buff), 0, (struct sockaddr *)&client_addr, (socklen_t *)&len)
    if (recv_len > 0)
    {
        processMsg(recv_buff, recv_len, client_addr);
    }
}

5、poll模型的构建,同时监控多个fd

{
    int maxCount = 20;
#ifdef LINUX
    struct pollfd wait_fd[maxCount];
#endif

#ifdef WIN32
    WSAPOLLFD wait_fd[maxCount];
#endif

    int real_count = 0;

    listen_fds.clear();
    GetListenFd(listen_fds);
    for (int index = 0; index < (int)listen_fds.size(); index++)
    {
        wait_fd[real_count].fd = listen_fds[index];
        wait_fd[real_count].events = POLLIN | POLLOUT;
        real_count++;
    }

#ifdef LINUX
    int res = ::poll(wait_fd, real_count, 100); //100毫秒超时
#endif

#ifdef WIN32
    int res = WSAPoll(wait_fd, real_count, 100);
#endif

    if (res == -1)
    {
        usleep(10000);
    }
    else if (res)
    {
        int current_fd;
        for (int index = 0; index < real_count; index++)
        {
            current_fd = wait_fd[index].fd;
            if ((wait_fd[index].revents & POLLIN) > 0)
            {
                recvfrom(current_fd, recv_buff, sizeof(recv_buff), 0, (struct sockaddr *)&client_addr, (socklen_t *)&alen);

                bool is_listen_fd = false; //是否是监听句柄
                for (int pos = 0; pos < (int)listen_fds.size(); pos++)
                {
                    if (current_fd == listen_fds[pos])
                    {
                        is_listen_fd = true;
                        break;
                    }
                }
            }

            if ((wait_fd[index].revents & POLLERR) > 0)
                
                usleep(10000);
            }
        }
    }
    else
    {
        printf("time out.\n");
    }
    
}

猜你喜欢

转载自www.cnblogs.com/share-ideas/p/10886689.html