准备做一个服务器,用5060端口接收客户端的SIP指令,
28880端口接收客户端的语音包,转发给网关;
接受语音包有异常
数据包长度都是1,但是通过SNIFFER抓包显示长度是172;请大家分析下面代码,谢谢
//////////////////////////////////////////////////////////////////////////////////////
        //接收SIP指令的主要代码
        SOCKET mSckSender = socket(AF_INET, SOCK_DGRAM, 0);
        SOCKADDR_IN addrClent;
memset((char *) &addrClent, 0, sizeof(addrClent));  
addrClent.sin_family      = AF_INET;
addrClent.sin_addr.s_addr = htonl(INADDR_ANY);
addrClent.sin_port        = htons(5060); //接收客户端和网关SIP指令的端口号
int ret = bind(mSckSender, (struct sockaddr*) &addrClent, sizeof(addrClent)); char RecevMsg[1024];
         SOCKADDR_IN addrCli;
int addr_cli_len = sizeof(addrCli);
recvfrom(mSckSender, (char *)RecevMsg, 1024, 0,(LPSOCKADDR) &addrCli, (int *) &addr_cli_len); 
CString rcvMsg = RecevMsg; //////////////////////////////////////////////////////////////////////////////////////
//接收PC客户端语音包的主要代码
BOOL CSipServerManager::InitSocket(SOCKET &sck,int iPort)
{
sck = socket(AF_INET, SOCK_DGRAM, 0);
SOCKADDR_IN addr;
memset((char *) &addr, 0, sizeof(addr));  
addr.sin_family      = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port        = htons(iPort); //28880端口用来接收客户端的语音包
int ret = bind(sck, (struct sockaddr*) &addr, sizeof(addr)); 
return TRUE;
}BOOL CSipServerManager::SendTo(SOCKET sck,const char * inBuffer,DWORD strIP,int iPort)
{
if (sck != INVALID_SOCKET)
{
SOCKADDR_IN  addr;
memset((char *) &addr, 0, sizeof(addr));  
addr.sin_family      = AF_INET;
addr.sin_addr.s_addr = htonl(strIP); //目标IP
addr.sin_port        = htons(iPort); //目标端口

//向客户端或网关发消息
int val = sendto(sck, inBuffer, strlen(inBuffer), 0, (sockaddr *) &addr, sizeof(addr));
return (val != SOCKET_ERROR);
}
return FALSE;
}void CSipServerManager::Process_Thread(void)
{
char bytes[1024];
        SOCKET udpSckClientToProxy; while (TRUE)
{
                InitSocket(udpSckClientToProxy,28880); //28880端口接收客户端的语音包 //接受客户端数据包 
recvfrom(udpSckClientToProxy, bytes, 1024, 0,(LPSOCKADDR) &udpAddrHole, (int *) &ilength);
CString strIP=inet_ntoa(udpAddrHole.sin_addr); //PC客户端的IP if (strcmp(strIP,"211.1.1.1") != 0) //收到客户端语音包,转发给网关
{
DWORD dwIP=ntohl(inet_addr("211.1.1.1")); //网关IP
BOOL ret = FALSE;
        tmp.Empty();
                        tmp= bytes;                        //接收到语音包长度一直为1,通过SNIFFER抓包长度基本都是172
if (tmp.GetLength() >10) 
{
//把语音包转发给网关
ret = SendTo(udpSckProxyToGaty,bytes,dwIP,iProxyToGatyPort); 
}    
}
}
}

