Linux下udp开发

Linux UDP开发:


UDP发送方:(客户端)
1、通过socket()函数实现创建套接字。
2、往sockaddr_in结构体中,填充对方的地址信息。
3、通过bind函数,绑定自己设备信息(上一步的sockaddr_in结构体)。
4、通过sendto()发送数据。
5、通过recvfrom()接收数据。

 

udp的建立:


    int m_sock = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
    //选择 AF_INET 的目的就是使用 IPv4 进行通信。
    //SOCK_DGRAM (数据报套接字)
    //1、分组在发送后,可能无序地到达接收端。
    //2、分组可能丢失。如果发生丢失,不会采取任何补救的措施,而且接受端也不必知道有分租丢失。
    //3、数据报分组有尺寸大小的限制,如果超出限制,在某些路由器和节点上就无法传送。
    //4、分组是在不建立连接的情况下被发送到远程进程的。
    //IPPROTO_UDP建立udp的宏。

    if(m_sock  < 0)
    {
        //qDebug("创建套接字失败了");
        return false;
    }

    struct sockaddr_in m_fromAddr;
    memset(&m_fromAddr,0,sizeof(m_fromAddr));
    m_fromAddr.sin_family=AF_INET;    //IP协议家族
   
m_fromAddr.sin_addr.s_addr=htonl(nIpAddr); //htonl()将主机数转换成无符号长整型的网络字节顺序
   
m_fromAddr.sin_port = htons(nPort);//htons()是将整型变量从主机字节顺序转变成网络字节顺序

    if(bind(m_sock,(struct sockaddr*)&m_fromAddr,sizeof(m_fromAddr))<0)
    {
        close(m_sock);
        return false;
    }

DE的udp发送:


    int nSize = sizeof(struct sockaddr_in);  
    int nLen = sendto(m_sock,sendBytes,writeNum,0,(struct sockaddr *)&sockAddr,nSize);
    //m_sock socket号。
    //sendBytes发送的数据,char*。
    //writeNum 数据个数,int。
    //flags通常为0
    //sockAddr 目的sockaddr_in信息
    //nSize sockAddr长度

    
    if (nLen == writeNum)
    {
       return true;
    }
    else
    {
       //qDebug("send Json Response failed!");
       return false;
    }

DE的udp接收:


法一:
void UdpServerInterface::monitorInterface()
{
    fd_set fds;//select()机制的结构集合
    int len = 0;
    struct timeval timeout={0,250000}; //timeval结构,第一个参数秒(s),第二个参数(us),即设置250ms
    char buffer[2048]={0}; //2M字节的接收缓冲区
    socklen_t scokAddrLen = sizeof(struct sockaddr_in);
    struct sockaddr_in fromAddr;

    FD_ZERO(&fds); //每次循环都要清空集合,否则不能检测描述符变化
    FD_SET(m_sock,&fds); //添加描述符

    switch(select(m_sock+1,&fds,NULL,NULL,&timeout))   
    //第一个参数,是指集合中所有文件描述符的范围,即所有文件描述符的最大值加1。
    //这个集合中是我们要监视的文件描述符,即我们关心数据是否可读,如果这个集合中有一个文件可读,select就会返回一个大于0的值,
    //如果没有可读的文件,则根据timeout参数再判断是否超时,若超出timeout的时间,select返回0,若发生错误返回负值。

    {
    case -1:
         outputMessage(QtWarningMsg,"socket select error!");
         break; //select错误,退出程序
    case  0:
         //outputMessage(QtWarningMsg,"socket recieve timeout!");
         m_RecvArray.clear();
         break; //再次轮询
    default:
         if (FD_ISSET(m_sock,&fds)) //测试sock是否可读,即是否网络上有数据
         {
              len = recvfrom(m_sock,buffer,2048,MSG_DONTWAIT, (struct sockaddr *)&fromAddr,&scokAddrLen);//接受网络数据
              if (len > 0)
              {
                   m_RecvArray.clear();
                   m_RecvArray.append(buffer,len);
                   parserRecvMessage(m_RecvArray);
              }
              else
              {
                   outputMessage(QtDebugMsg, "socket recieve error!");
              }
         }
    }
}

法二:
{
    int sockfd;
    char buf[64];
    if((sockfd = socket(AF_INET,SOCK_DGRAM,0)) == -1)
    {
        perror("socket");
        exit(1);
    }

    struct sockaddr_in myaddr,peeraddr;

    memset(&myaddr,0,sizeof(myaddr));
    myaddr.sin_family = AF_INET;
    myaddr.sin_port = htons(50000);
    myaddr.sin_addr.s_addr = inet_addr("192.168.1.103");

    if(bind(sockfd,(struct sockaddr *)&myaddr,sizeof(myaddr)) == -1)
    {
        perror("bind");
        exit(1);
    }

    int flag;
    flag = fcntl(sockfd,F_GETFL);
    flag |= O_NONBLOCK;
    fcntl(sockfd,F_SETFL,flag);

    int peer_len = sizeof(peeraddr);
    int len;
    while(1)
    {
        memset(buf,0,sizeof(buf));
        len = recvfrom(sockfd,buf,sizeof(buf),0,(struct sockaddr *)&peeraddr,&peer_len);

        if(len == -1)
        {
            if(errno == EAGAIN)
            {
                sleep(1);
                printf("还没准备好呢\n");
                continue;
            }
            else 
            {
                perror("recvfrom");
                exit(1);
            }
        }

        printf("ip:%s,port:%d,buf:%s\n",inet_ntoa(peeraddr.sin_addr),ntohs(peeraddr.sin_port),buf);
    }
    close(sockfd);
    return 0;
}

你可能感兴趣的:(linux)