UDP 向一个错误端口发送数据后就没法接受数据了。

时间:2023-02-13 21:08:09
假设第一次客户端发送时的设定信息如下:
-----------------------
服务器受信端口号:50004(实际正确的服务器端口号为50002)
本地受信端口号  :50011
-----------------------
发送后当然服务器是接受不到数据的,
可是服务器再向客户端送信时客户端也接受不到数据了。
服务器送信的设定信息如下:
-----------------------
客户端端口号:50011
-----------------------

很让人郁闷,如果本地想要受信成功就必须把SOCKET清除再生成(BIND)一次。
我感觉是本地向一个未知端口(非正确的服务器端口)发送数据后会将自己的端口(50011)或是线程什么的锁住,
从而无法继续接受数据了。但是UDP是非连接的协议啊。怎么也会有这种现象呢?请大家指教!谢谢。

8 个解决方案

#1


拜托各位大大啊!帮帮忙吧!我都快急疯了,哪儿都找不到资料。
我这个UDP的SOCKET没有使用控件,是直接用SOCKET类的实例BIND的。
项目要求没法使用控件。我苦啊。
苦啊,苦啊,苦啊,苦啊,苦啊,苦啊,苦啊,苦啊,苦啊,苦啊。

#2


SIO_UDP_CONNRESET (opcode setting: I, T==3)
  Windows XP:  Controls whether UDP PORT_UNREACHABLE messages are reported. Set to TRUE to enable reporting. Set to FALSE to disable reporting
http://support.microsoft.com/kb/263823

#3


下面的代码段演示一技术,可使用 SIO_UDP_CONNRESET 控制代码,以获取原始的 Windows NT 4.0 行为调用 WSAIoctl 
DWORDdwBytesReturned = 0;
BOOLbNewBehavior = FALSE;
DWORDstatus;

// disable  new behavior using
// IOCTL: SIO_UDP_CONNRESET
status = WSAIoctl(sd, SIO_UDP_CONNRESET,
&bNewBehavior, sizeof(bNewBehavior),
                   NULL, 0, &dwBytesReturned,
                   NULL, NULL);

if (SOCKET_ERROR == status)
{
DWORD dwErr = WSAGetLastError();
if (WSAEWOULDBLOCK == dwErr)
{
// nothing to do
return(FALSE);
}
else
{
printf("WSAIoctl(SIO_UDP_CONNRESET) Error: %d\n", dwErr);
return(FALSE);
}
}


到能够编译此代码,您需要将包括 SIO_UDP_CONNRESET 的定义在最新 Mswsock.h 或将它的直接在您的代码的定义下面 
// MS Transport Provider IOCTL to control
// reporting PORT_UNREACHABLE messages
// on UDP sockets via recv/WSARecv/etc.
// Path TRUE in input buffer to enable (default if supported),
// FALSE to disable.
#defineSIO_UDP_CONNRESET_WSAIOW(IOC_VENDOR,12)

#4


对上面两位大大的支持万分感谢啊!可是使用WSAIoctl函数的话需要INCLUDE"winsock2.h"头文件,而我原有的既存项目里使用的都是"winsock.h"两个文件会冲突。会报“函数重复定义错误”。还有其它的办法么?

#5


把winsock.h文件随便改个名字,然后把引用winsock.h的地方都改成引用winsock2.h,这样就可以啦。

#6


把winsock.h文件随便改个名字,然后把引用winsock.h的地方都改成引用winsock2.h,这样就可以啦。

#7


谢谢大家,问题已经解决。改天把详细的办法再发上来。

#8


补发一下这个问题的解决方法。
以我自己的程序为例:我是直接将SOCKET类实例化来进行UDP通信的。
在对SOCKET进行BIND之前添加如下代码:
    DWORD               di_w_dwBytesReturned;
    BOOL                di_b_bNewBehavior;

    if( SOCKET_ERROR == WSAIoctl ( t_sock, // t_sock为实例化后的对象
        SIO_UDP_CONNRESET,&di_b_bNewBehavior,
        sizeof( di_b_bNewBehavior ),
        NULL,0,
        &di_w_dwBytesReturned,NULL,NULL) )
    {
        return 错误消息;
    }
要使用上面这个函数必须在调用该函数的文件内导入下面两个头文件
#include <winsock2.h>
#include <Mswsock.h> 
但是直接这样导入的话会出现多重定义的错误。
所以必须在位于以下目录中的windows.h里追加#include <winsock2.h>语句,并且一定要添加在#include <winsock.h>前面。
文件路径:\Borland\CBuilder6\Include

