关于WSAConnect返回的10048错误,why??谢谢!

viewerviewer 2006-06-12 04:33:09
客户端,用tcp连接,
bind(...)没有返回错误,
用的是WSAEventSelect,
调用WSAConnect()后,在WSAEnumNetworkEvents返回的NetworkEvents中的:
lparam = (NetworkEvents.iErrorCode[FD_CONNECT_BIT];
此时lparam的值为10048;但用WSAGetLastError()却得到的是0。

按道理说,要是地址或者端口被占用的话,在bind()时就应该返回错误才是,不知为什么??
请教各位。
...全文
608 17 打赏 收藏 转发到动态 举报
写回复
用AI写文章
17 条回复
切换为时间正序
请发表友善的回复…
发表回复
viewerviewer 2006-06-20
  • 打赏
  • 举报
回复
已改变应用,避免使用bind。
结。
化外之民 2006-06-16
  • 打赏
  • 举报
回复
mark
viewerviewer 2006-06-16
  • 打赏
  • 举报
回复
谢谢!
SO_LINGER、SO_DONTLINGER、SO_REUSEADDR都不能解决问题。

另:
关于TIME_WAIT,《Windows网络编程(第2版)》第一章里面描述的很清楚,基本意思是说:
主动关闭时肯定会进入TIME_WAIT状态,被动关闭时却不会,这个描述跟这里出现的问题相吻合。

《Windows网络编程(第2版)》给出的方法是用SO_REUSEADDR,但经测试,不能解决。

此外,MSDN里面说的是TIME_WAIT要持续 2MSL 的时间段,且默认2MSL = 4分钟,所以要4分钟才能完

全脱离TIME_WAIT。
这个值是在注册表里面可以设置的:
From the HKEY_LOCAL_MACHINE subtree, go to the following key:
\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters

MSDN具体描述如下:

TcpTimedWaitDelay (new in Windows NT versions 3.51 SP5 and later)
Key: Tcpip\Parameters
Value Type: REG_DWORD - Time in seconds
Valid Range: 30-300 (decimal)
Default: 0xF0 (240 decimal)
Description: This parameter determines the length of time that a connection
will stay in the TIME_WAIT state when being closed. While a connection is
in the TIME_WAIT state, the socket pair cannot be re- used. This is also
known as the "2MSL" state, as by RFC the value should be twice the
maximum segment lifetime on the network. See RFC793 for further details.

增加键值:TcpTimedWaitDelay,类型为REG_DWORD.
并且要重启计算机,这种方法可以把TIME_WAIT的最少持续时间限制为30s。
这方法经测试,有效,但个人认为不能作为最终解决之道。
godfly000 2006-06-15
  • 打赏
  • 举报
回复
刚在gdy119 (夜风微凉)的帖子上看到的,看看又没没有用
godfly000 2006-06-15
  • 打赏
  • 举报
回复
如果要已经处于连接状态的soket在调用closesocket后强制关闭,不经历
TIME_WAIT的过程:
BOOL bDontLinger = FALSE;
setsockopt(s,SOL_SOCKET,SO_DONTLINGER,(const char*)&bDontLinger,sizeof(BOOL));
gao_ming77 2006-06-14
  • 打赏
  • 举报
回复
哦,想起来了,你去掉SO_LINGER,这种事shutdown SOCKET就立即关断的。
具体看看MSDN.
viewerviewer 2006-06-13
  • 打赏
  • 举报
回复
To godfly000:已经发送,请查收,谢谢!
godfly000 2006-06-13
  • 打赏
  • 举报
回复
godfly000@163.com
服务器端有没有设置断开连接的处理代码?
viewerviewer 2006-06-13
  • 打赏
  • 举报
回复
int nRet = WSAConnect(..);
nRet的值为SOCKET_ERROR,并且此时WSAGetLastError返回的是WSAEWOULDBLOCK(10035),这是合理的。

另外,出现10048错误也不是一直出现,所以偶尔还是会连接上的。
还发现一种情况:
若是连接上后,要是服务器主动断开连接,然后客户端收到FD_CLOSE后再自己Close,若此时又connect,则可以连接成功;
若是连接上后,客户端主动断开Close,此时就再也连不上了。
开始以为是服务器和客户端在同一台机子上的缘故,但分开2台机子测试也是一样。
就算是把服务器和客户端程序关掉,然后再重新启动程序,第一次连接都会出现这种情况,不管换什么端口号都一样。
这代码也很容易测试,随便写个tcp服务器就可以测试了,就用《Windows网络编程技术》上面的那个server稍微修改一下就可以了。
各位要是用空帮俺调试一下,感激不禁,要测试代码也是可以的,留下EMail,谢谢!
viewerviewer 2006-06-13
  • 打赏
  • 举报
回复
另:用netstat看到的结果是:

Active Connections

Proto Local Address Foreign Address State
TCP jiang:5000 jiang:7000 TIME_WAIT
TCP jiang:5001 jiang:7000 TIME_WAIT
TCP jiang:5002 jiang:7000 TIME_WAIT
TCP jiang:5003 jiang:7000 TIME_WAIT
TCP jiang:5004 jiang:7000 TIME_WAIT
TCP jiang:5005 jiang:7000 TIME_WAIT
TCP jiang:5006 jiang:7000 TIME_WAIT
TCP jiang:5007 jiang:7000 TIME_WAIT
TCP jiang:5008 jiang:7000 TIME_WAIT
TCP jiang:5009 jiang:7000 TIME_WAIT
TCP jiang:5010 jiang:7000 TIME_WAIT
TCP jiang:5011 jiang:7000 TIME_WAIT
TCP jiang:5012 jiang:7000 TIME_WAIT
TCP jiang:5013 jiang:7000 TIME_WAIT
TCP jiang:5014 jiang:7000 TIME_WAIT
TCP jiang:5015 jiang:7000 TIME_WAIT

所以,即使
shutdown(m_hSocket,SD_BOTH);
closesocket(m_hSocket);
也不能关闭该端口。
服务器和客户端都是显式的关闭了的,不知为什么那么久,几分钟了都不能完全关闭。
viewerviewer 2006-06-13
  • 打赏
  • 举报
回复
多谢各位!
但问题还是没有解决:
1、不管是有没有加上SO_REUSEADDR选项,都不行。
2、不用客户端bind的话当然没有这个问题出现,但是由于应用2端都需要知道这个端口号,所以要bind,不bind的话客户端能否得到该自动分配的端口号?
3、第一次连接成功,只要是客户端主动Close,然后立即连接或者立即重新启动客户端连接,都不行。
但又测试发现,过了几分钟后再连接或者再启动客户端连接的话又能连接上了,估计是3-5分钟左右。
由此,推测可能的原因是:
or a socket that was not closed properly, or one that is still in the process of closing.
但事实上已经调用
shutdown(m_hSocket,SD_BOTH);
closesocket(m_hSocket);
,就算再慢也没有等到几分钟还不能完全关闭socket的道理。
gao_ming77 2006-06-13
  • 打赏
  • 举报
回复
同意godfly000(),可能你的socket设置有端口重用。我以前好像也碰到类似的问题。
特别是调试的时候,退出程序以后,然后重新debug,经常碰到10048,“地址被占用的错误”。
你试试setsockopt 去掉SO_REUSEADDR选项?
godfly000 2006-06-13
  • 打赏
  • 举报
回复
服务器端口与客户端设置的远程端口一样的话,第一次连接成功,以后nRet的值为SOCKET_ERROR,并且此时WSAGetLastError返回的是WSAEWOULDBLOCK(10035),这是合理的。
另外:
WSAEADDRINUSE (10048)
Address already in use.
Typically, only one usage of each socket address (protocol/IP address/port) is permitted. This error occurs if an application attempts to bind a socket to an IP address/port that has already been used for an existing socket, or a socket that was not closed properly, or one that is still in the process of closing. For server applications that need to bind multiple sockets to the same port number, consider using setsockopt(SO_REUSEADDR). Client applications usually need not call bind at all—connect chooses an unused port automatically. When bind is called with a wildcard address (involving ADDR_ANY), a WSAEADDRINUSE error could be delayed until the specific address is committed. This could happen with a call to another function later, including connect, listen, WSAConnect, or WSAJoinLeaf.
nuaawenlin 2006-06-12
  • 打赏
  • 举报
回复
int nRet = WSAConnect(m_hSocket,
(struct sockaddr*)&m_saDesAddr,
sizeof(struct sockaddr),
NULL, NULL, NULL, NULL);
看看nRet的返回值
viewerviewer 2006-06-12
  • 打赏
  • 举报
回复

附上简单的源代码:

CSocketTCP是封装的一个类,有Open(...),Connect(...),Close(...)3个函数。

BOOL CSocketTCP::Open(char *strLocalBindIp, //本地IP
u_short u_sLocalPort, //本地端口
char *strDesIp, //远程IP
u_short u_sRemotePort//远程端口
)
{
Close();

//create socket
DWORD dwFlags = WSA_FLAG_OVERLAPPED;

if(strDesIp) //设置远程地址信息.
{
u_long ulDesAddr = inet_addr(strDesIp);
ZeroMemory(&m_saDesAddr,sizeof(SOCKADDR_IN));
m_saDesAddr.sin_family = AF_INET;
m_saDesAddr.sin_port = htons(u_sRemotePort);
m_saDesAddr.sin_addr.S_un.S_addr = ulDesAddr;
}

if((m_hSocket = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, dwFlags)) == INVALID_SOCKET)
{
DWORD dwErr = WSAGetLastError();
return FALSE;
}
DT("m_hSocket: %d", m_hSocket);
ZeroMemory(&m_saSrcAddr,sizeof(SOCKADDR_IN));

//设置本地地址信息
m_saSrcAddr.sin_family = AF_INET;
m_saSrcAddr.sin_port = htons(u_sLocalPort);
m_saSrcAddr.sin_addr.s_addr = htonl(INADDR_ANY);
m_bInited = TRUE;

//绑定地址.
int ret = 0;
ret=bind(m_hSocket,(LPSOCKADDR)&m_saSrcAddr,sizeof(m_saSrcAddr));//此时返回成功代码
if(ret == SOCKET_ERROR)
{
DWORD dwErr = WSAGetLastError();
DT("Bind Error: %d", dwErr);
return FALSE;
}

//set TTL(32) to 64
int nMaxTTL = 64;
setsockopt(m_hSocket,IPPROTO_IP,IP_TTL,(char *)&nMaxTTL,sizeof(int));

if(m_hEvent == WSA_INVALID_EVENT)
m_hEvent = WSACreateEvent();

WSAEventSelect(
m_hSocket,
m_hEvent,
FD_READ | FD_CONNECT | FD_CLOSE
);

return TRUE;
}

