有关socket端口重用的问题

oldmtn 2014-08-17 05:21:02
假设有3台机器,其中2台服务器,1台客户端。

客户端知道服务器的IP地址,

1. 客户端新建一个套接字A,绑定本地一个IP,然后connect一个服务器。
2. 连接后closesocket关闭套接字A,再新建一个套接字B,也绑定到同样的IP地址及端口,此时该端口无法被绑定。

如何解决呢?
...全文
674 13 打赏 收藏 转发到动态 举报
写回复
用AI写文章
13 条回复
切换为时间正序
请发表友善的回复…
发表回复
Henzox 2014-10-09
  • 打赏
  • 举报
回复
楼上所说的都不完全正确,在理想情况下,closesocket 之后,就可以重复使用 IP-Port 对了。 closesocket 会发关结束包到对端以完成本方的主动关闭,在不理想情况下,这个包也是有可能会被丢掉的,此时就要等待超时来释放资源,这个时间会持续很长,所以此时重用就不可行了。 可以设置 setsockopt( sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on) ); 但更推荐重新设计程序,因为这样做好像意义不大。
oldmtn 2014-09-10
  • 打赏
  • 举报
回复
引用 10 楼 oyljerry 的回复:
setsockopt( sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on) ); 要么就是设置重用地址 不然就是释放socket,当不需要的时候
释放并不是那么及时,需要一段时间才能彻底释放干净。
oyljerry 2014-08-18
  • 打赏
  • 举报
回复
setsockopt( sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on) ); 要么就是设置重用地址 不然就是释放socket,当不需要的时候
mayudong1 2014-08-18
  • 打赏
  • 举报
回复
无法绑定是因为在关闭套接字之后套接字处于一个time_wait的状态,这个状态会持续一段时间,此时再次绑定就会失败 解决办法就是不绑定到某个地址上让系统自己分配 或者 可以试一下1楼说的 setsockopt( sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on) );
xian_wwq 2014-08-18
  • 打赏
  • 举报
回复
引用 7 楼 oldmtn 的回复:
[quote=引用 6 楼 oldmtn 的回复:] [quote=引用 4 楼 woheduole 的回复:] 我closesocket之后, 再新建, 是可以帮定到同一个IP和端口的,不知道你哪里什么问题
昨天我测试过了,的确可以的。 但是你有没有考虑过,这样频繁的closesocket,再新建一个socket,当很多次的话,有没有可能泄漏资源。 对效率有没有影响,closesocket底层到底做了什么?[/quote] 还有,如果可以在closesocket后,有没有可能不新建一个socket,还可以继续打开该socket. 也就是有没有,或者自己能否实现一个opensocket的函数。[/quote] socket要复用,就不要closesocket, 而是调用disconnectEx函数,以此为基础可以构建socket池, 道理和内存池类似,实现复用。
oldmtn 2014-08-18
  • 打赏
  • 举报
回复
引用 6 楼 oldmtn 的回复:
[quote=引用 4 楼 woheduole 的回复:] 我closesocket之后, 再新建, 是可以帮定到同一个IP和端口的,不知道你哪里什么问题
昨天我测试过了,的确可以的。 但是你有没有考虑过,这样频繁的closesocket,再新建一个socket,当很多次的话,有没有可能泄漏资源。 对效率有没有影响,closesocket底层到底做了什么?[/quote] 还有,如果可以在closesocket后,有没有可能不新建一个socket,还可以继续打开该socket. 也就是有没有,或者自己能否实现一个opensocket的函数。
oldmtn 2014-08-18
  • 打赏
  • 举报
回复
引用 4 楼 woheduole 的回复:
我closesocket之后, 再新建, 是可以帮定到同一个IP和端口的,不知道你哪里什么问题
昨天我测试过了,的确可以的。 但是你有没有考虑过,这样频繁的closesocket,再新建一个socket,当很多次的话,有没有可能泄漏资源。 对效率有没有影响,closesocket底层到底做了什么?
我喝多了 2014-08-17
  • 打赏
  • 举报
回复


