有关SOCKET关闭后的重用问题。。。

tongdings 2003-12-08 03:12:36
在客户端中,一次通信(注:一次通信,指的是从创建->连接->发包->关闭过程)都没问题,问题出在,现在关闭SOCKET,程序不退出,继续创建SOCKET->连接服务器->发送数据,连接、发送均成功,可奇怪的是在recv()时竟然返回0(server端已关闭socket,那现在已经创建好的SOCKET算什么呢??)。

程序主要实现(阻塞,后来改非阻塞也一样):
在连接成功后,创建带有recv()实现的接收线程,监听网络接收,通信后来我是知道server端已经closesocket()的,此时client也closesocket()响应,退出(安全退出)接收线程。

问题提出:为什么第二次通信行不通呢?我在知道server端已经关闭时就已经关掉socket,并且退出接收线程的。望高手指点,分数可以再加,不是问题,
郁闷好了几天…………………………

e-mail: kittyhdb@21cn.com
...全文
537 13 打赏 收藏 转发到动态 举报
写回复
用AI写文章
13 条回复
切换为时间正序
请发表友善的回复…
发表回复
glacierrr 2003-12-09
  • 打赏
  • 举报
回复
好啊
tongdings 2003-12-09
  • 打赏
  • 举报
回复
已经搞定。
faint,原来是应用层上的失误,这个程序本身是没问题的。呵呵 :)
一个很关键的量没设置好,而这个恰巧很容易被忽略。
太累了,折腾了两天……
可以休息一下了.
散分了……
williamxia8 2003-12-09
  • 打赏
  • 举报
回复
好长的内容
tongdings 2003-12-08
  • 打赏
  • 举报
回复
// 接收线程实现
// 接收线程
DWORD WINAPI CClientSocket::RecvThread(LPVOID lParam)
{
if (lParam == NULL) return 1;
CClientSocket* pClientSock = (CClientSocket*)lParam;

fd_set fdRead;
struct timeval tmvTimeout={0L,100L};

while (TRUE)
{
// Always clear the read set before calling select()
FD_ZERO(&fdRead);

// EnterCriticalSection (&pClientSock->m_csSynch);
// add SOCKET m_hSocket to the read set
FD_SET(pClientSock->m_hSocket,&fdRead);

int ret = select(0,&fdRead,NULL,NULL,&tmvTimeout);
if (ret == SOCKET_ERROR)
{
// Error condition
TRACE(_T("Select() Socket error: %d..\n"),GetLastError ());
continue;
}
else if (ret > 0)
{
if (FD_ISSET(pClientSock->m_hSocket,&fdRead))
{
// read data
nRecv = recv (pClientSock->m_hSocket, chRecv, sizeof(chRecv), 0); // Block here
if (nRecv == SOCKET_ERROR)
{
// Socket recv error
TRACE(_T("Recv socket error: %d..\n"),GetLastError());
}
else if (nRecv == 0) // remote socket close
{
TRACE(_T("remote socket closed..\n"));
// close socket and WSACleanup()
pClientSock->m_bConnected = FALSE;
pClientSock->Close ();
TRACE(_T("close client socket..\n"));
// free thread handle
CloseHandle (pClientSock->m_hRecvThread);
pClientSock->m_hRecvThread = NULL;
break;
}

// read socket data to buf and to deal with it
TRACE(_T("Recv %x bytes..\n"),nRecv);
//...
}
}
}
TRACE(_T("Recv thread exit with 0..\n"));
return 0;
}

相关的程序框架大致如上,希望能得到帮助……
附:
class CClientSocket
{
public:
//..
protected:
SOCKET m_hSocket;
//..
};
}
tongdings 2003-12-08
  • 打赏
  • 举报
回复
ok.有点长了代码,贴主要的吧……