BOOL CSocketTCP::Connect()
{
if(m_bConnected)
return 0;
int nRet = WSAConnect(m_hSocket,
(struct sockaddr*)&m_saDesAddr,
sizeof(struct sockaddr),
NULL, NULL, NULL, NULL);
m_bConnected = TRUE;
return nRet;
}


BOOL CSocketTCP::Close()
{
if (m_hSocket != INVALID_SOCKET)
{
shutdown(m_hSocket,SD_BOTH);
closesocket(m_hSocket);
m_hSocket = INVALID_SOCKET;
m_bConnected = FALSE;
}
if(m_hEvent != WSA_INVALID_EVENT)
{
CloseHandle(m_hEvent);
m_hEvent = WSA_INVALID_EVENT;
}
return TRUE;


测试代码:

//建立连接:
void CTestDlg::OnButton1()
{
// TODO: Add your control notification handler code here

for(int i = 0; i < 16; i ++)
{
m_skSocketTCP[i].Open(NULL, 5000 + i, "192.168.0.31", 7000);
//以下启动其他辅助线程来处理FD_READ | FD_CONNECT | FD_CLOSE
m_pThreadClient[i] = new CThreadClient(i);
m_pThreadClient[i]->ResumeThread();
}
for(i = 0; i < 16; i ++)
{
m_skSocketTCP[i].Connect();
}
}

//断开连接:
void CTestDlg::OnButton2()
{
// TODO: Add your control notification handler code here

for(int i = 0; i < 16; i ++)
{
m_skSocketTCP[i].Close();
if(m_pThreadClient[i] != NULL)
{
delete m_pThreadClient[i];
m_pThreadClient[i] = NULL;
}
}
}
WecanHuang 2006-06-12
  • 打赏
  • 举报
回复
通常每个套接字地址 (协议/网络地址/端口) 只允许使用一次。

18,356

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 网络编程
c++c语言开发语言 技术论坛(原bbs)
社区管理员
  • 网络编程
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