2012-02-21 110 views
2

我从.Net应用程序发送1404浮点值,通过udp套接字组成了5616字节。我没有例外关闭此操作。如何轻松解决在Wsock2上的10040消息太长错误

但是,接收这些数据的程序是一个C++应用程序,并且在接收到这种数量的数据时,我得到一个10040消息太长的错误。

显然1480bytes是Wsock2中消息的最大可能大小。

什么是最简单,最干净的方法来解决这个问题?

谢谢!

编辑:发布一些代码:

这是我的插座J_Receive类:

#include "J_Receive.h" 


#include <stdio.h> 
#include <fcntl.h> 
#include <sys/types.h> 
#if defined (WIN32) && !defined(__CYGWIN__) 
#include <winsock.h> 
#else 
#include <unistd.h> 
#include <sys/uio.h> 
#include <sys/socket.h> 
#include <netinet/in.h> 
#include <netdb.h> 
#include <arpa/inet.h> 
#include <sys/time.h> 
#endif 
#include <string.h> 

#include <iostream> 

using namespace sockets; 

J_Recibir::J_Recibir(void) 
{ 
    _port = 0; 
    _initialized = false; 
    _buffer = 0L; 
} 

J_Recibir::~J_Recibir(void) 
{ 
#if defined (WIN32) && !defined(__CYGWIN__) 
    closesocket(_so); 
#else 
    close(_so); 
#endif 
} 