解决方案 »

  1.   

    //接受客户端语音包
    int msgLen =
    recvfrom(udpSckClientToProxy, bytes, 1024, 0,(LPSOCKADDR) &udpAddrHole, (int *) &ilength);
    CString strMsg = bytes;//把语音包转发给网关 
    ret = SendTo(udpSckProxyToGaty,bytes,dwIP,iProxyToGatyPort); msgLen返回值是172,但是strMsg长度为1,
    使用SNIFFER抓包显示,发送给网关的数据包长度一直为1
      

  2.   

    udp包本身是不可靠的,你得自己定义协议来确保通信的可靠性,比如在收到数据后应该相互进行一次确认,如果做一次检验那是更好了。另外你的recvfrome之间应该用select判断一下,然后需要多次接收,不一定一次就能接收完。
      

  3.   

    是不是recvfrom函数用的有问题,flg标记有影响么?
      

  4.   


    //接受客户端数据包 
    recvfrom(udpSckClientToProxy, bytes, 1024, 0,(LPSOCKADDR) &udpAddrHole, (int *) &ilength); 
    int nReceivedLen = recvfrom(....);看一下长接收到的长度.
      

  5.   

    //HANDLE g_hThread;
    DWORD g_threadID;#ifdef FD_SETSIZE
    #undef FD_SETSIZE
    #define FD_SETSIZE 1024
    #endifDWORD WINAPI PhoneServices(LPVOID param)
    {
    hostent *hostAddr;
    char hostName[256]={0};
    gethostname(hostName,256);
    hostAddr=gethostbyname(hostName);
    char *IP;
    IP=inet_ntoa(*((struct in_addr*)hostAddr->h_addr_list[0]));
    CManagerClient manager; SOCKET sock_Server=socket(AF_INET,SOCK_DGRAM,0);
    sockaddr_in ser_Addr={0};
    ser_Addr.sin_addr.s_addr=inet_addr(IP);
    ser_Addr.sin_family = AF_INET;
    ser_Addr.sin_port = htons(g_ser_info.GetSerPort()); //配置文件中获得
    int addr_Len = sizeof(sockaddr_in);
    bind(sock_Server,(sockaddr*)&ser_Addr,addr_Len);
    if(WSAGetLastError()!=0)
    {
    AfxMessageBox("服务器开启失败:已开启或端口占用!");
    }
    while(1)
    {
    fd_set serv_Set;
    FD_ZERO(&serv_Set);
    FD_SET(sock_Server,&serv_Set);
    timeval time_Out={g_ser_info.GetTimeOut(),0}; //配置文件中获得
    int res=select(0,&serv_Set,NULL,NULL,&time_Out);
    if(res==0 || res==-1)
    {
    TRACE("timeout or error:%d\n",res);
    }
    else if(FD_ISSET(sock_Server,&serv_Set))
    {
    char buf[1024]={0};
    sockaddr_in client_Addr={0};
    recvfrom(sock_Server,buf,1024,0,(sockaddr*)&client_Addr,&addr_Len);
    manager.MessageSwitch(sock_Server,buf,client_Addr);
    } Sleep(100);
    MSG msg_Stop;
    if(PeekMessage(&msg_Stop,NULL,0,0,0))
    {
    GetMessage(&msg_Stop,NULL,0,0);
    if(msg_Stop.message==WM_THREAD_STOP)
    {
    break;
    }
    }
    }
    closesocket(sock_Server);
    return 0;
    }
      

  6.   

           设置接收数据的超时时间,还是收不到数据;
                   客户端和网关协商,
                   支持的音频格式,pt=0(g711.u),pt=101                            网关异常日志:
                   10d:17h:51m:3s (lgr_coders_list)(5696      ) 
                   ?? [WARNING] ACCodersList::IsMatch found match with different intervals g711Ulaw64k10 (10 != 20)                               #ifdef FD_SETSIZE
                   #undef FD_SETSIZE
                   #define FD_SETSIZE 1024
                   #endif                fd_set serv_Set;
    FD_ZERO(&serv_Set);
    FD_SET(udpSckClientToProxy,&serv_Set);
    timeval time_Out={20,0}; //设置接收数据的超时时间200ms
    int res=select(0,&serv_Set,NULL,NULL,&time_Out); if(res==0 || res==-1)
    {
    TRACE("timeout or error:%d\n",res);
    }
    else if(FD_ISSET(udpSckClientToProxy,&serv_Set))
    {
    char buf[1024]={0};
    bRsLength=recvfrom(udpSckClientToProxy,buf,1024,0,(sockaddr*)&udpAddrHole,&ilength);
    CString strIP=inet_ntoa(udpAddrHole.sin_addr); //客户端或网关的IP                        //把语音包转发给网关
                    }
      

  7.   

    char buf[1024]={0}; 
    bRsLength=recvfrom(udpSckClientToProxy,buf,1024,0,(sockaddr*)&udpAddrHole,&ilength); tmp.Empty();
    tmp= buf;
    int k = tmp.GetLength(); bRsLength的值为172,但是k的值为1,很奇怪
      

  8.   

    这种问题,你可以单步调试一下,看recvfrom()后的字符串内容是什么.这个可以赋值后再看字符串值好的多.
     把
       tmp.Empty();
       tmp = buf;
     替换为: 
       tmp.Format(_T("%s"),buf);
      

  9.   


    不是字符串的对象赋值到了CSTRING,只会截取到0X00前的部分。
      

  10.   

    char buf[1024];
    CString str;感觉str=buf;没有问题,之前这样传过值...
      

  11.   


    tmp.Empty();
    tmp = buf;
    替换为: 
    tmp.Format(_T("%s"),buf);还是有问题,buf长度为172(recvfrom返回值),
    tmp长度还是1
      

  12.   

    recvfrom(udpSckClientToProxy,buf,1024,0,(sockaddr*)&udpAddrHole,&ilength);缓冲区大小1024,已经flg标记0,Sleep()时间,
    还有下面的超时时间,是否有影响呢?
     #ifdef FD_SETSIZE 
                  #undef FD_SETSIZE 
                  #define FD_SETSIZE 1024 
                  #endif                 fd_set serv_Set; 
    FD_ZERO(&serv_Set); 
    FD_SET(udpSckClientToProxy,&serv_Set); 
    timeval time_Out={20,0}; //设置接收数据的超时时间200ms 
    int res=select(0,&serv_Set,NULL,NULL,&time_Out); 
      

  13.   


    Format不是一样的?你还是没明白。
    你这样,在你的recvfrom后加一句,打印出来贴上了for (int i = 0; i < bRsLength; i++)
    {
      if (i % 16)
        TRACE("\n");
      TRACE("%02X ", buf[i]);
    }
      

  14.   

    for (int i = 0; i < bRsLength; i++)
    {
      if (i % 16)
        TRACE("\n");
      TRACE("%02X ", buf[i]);
    }下面是输出结果...
    FFFFFF80 
    FFFFFF80 
    FFFFFFB6 
    FFFFFFD6 
    FFFFFFBC 
    03 
    51 
    06 
    1A 
    FFFFFFC5 
    7E 
    1D 
    7A 
    7D 
    7A 
    78 77 
    74 
    73 
    6F 
    71 
    71 
    73 
    74 
    73 
    72 
    72 
    70 
    6E 
    6D 
    6E 
    72 76 
    79 
    7F 
    FFFFFFFC 
    FFFFFFF6 
    FFFFFFF5 
    FFFFFFF1 
    FFFFFFEE 
    FFFFFFED 
    FFFFFFEE 
    FFFFFFEE 
    FFFFFFEE 
    FFFFFFED 
    FFFFFFED 
    FFFFFFEE 
    FFFFFFEE FFFFFFEF 
    FFFFFFEF 
    FFFFFFEF 
    FFFFFFF0 
    FFFFFFF1 
    FFFFFFF1 
    FFFFFFF1 
    FFFFFFF5 
    FFFFFFF8 
    FFFFFFFB 
    FFFFFFFC 
    FFFFFFFD 
    FFFFFFFF 
    7F 
    FFFFFFFF 
    FFFFFFFF 7E 
    7D 
    7E 
    FFFFFFFF 
    FFFFFFFE 
    7E 
    7E 
    7B 
    7A 
    7A 
    7B 
    7C 
    7D 
    7E 
    7F 
    FFFFFFFE FFFFFFFC 
    FFFFFFF9 
    FFFFFFF5 
    FFFFFFEF 
    FFFFFFEC 
    FFFFFFEB 
    FFFFFFE8 
    FFFFFFE7 
    FFFFFFE6 
    FFFFFFE5 
    FFFFFFE4 
    FFFFFFE3 
    FFFFFFE3 
    FFFFFFE4 
    FFFFFFE4 
    FFFFFFE4 FFFFFFE6 
    FFFFFFE7 
    FFFFFFEA 
    FFFFFFEA 
    FFFFFFEE 
    FFFFFFEF 
    FFFFFFF3 
    FFFFFFFA 
    FFFFFFFB 
    FFFFFFF9 
    FFFFFFF9 
    FFFFFFFA 
    FFFFFFFA 
    FFFFFFFC 
    FFFFFFFB 
    FFFFFFFC FFFFFFFB 
    FFFFFFFB 
    FFFFFFF8 
    FFFFFFF4 
    FFFFFFEF 
    FFFFFFED 
    FFFFFFE8 
    FFFFFFE5 
    FFFFFFE1 
    FFFFFFDF 
    FFFFFFDE 
    FFFFFFDE 
    FFFFFFDE 
    FFFFFFDF 
    FFFFFFDF 
    FFFFFFE1 FFFFFFE1 
    FFFFFFE4 
    FFFFFFE7 
    FFFFFFE8 
    FFFFFFE9 
    FFFFFFEC 
    FFFFFFED 
    FFFFFFF0 
    FFFFFFF7 
    FFFFFFFA 
    FFFFFFFD 
    7F 
    FFFFFFFF 
    FFFFFFFF 
    FFFFFFFD 
    FFFFFFFC FFFFFFFD 
    FFFFFFFD 
    FFFFFFFD 
    FFFFFFFF 
    7E 
    7D 
    7C 
    7C 
    79 
    7A 
    79 
    78 
    77 
    78 
    7B 
    7D 7D 
    FFFFFFFF 
    FFFFFFFF 
    FFFFFFFD 
    FFFFFFFD 
    FFFFFFF7 
    FFFFFFF6 
    FFFFFFF4 
    FFFFFFF0 
    FFFFFFEE 
    FFFFFFED 
    FFFFFFED 
      

  15.   

    调试时
    buf中显示的值如下:
    + buf 0x0123ed18 "€€吨?Q舿z}zxwtsoqqstsrrpnmnrvy躐铐铑铐眍铒镲瘃耨貘?~}~~{zz{|}~镬腓珂邃沣滗滏珀觐矬麸龛遽咿揶哌後溏栝祉瘅?~}||yzyxwx{}}黯麴铐
      

  16.   


    你的数据一直是这样的吗?我能够GetLength()到不为1
      

  17.   

    就第一次buf中有172个字符,
    后面都是只收到一个字符:
    + buf 0x012bed14 "€"
    - tmp {"€"}
    FFFFFF80 
    FFFFFF80 
    7C 
    1A 
    2D 
    FFFFFFA1 
    FFFFFFFB 
    FFFFFFAB 
    FFFFFFA6 
    FFFFFFB2 
    FFFFFF8D 
    28 
    6D 
    6F 
    76 
    79 7B 
    7E 
    7F 
    7B 
    7C 
    7C 
    FFFFFFFF 
    7E 
    7C 
    78 
    77 
    72 
    6F 
    6E 
    6E 
    6C 6C 
    6D 
    6E 
    6C 
    6A 
    6A 
    6A 
    69 
    69 
    68 
    68 
    66 
    68 
    6A 
    6A 
    6B 6C 
    6D 
    6B 
    6A 
    6B 
    6C 
    6D 
    6D 
    6F 
    6F 
    6F 
    6E 
    6F 
    6E 
    6D 
    6E 71 
    74 
    73 
    71 
    72 
    74 
    76 
    73 
    6E 
    6C 
    69 
    68 
    67 
    66 
    65 
    66 65 
    64 
    64 
    63 
    64 
    66 
    67 
    67 
    67 
    69 
    69 
    6B 
    6D 
    6E 
    6E 
    6F 72 
    75 
    75 
    77 
    7C 
    FFFFFFFC 
    FFFFFFFC 
    FFFFFFFC 
    FFFFFFFE 
    7D 
    7A 
    77 
    75 
    73 
    6E 
    6B 6B 
    6A 
    6A 
    68 
    66 
    67 
    68 
    69 
    68 
    68 
    6A 
    6C 
    6D 
    6F 
    70 
    73 77 
    7A 
    7B 
    76 
    74 
    75 
    75 
    76 
    73 
    75 
    79 
    78 
    73 
    6E 
    6D 
    6A 68 
    67 
    67 
    68 
    67 
    67 
    68 
    6B 
    6B 
    6A 
    68 
    65 
    63 
    61 
    61 
    61 60 
    61 
    5F 
    61 
    62 
    63 
    63 
    63 
    63 
    64 
    66 
    67 
      

  18.   


    23楼的是你GetLength()为1的buf数据?
      

  19.   

    23楼是数据包长度为1时打印出来的值;程序中启动两个线程序,用两个SOCKET,两个端口来监听数据包,
    一个线程处理SIP指令(thrd111,sock111,SIP指令的端口5060),
    一个线程处理音频数据包(thrd222,sock222,接收语音包的端口28880);是不是这两个线程序相互干扰造成的?
      

  20.   

    你第二次以后接收到的bytes长度是多少?在接收前将bytes数组清空(memset(bytes,0,1024).
    把temp.Empty()这行去掉.我之前也是用了这行,一直没收到过数据.
    给你一段我的UDP接收程序参考一下:BOOL CUDPDlg::InitSock()
    {
    BOOL result = true;
    CString strTemp = "";
    SOCKET m_hSock = socket(AF_INET,SOCK_DGRAM,IPPROTO_IP);
    if(m_hSock == INVALID_SOCKET)
    {
    strTemp.Format("Initialize socket library error!\r\nError code:%d",WSAGetLastError());
    AfxMessageBox(strTemp);
    return false;
    } UpdateData();
    SOCKADDR_IN addrSock;
    addrSock.sin_family = AF_INET;
    addrSock.sin_addr.S_un.S_addr = INADDR_ANY;
    addrSock.sin_port = htons(m_localport);
    BOOL bDontLinger = true;
    setsockopt(m_hSock,SOL_SOCKET,SO_REUSEADDR,(char *)&bDontLinger,sizeof(BOOL));
    if(bind(m_hSock,(SOCKADDR *)&addrSock,sizeof(SOCKADDR)) == SOCKET_ERROR)
    {
    strTemp.Format("Bind socket error!\r\nError code:%d",WSAGetLastError());
    AfxMessageBox(strTemp);
    return false;
    } int rc = WSAAsyncSelect(m_hSock,m_hWnd,WM_SOCK_RECV,FD_READ);
    if(rc == SOCKET_ERROR)
    {
    closesocket(m_hSock);
    strTemp.Format("Listen socket error!\r\nError code:%d",WSAGetLastError());
    AfxMessageBox(strTemp);
    return false;
    } return result;
    }void CUDPDlg::OnRecv(WPARAM wParam,LPARAM lParam)
    {
    SOCKET hSock = (SOCKET)wParam;
    SOCKADDR_IN clintSock;
    int sockLen = sizeof(SOCKADDR_IN);
    char buff[255] = "";
    CString strTemp = "";
    UpdateData();
    switch(LOWORD(lParam))
    {
    case FD_READ:
    recvfrom(hSock,buff,255,0,(SOCKADDR *)&clintSock,&sockLen);
    strTemp.Format("%s:%d>\r\n\t%s\r\n",inet_ntoa(clintSock.sin_addr),clintSock.sin_port,buff);
    m_recvtext += strTemp;
    UpdateData(false);
    break;
    }

    }
      

  21.   


    你的数据的第二个字节不是0X00,我把你的数据从前摘取了10个,能够成功赋值给CSTRING
      

  22.   

    OnRecv(WPARAM wParam,LPARAM lParam)
    这个函数要放回掉函数里么?
      

  23.   

    这个是自定义的Windows message.在发生WM_SOCK_RECV 时触发.
    我用的是WSAAsyncSelect模型BEGIN_MESSAGE_MAP(CUDPDlg, CDialog)
    //{{AFX_MSG_MAP(CUDPDlg)
    ON_WM_SYSCOMMAND()
    ON_WM_PAINT()
    ON_WM_QUERYDRAGICON()
    ON_BN_CLICKED(IDC_BUTTON_CONNECT, OnButtonConnect)
    ON_BN_CLICKED(IDC_BUTTON_SEND, OnButtonSend)
    //}}AFX_MSG_MAP
    ON_MESSAGE(WM_SOCK_RECV,OnRecv)  //接收消息
    END_MESSAGE_MAP()
      

  24.   

    //设置收发等待时间试下看看
    在send(),recv()过程中有时由于网络状况等原因,发收不能预期进行,而设置收发时限:
    int nNetTimeout=1000;//1秒
    //发送时限
    setsockopt(socket,SOL_S0CKET,SO_SNDTIMEO,(char *)&nNetTimeout,sizeof(int));
    //接收时限
    setsockopt(socket,SOL_S0CKET,SO_RCVTIMEO,(char *)&nNetTimeout,sizeof(int));
      

  25.   

    //程序两个地方有问题
    //发送和接受的数据不一定是字码
    //接受数据的长度是recvfrom函数的返回值,不要把数据赋值给字符串,在赋值过程中会丢失数据,直接用接受的char *发送即可
    发送代码改为如下:
    BOOL CSipServerManager::SendTo(SOCKET sck,const char * inBuffer,int len,DWORD strIP,int iPort)
    {
    if (sck != INVALID_SOCKET)
    {
    SOCKADDR_IN addr;
    memset((char *) &addr, 0, sizeof(addr)); 
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = htonl(strIP); //目标IP
    addr.sin_port = htons(iPort); //目标端口//向客户端或网关发消息
    int val = sendto(sck, inBuffer, len, 0, (sockaddr *) &addr, sizeof(addr));
    return (val != SOCKET_ERROR);
    }
    return FALSE;
    }