//connect
//主要步骤:
//WSAStartup() -> Create Socket -> Connect to server -> Create recv thread
BOOL CClientSocket::Connect(const char* szIPAddr,unsigned short nPort)
{
if (szIPAddr == NULL || nPort < 1024) return FALSE;

WORD wVersion = MAKEWORD(0x02,0x00);
// WSAStartup()..
if (!StartUp(wVersion)) return FALSE;

if (m_hSocket != INVALID_SOCKET)
{
Close ();
}
m_hSocket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if (INVALID_SOCKET == m_hSocket) return FALSE;

SOCKADDR_IN sockAddr;
DWORD dwIP;
dwIP = inet_addr(szIPAddr);
if (dwIP == INADDR_NONE) return FALSE;
sockAddr.sin_family = AF_INET;
sockAddr.sin_port = htons(nPort);
sockAddr.sin_addr.S_un.S_addr = dwIP;

Sleep(500);
int nConnect = connect(m_hSocket,(SOCKADDR *)&sockAddr,sizeof(sockAddr));
if (nConnect == SOCKET_ERROR)
{
DWORD dwErrorCode = GetLastError ();
if (WSAEWOULDBLOCK != dwErrorCode)
{
TRACE(_T("Connect() Socket error: %d..\n"),dwErrorCode);
//WSAEADDRINUSE
if (WSAEISCONN == dwErrorCode)
{
TRACE(_T("connect(): Socket have connected..\n"));
// close socket and WSACleanup()
// Close ();
// SetLastError(0);
// continue;
}
else if (WSAENOTSOCK == dwErrorCode)
{
TRACE(_T("connect(): Not Socket..\n"));
}
return FALSE;
}
else // WSAEWOULDBLOCK is ignored
{
SetLastError(0);
}
}
m_bConnected = TRUE; // connect server successfully
if (m_hRecvThread != NULL) // terminate the old Recv thread
{
TerminateThread (m_hRecvThread,0);
CloseHandle (m_hRecvThread);
m_hRecvThread = NULL;
}
m_hRecvThread = CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE)RecvThread, (LPVOID)this, 0, &m_dwRecvID);
ASSERT(m_hRecvThread != NULL);
TRACE(_T("Create Recv Thread,ID: 0x%x\n"),m_dwRecvID);
return TRUE;
}

// 关闭Socket连接 and WSACleanup()
BOOL CClientSocket::Close ()
{
if (INVALID_SOCKET != m_hSocket)
{
// shutdown(m_hSocket,2);
int iClose = closesocket(m_hSocket);
if (iClose == SOCKET_ERROR)
{
TRACE(_T("closesocket() socket error: %d..\n"),GetLastError ());
}
if (WSACleanup () == SOCKET_ERROR)
{
TRACE(_T("WSACleanup () socket error: %d..\n"),GetLastError ());
}
}
m_hSocket = INVALID_SOCKET;
m_bConnected = FALSE;
return TRUE;
}



seilfer2000 2003-12-08
  • 打赏
  • 举报
回复
不知道怎么回事,按理说应该没什么问题吧。把代码贴上看看
tongdings 2003-12-08
  • 打赏
  • 举报
回复
to madhappy(545454)
server端应该已经做到这点了吧,
server端监听的SOCKET对已被接受的SOCKET才创建吧。
好像不会无缘无故在关闭一个socket后去创建,这样好像不太合理吧。

各位路过的朋友,请发表下高见。要求加分,没问题,
决不含糊阿。。。钱乃身外物阿,有点扯开了,呵呵
tongdings 2003-12-08
  • 打赏
  • 举报
回复
to ISunwu(刀口蒙特)
我都试过了,一个样阿,
大哥,help me……
ISunwu 2003-12-08
  • 打赏
  • 举报
回复
你用的是MFC的CAsyncSocket?
madhappy 2003-12-08
  • 打赏
  • 举报
回复
这个问题我也遇到过!

第一次断开以后服务端的要重新生成对象.
myCsocket::Onclose()
{
m_ServerSocket.close();
m_ServerSocket.create(端口);
...(创建过程)...
}

tongdings 2003-12-08
  • 打赏
  • 举报
回复
to ISunwu(刀口蒙特)
检查了,返回0,无错。
已经知道server端已经关闭了的。
ISunwu 2003-12-08
  • 打赏
  • 举报
回复
同情楼主。
看看closesocket的返回值吧。
tongdings 2003-12-08
  • 打赏
  • 举报