以上操作结束后还要在项目工程中导入以下库文件不然会出现未找到WSAIoctl函数实现的链接错误。
ws2_32.lib
文件路径:\Borland\CBuilder6\Lib
以上的操作完成后问题就解决了。不过由于要改动builder环境下的头文件所以感觉还是有点怪怪的。
如果有什么错误或者有更好的解决办法还请大家多批评指正。

#1


拜托各位大大啊!帮帮忙吧!我都快急疯了,哪儿都找不到资料。
我这个UDP的SOCKET没有使用控件,是直接用SOCKET类的实例BIND的。
项目要求没法使用控件。我苦啊。
苦啊,苦啊,苦啊,苦啊,苦啊,苦啊,苦啊,苦啊,苦啊,苦啊。

#2


SIO_UDP_CONNRESET (opcode setting: I, T==3)
  Windows XP:  Controls whether UDP PORT_UNREACHABLE messages are reported. Set to TRUE to enable reporting. Set to FALSE to disable reporting
http://support.microsoft.com/kb/263823

#3


下面的代码段演示一技术,可使用 SIO_UDP_CONNRESET 控制代码,以获取原始的 Windows NT 4.0 行为调用 WSAIoctl 
DWORDdwBytesReturned = 0;
BOOLbNewBehavior = FALSE;
DWORDstatus;

// disable  new behavior using
// IOCTL: SIO_UDP_CONNRESET
status = WSAIoctl(sd, SIO_UDP_CONNRESET,
&bNewBehavior, sizeof(bNewBehavior),
                   NULL, 0, &dwBytesReturned,
                   NULL, NULL);

if (SOCKET_ERROR == status)
{
DWORD dwErr = WSAGetLastError();
if (WSAEWOULDBLOCK == dwErr)
{
// nothing to do
return(FALSE);
}
else
{
printf("WSAIoctl(SIO_UDP_CONNRESET) Error: %d\n", dwErr);
return(FALSE);
}
}


到能够编译此代码,您需要将包括 SIO_UDP_CONNRESET 的定义在最新 Mswsock.h 或将它的直接在您的代码的定义下面 
// MS Transport Provider IOCTL to control
// reporting PORT_UNREACHABLE messages
// on UDP sockets via recv/WSARecv/etc.
// Path TRUE in input buffer to enable (default if supported),
// FALSE to disable.
#defineSIO_UDP_CONNRESET_WSAIOW(IOC_VENDOR,12)

#4


对上面两位大大的支持万分感谢啊!可是使用WSAIoctl函数的话需要INCLUDE"winsock2.h"头文件,而我原有的既存项目里使用的都是"winsock.h"两个文件会冲突。会报“函数重复定义错误”。还有其它的办法么?

#5


把winsock.h文件随便改个名字,然后把引用winsock.h的地方都改成引用winsock2.h,这样就可以啦。

#6


把winsock.h文件随便改个名字,然后把引用winsock.h的地方都改成引用winsock2.h,这样就可以啦。

#7


谢谢大家,问题已经解决。改天把详细的办法再发上来。

#8


补发一下这个问题的解决方法。
以我自己的程序为例:我是直接将SOCKET类实例化来进行UDP通信的。
在对SOCKET进行BIND之前添加如下代码:
    DWORD               di_w_dwBytesReturned;
    BOOL                di_b_bNewBehavior;

    if( SOCKET_ERROR == WSAIoctl ( t_sock, // t_sock为实例化后的对象
        SIO_UDP_CONNRESET,&di_b_bNewBehavior,
        sizeof( di_b_bNewBehavior ),
        NULL,0,
        &di_w_dwBytesReturned,NULL,NULL) )
    {
        return 错误消息;
    }
要使用上面这个函数必须在调用该函数的文件内导入下面两个头文件
#include <winsock2.h>
#include <Mswsock.h> 
但是直接这样导入的话会出现多重定义的错误。
所以必须在位于以下目录中的windows.h里追加#include <winsock2.h>语句,并且一定要添加在#include <winsock.h>前面。
文件路径:\Borland\CBuilder6\Include

以上操作结束后还要在项目工程中导入以下库文件不然会出现未找到WSAIoctl函数实现的链接错误。
ws2_32.lib
文件路径:\Borland\CBuilder6\Lib
以上的操作完成后问题就解决了。不过由于要改动builder环境下的头文件所以感觉还是有点怪怪的。
如果有什么错误或者有更好的解决办法还请大家多批评指正。