Код ошибки 10040

I’m sending from a .Net application 1404 float values which make up for 5616 bytes through an udp socket. I get no exceptions off this operation.

However, the program receiving those data, is a C++ application, and when receiving such amount of data I get a 10040 message too long error.

Apparently 1480bytes is the longest size possible for messages in Wsock2.

What would be the easiest, cleanest way to fix this?

Thanks!

EDIT: Posting some code:

This is my socket J_Receive class:

#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 definedn" );
    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 buffern" );
        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 %dn",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;
}

And this is how I call the receive function:

     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);

Я отправляю из .Net-приложения 1404 значения с плавающей запятой, которые составляют 5616 байт через сокет udp. Я не исключаю исключений из этой операции.

Однако программа, получающая эти данные, является приложением С++, и при получении такого количества данных я получаю сообщение об ошибке 10040 слишком долго.

По-видимому, 1480 байтов является самым длинным размером для сообщений в Wsock2.

Каким будет самый простой, самый чистый способ исправить это?

Спасибо!

EDIT: Проводка кода:

Это мой сокет. Класс 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 definedn" );
    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 buffern" );
        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 %dn",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);

I have a UDP sender and a UDP listener. Transfering messages works nicely. But…

It appears when I am overfeeding (sending sustained data quickly) the listening socket may throw on the call to ReceiveFrom with error code 10040 which means some buffer was not large enough. The exception message is

A message sent on a datagram socket was larger than the internal
message buffer or some other network limit, or the buffer used to
receive a datagram into was smaller than the datagram itself.

Fair enough. But the problem is I will then get this exception on every following call to ReceiveFrom. The socket appears broken. I am willing to accept the transfer failed but I now want to flush the socket’s receive buffer and continue.

I can prevent this from happening by setting a substantial receive buffer size of 128K on the listening socket (as opposed to the default of 8K). I can also fix it by having the sender pause for 1 ms after sending a chunk of 65507 bytes of a multi-chunk bulk message.

But I do not feel safe. If this exception still occurs, I want to log and continue (better luck next time). Recreating the socket and restarting the listen thread seems blunt. Is there a better way?

Something unrelated I do not like: Socket.ReceiveFrom throws an exception after the timeout. This is stupid, timeouts are normal behavior. I would expect a TryReceiveFrom method and I do not like using the exception handler as a flow control statement, which seems to be the only option I have. Is there a better way?

[Edit]

On further scrutiny (I ran into exceptions being thrown again after sending messages in one piece in an effort to optimize) I found the main reason for my troubles. It turns out the ReceiveFrom method is not the friendliest API…

Here it says:

«With connectionless protocols, ReceiveFrom will read the first
enqueued datagram received into the local network buffer. If the
datagram you receive is larger than the size of buffer, the
ReceiveFrom method will fill buffer with as much of the message as is
possible, and throw a SocketException.»

In other words: with UDP a full datagram will always be returned regardless the size argument, which is effectively ignored in its capacity as a limiter, and you’d better make sure your buffer is big enough.

So you want the buffer passed to ReceiveFrom to be at least 64K in order for it to be big enough for the biggest possible datagram, see what you got by checking the return value and work with that.

It gets a little worst still: the size argument is not entirely ignored, if offset plus size exceeds the length of your buffer you also get an exception. So it is ignored on the one hand because it does not limit the number of bytes being written to your buffer but it is still being sanity-checked.

After discovering this quirk and respecting it I did have not had any overruns, no matter how hard I bashed it from the sending end (I send a large bitmap repeatedly without pausing). The report on my journey my save others some frustration.

#python #sockets #udp #game-development #imutils

#python #сокеты #udp #разработка игр #imutils

Вопрос:

Я пытаюсь создать приложение с использованием python для совместного просмотра фильмов, но я постоянно получаю ошибки с :