回复
自己先mark it
完成端口通讯服务器(IOCP Socket Server)设计 (六)功能强大的IOCP Socket Servre模块例程源码 Copyright © 2009 代码客(卢益贵)版权所有 QQ:48092788 源码博客:http://blog.csdn.net/guestcode 一、声明 版权声明: 1、通讯模块代码版权归作者所有; 2、未经许可不得全部或部分用于任何项目开发; 3、未经许可不得部分修改后再利用源码。 免责声明: 1、 由于设计缺陷或其它Bug造成的后果,作者不承担责任; 2、未经许可的使用作者不提供任何技术支持服务。 权利和义务: 1、任何获得源码并发现Bug的个人或单位均有义务向作者反映; 2、作者保留追究侵权者法律责任的权利。 二、开发背景 部分代码由前项目分离而来,尚未有应用考验,但对于初学者学习和进阶有很大帮助。性能上尚未有定论,但应该不会令你失望。 三、功能说明 1、可以关闭Socket的Buffer; 2、可以关闭MTU(不等待MTU满才发送); 3、可以多IP或多端口监听; 4、可以重用socket(主动关闭除外); 5、可以0缓冲接收(Socket的Buffe = 0时,避免过多的锁定内存页); 6、可以0缓冲连接(客户端仅连接,不一定立即发数据); 7、可以条件编译: a、是否使用内核Singly-linked lists; b、是否使用处理线程(工作线程和处理线程分开); c、是否使用内核锁来同步链表。 8、可以实现集群服务器模式的通讯(有客户端socket); 9、可以单独设置每个连接的Data项来实现连接和Usernfo的关联; 10、每个线程有OnBegin和OnEnd,用于设置线程独立的对象(数据库会话对象); 11、可以提供详细的运行情况,便于了解IOCP下的机制,以及进行调试分析; 12、可以发起巨量连接和数据(需要硬件配置来支持)。
1. 连接oracle时,目录中不能有()字符,否则ADO是无法连接数据库的 修改: 2.1 去掉TCPChannel的BuildPacket函数,改成直接由OnRecv回调函数返回实际数据 去掉UDPChannel的Response函数,改成直接由内部处理 2.2 修改TCPChannel类,实现同步调用接口 定义IRPC接口用来处理同步调用的被调用端 定义Bind函数用来绑定IRPC接口的实例 定义CallEx函数用来实现用户同步调用 2.3 添加bInit变量,用于设置初始化和关闭状态。 设置此变量的目的主要是用来控制,在关闭socket之后,后续的任何投递都不执行。 修改了IRPC接口名称为IRemoteProcCall,并且调整了部分结构体名称,如RPC相关的结构体, 组合包相关的结构体,以及P2P相关的结构体。 修改TCPChannel类的接口函数Bind成BindEx,使之与TCPChannel的其他接口统一命名。 修改测试Demo,添加多发选项 修改DataType.h中的内存块大小定义 封装临界区类,信号量类 修改TCPListener接口类中的EnumSockets接口,添加pArg参数 Socket类添加ReUseAddr函数,用来设置端口重用 TCPSocket接口类添加GetListener接口用来获得链接管理对象 修改Demo实例中的TCP客户端部分,增加可更改客户端连接数 2.4 添加UDT支持 修改UDPChannel接口类,添加UDT支持接口函数 添加日志支持 添加接口类ILogger,用来实现对日志的输出 添加x64的编译环境 添加部分WARN级别的日志输出 添加C接口,方便非C++语言应用 UDT添加特性,关闭UDT时,给对端发送断线信息,通知对端断线 UDT提高效率,UDT句柄部分改用读写锁来控制,以提高效率 修改OnSend和OnSendTo的行为 修改过的BUG: 1. 数据发送时,如果数据大小正好是MAX_PACKET_SIZE个字节的话,数据发送不出去,在计算包大小时,边界值没处理好。 2. IOCPUnhandledException函数内部逻辑错误,没有关联到自己的异常处理函数中,导致即使调用成功,程序异常了,也无法写dump文件。 3. 修复IOCP UDP Release模式下不能正常运行的BUG。由于传递的输出参数使用了局部变量导致的问题 4. 修复UDT发送时,计算尾包大小错误 5. 修复UDT快速发送错误 6. 修改Queue关闭时,如果有线程正在等待信号,会导致线程死等

18,356

社区成员

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

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