//服务器连接测试函数
BOOL CMainFrame::ServerConnectTest(char* pszIP, short nPort)
{
	SOCKADDR_IN LocalAddr = {0};//本地地址
	SOCKADDR_IN SerAddr = {0};//服务器地址
	int nLen = sizeof(SerAddr);
	BOOL bRet = FALSE;
	DWORD dwWait = 0;

	//服务器连接测试, 发送2个CMD_CONNECT_TEST
	CommunicationCMD cmd = {0};
	cmd.nCmd1 = CMD_CONNECT_TEST;
	cmd.nCmd2 = CMD_CONNECT_TEST;

	DWORD dwSendByte = 0;
	OVERLAPPED ol = {0};

	DWORD dwFlags = 0;
	char szRecvbuf[8] = {0};
	WSABUF wsabuf = {0};//接收缓冲区
	DWORD dwRecv = 0;//接收长度

	SOCKET s = ::WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED);
	if (INVALID_SOCKET == s)
		goto OPFAILED;

	LocalAddr.sin_family = AF_INET;
	LocalAddr.sin_port = ::htons(105);//使用0让系统自动分配
	LocalAddr.sin_addr.s_addr = INADDR_ANY;

	SerAddr.sin_family = AF_INET;
	SerAddr.sin_port = ::htons(nPort);
	SerAddr.sin_addr.s_addr = ::inet_addr(pszIP);

	if (::bind(s, (sockaddr*)&LocalAddr, nLen) == SOCKET_ERROR)
		goto OPFAILED;

	//连接服务器并发送数据
	bRet = m_pfnConnectEx(s, (sockaddr*)&SerAddr, nLen, (char*)&cmd, sizeof(cmd), &dwSendByte, &ol);
	if (bRet == FALSE)
	{
		if (::WSAGetLastError() != ERROR_IO_PENDING)
			goto OPFAILED;
	}
	
	DWORD dwTime = ::GetTickCount();
	while(::GetTickCount() - dwTime <= 3000)//等待3秒
	{
		bRet = ::WSAGetOverlappedResult(s, &ol, &dwSendByte, FALSE, &dwFlags);
		if (bRet)
			break;
		::Sleep(1);
	}

	//发送的字节数,小于缓冲区长度,失败
	if (dwSendByte < sizeof(cmd))
		goto OPFAILED;

	::ResetEvent(ol.hEvent);

	wsabuf.buf = szRecvbuf;
	wsabuf.len = sizeof(szRecvbuf);
	//发送完就接收
	bRet = ::WSARecv(s, &wsabuf, 1, &dwRecv, &dwFlags, &ol, NULL);
	if (SOCKET_ERROR == bRet && ::WSAGetLastError() != ERROR_IO_PENDING)
		goto OPFAILED;

	dwSendByte = 0;

	dwTime = ::GetTickCount();
	while(::GetTickCount() - dwTime <= 3000)//等待3秒
	{
		bRet = ::WSAGetOverlappedResult(s, &ol, &dwSendByte, FALSE, &dwFlags);
		if (bRet)
			break;
		::Sleep(1);
	}

	if (dwSendByte != 8)
		goto OPFAILED;

	CommunicationCMD* pCmd = (CommunicationCMD*)szRecvbuf;
	////数据接收完毕, 判断是否正常
	if (pCmd->nCmd1 != CMD_CONNECT_TEST &&
		pCmd->nCmd2 != CMD_CONNECT_TEST)
		goto OPFAILED;

	pCmd->nCmd1 = CMD_CONNECT_CLOSE;
	pCmd->nCmd2 = CMD_CONNECT_CLOSE;

	dwSendByte = 0;
	//发送关闭连接命令
	bRet = ::WSASend(s, &wsabuf, 1, &dwSendByte, 0, &ol, NULL);
	if (SOCKET_ERROR == bRet && ::WSAGetLastError() != ERROR_IO_PENDING)
		goto OPFAILED;

	dwTime = ::GetTickCount();
	while(::GetTickCount() - dwTime <= 3000)//等待3秒
	{
		bRet = ::WSAGetOverlappedResult(s, &ol, &dwSendByte, FALSE, &dwFlags);
		if (bRet)
			break;
		::Sleep(1);
	}
	if (dwSendByte != 8)
		goto OPFAILED;

	::CloseHandle(ol.hEvent);
	::closesocket(s);

	return TRUE;

OPFAILED:
	if (s != INVALID_SOCKET)
		::closesocket(s);

	return FALSE;
}
随便写了一个函数, 经测试是可以再次绑定到同一个IP和端口的
我喝多了 2014-08-17
  • 打赏
  • 举报
回复
我closesocket之后, 再新建, 是可以帮定到同一个IP和端口的,不知道你哪里什么问题
oldmtn 2014-08-17
  • 打赏
  • 举报
回复
引用 2 楼 woheduole 的回复:
之前的没释放干净
那如何释放干净?
我喝多了 2014-08-17
  • 打赏
  • 举报
回复
之前的没释放干净
昨夜无风 2014-08-17
  • 打赏
  • 举报
回复
试试 setsockopt( sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on) );

18,356

社区成员

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

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