bool J_Recibir::init(void) 
{ 
#if defined(WIN32) && !defined(__CYGWIN__) 
    WORD version = MAKEWORD(1,1); 
    WSADATA wsaData; 
    // First, we start up Winsock 
    WSAStartup(version, &wsaData); 
#endif 

    if(_port == 0) 
    { 
    fprintf(stderr, "Receiver::init() - port not defined\n"); 
    return false; 
    } 

    if((_so = socket(AF_INET, SOCK_DGRAM, 0)) < 0) 
    { 
     perror("Socket"); 
    return false; 
    } 



    /*int buffsize = 50000; 
    setsockopt(_so, SOL_SOCKET, SO_RCVBUF, (const char*)&buffsize, sizeof(buffsize));*/ 

#if defined (WIN32) && !defined(__CYGWIN__) 
// const BOOL on = TRUE; 
// setsockopt(_so, SOL_SOCKET, SO_REUSEADDR, (const char*) &on, sizeof(int)); 
#else 
    int on = 1; 
    setsockopt(_so, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); 
#endif 




// struct sockaddr_in saddr; 
    saddr.sin_family = AF_INET; 
    saddr.sin_port = htons(_port); 
#if defined (WIN32) && !defined(__CYGWIN__) 
    saddr.sin_addr.s_addr = htonl(INADDR_ANY); 
#else 
    saddr.sin_addr.s_addr = 0; 
#endif 

    if(bind(_so, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) 
    { 
     perror("bind"); 
     return false; 
    } 

    u_long iMode = 1;  // 1 para No bloqueante, 0 para bloqueante 
    ioctlsocket(_so, FIONBIO, &iMode); 

    _initialized = true; 
    return _initialized; 
} 


void J_Recibir::setPort(const short port) 
{ 
    _port = port; 
} 

void J_Recibir::setBuffer(void *buffer, const unsigned int size) 
{ 
    _buffer = buffer; 
    _buffer_size = size; 
} 

int J_Recibir::sync(void) 
{ 
    if(!_initialized) init(); 

    if(_buffer == 0L) 
    { 
     fprintf(stderr, "Receiver::sync() - No buffer\n"); 
     return -1; 
    } 

#if defined(__linux) || defined(__FreeBSD__) || defined(__APPLE__) 
    socklen_t 
#else 
    int 
#endif 
     size = sizeof(struct sockaddr_in); 

    fd_set fdset; 
    FD_ZERO(&fdset); 
    FD_SET(_so, &fdset); 

    struct timeval tv; 
    tv.tv_sec = 0; 
    tv.tv_usec = 0; 

#if defined (WIN32) && !defined(__CYGWIN__) 
// saddr.sin_port = htons(_port); 
    recvfrom(_so, (char *)_buffer, _buffer_size, 0, (sockaddr*)&saddr, &size); 


// recvfrom(sock_Receive, szMessage, 256, 0, (sockaddr*)&addr_Cli, &clilen) 
    int err = WSAGetLastError(); 
    if (err!=0){ 
     fprintf(stderr, "Receiver::sync() - error %d\n",err); 
     perror("Error: "); 
    } 

    while(select(_so+1, &fdset, 0L, 0L, &tv)) 
    { 
     if(FD_ISSET(_so, &fdset)) 
     { 
      recvfrom(_so, (char *)_buffer, _buffer_size, 0, (sockaddr*)&saddr, &size); 
     } 
    } 
#else 
    recvfrom(_so, (caddr_t)_buffer, _buffer_size, 0, 0, &size); 
    while(select(_so+1, &fdset, 0L, 0L, &tv)) 
    { 
     if(FD_ISSET(_so, &fdset)) 
     { 
      recvfrom(_so, (caddr_t)_buffer, _buffer_size, 0, 0, &size); 
     } 
    } 
#endif 

    if (err!=0) return -1; 
    else  return 0; 
} 

这是我如何调用接收功能:

 sockets::J_Receiver receiverGUI = new sockets::J_Recibir(); 
    receiverGUI->setPort(4020); 
    nDatosGUI = 1404; 
    float* datosGUI = new datosGUI[nDatosGUI ]; 
    receiverGUI->setBuffer((void *)datosGUI, sizeof(float)*nDatosGUI); 

回答

4

WSAEMSGSIZE通常意味着您提供给recvfrom()的缓冲区小于传入的数据报。检查或发布您的recvfrom()代码,以确保您使用的是足够大且正确声明的缓冲区。由于IPv4数据包在理论上可以达到64千字节,因此总是使用大型缓冲区是最安全的。

+0

我从1404浮动缓冲区发送并接收到1404浮动缓冲区。这不应该是相同的大小? – 2012-02-22 09:06:55

+0

不,您的缓冲区需要足够大以处理任何可能到达的数据报。除了防火墙之外,您可以随时随地从任何地方接收任何大小的数据报,而不仅仅是发送程序。所以至少你需要防止那些阻塞你的接收队列。但它更可能是你发送的数据超过你的意思。这将有助于查看代码。 – 2012-02-22 15:55:02

+0

你没事,我正在调整我的缓冲区大小,现在它的大小为5616字节,但现在程序只是永远挂起,这是否与阻塞套接字有关? – 2012-02-23 09:45:38

1

MSDN documentation的阅读错误WSAEMSGSIZE(10040):

消息太长。

在数据报套接字上发送的消息大于内部消息缓冲区或其他网络限制,或者用于接收数据报的缓冲区小于数据报本身。

这可能意味着您的接收缓冲区太小,您需要将其放大。这是通过setsockopt函数和SO_RCVBUF选项完成的。

+0

所以这段代码应该工作: int buffsize = 50000; setsockopt(_so,SOL_SOCKET,SO_RCVBUF,&buffsize,sizeof(buffsize)); 但我无法编译,因为setsockopt需要一个const char *并且使用一个转换器什么也不做:( – 2012-02-21 13:39:38

+0

根据这篇文章:http:// stackoverflow。com/questions/2566915/setsockopt-sys-socket-h 使用一个int应该可以工作,这让我很困惑:$ – 2012-02-21 13:43:21

+0

@kelmer这个应该可以工作,你应该只是施加参数:'(const char *)&buffsize' – 2012-02-21 13:51:27

1

10040告诉您在拨打recvfrom()时要使用更大的缓冲区。这并不意味着你要增加套接字内部接收缓冲区的大小。

既然你已经知道你期待有多少花车接受,简单地声明足够大以容纳所有这些,如缓冲区:

float buffer[1404]; 
int ret = recvfrom(..., (char*)&buffer[0], sizeof(buffer), ...); 

的Winsock肯定不会对消息的1480字节的限制。

相关问题