[Errno 10040] Сообщение, отправленное в сокет дейтаграммы, было больше, чем внутренний буфер сообщений или какой-либо другой сетевой лимит, или буфер, используемый для приема дейтаграммы, был меньше самой дейтаграммы

Server.py

 BUFFOR_SIZE_DATA = 65536

# SERVER SETTINGS
server_socket_main = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
server_socket_main.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, BUFFOR_SIZE_DATA)

print(Fore.RED   'UDP Server')
host_name = socket.gethostname()
print('HOST NAME:',host_name)
host_ip_adress = ''
print('HOST IP:',host_ip_adress)
host_port = 1337
socket_adress_main = (host_ip_adress, host_port)
print('PORT:',host_port)
server_socket_main.bind(socket_adress_main)
print(Fore.GREEN   'Server is listening > > >')
print(Fore.WHITE   ' ')
print(Fore.WHITE   'Connected devices: ')

# VIDEO U WANT TO WATCH TOGETHER
server_video_main = cv2.VideoCapture('movies/exmpl.mp4')

# MAIN LOOP
while True:
    msg, client_addres_obligatory = server_socket_main.recvfrom(BUFFOR_SIZE_DATA)
    print('Connected from ', client_addres_obligatory)
    WIDTH = 1024
    while(server_video_main.isOpened()):
        _,frame = server_video_main.read()
        frame = imutils.resize(frame, width=WIDTH)
        encoded, buffer = cv2.imencode('.jpg', frame, [cv2.IMWRITE_JPEG_QUALITY, 80])
        message = base64.b64encode(buffer)
        server_socket_main.sendto(message, client_addres_obligatory)
        cv2.imshow('HOST | Currently hosting', frame)
        key = cv2.waitKey(1) amp; 0xFF
        if key == ord('c'):
            server_socket_main.close()
            break

 

Client.py

 client_socket_main.sendto(welcomemessage.encode(), (client_ip_adress, client_port))

while True:
    packet,_ = client_socket_main.recvfrom(BUFFOR_SIZE_DATA)
    data = base64.b85decode(packet,' /')
    npdata = np.fromstring(data, dtype=np.unit8)
    frame = cv2.imdecode(npdata, 1)
    cv2.imshow('Currently watching ', frame)
    key = cv2.waitKey(1) amp; 0xFF
    if key == ord('c'):
        client_socket_main.close()
        break

 
 data = base64.b85decode(packet,' /')
 

Ошибка типа: b85decode() принимает 1 позиционный аргумент, но было задано 2

Заранее спасибо!

Ответ №1:

Ограничение в 64 КБ определяется не UDP, а IP. Вот заголовок IPv4 из исходного RFC:

     0                   1                   2                   3
    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
   |Version|  IHL  |Type of Service|          Total Length         |
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
   |         Identification        |Flags|      Fragment Offset    |
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
   |  Time to Live |    Protocol   |         Header Checksum       |
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
   |                       Source Address                          |
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
   |                    Destination Address                        |
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
   |                    Options                    |    Padding    |
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
 

Видите это поле «Общая длина»? Это 16 бит, поэтому его максимальное значение равно 0xffff, что равно 64Ki. Это даже включает заголовки, поэтому фактический максимальный размер меньше.

Кроме того, типичный MTU в Интернете составляет 1500 байт, иногда меньше (опять же, включая заголовки). Отправка пакетов, превышающих MTU, — это путь к неприятностям, потому что это означает, что произойдет фрагментация IP, что нежелательно.

Вам нужно разбить данные на более мелкие фрагменты или использовать TCP, который позаботится об этом за вас.

Комментарии:

1. Это сообщение об ошибке очень четкое. base64.b85decode ожидает один аргумент, но вы дали ему два.

Понравилась статья? Поделить с друзьями:
  • Код ошибки 1004 мегафон
  • Код ошибки 1004 геншин импакт
  • Код ошибки 1004 вк как исправить
  • Код ошибки 10038
  • Код ошибки 10031