我有两个socket管理对象,一个监听对象[A]用来监听多个客户端的新连接,一个数据处理对象[B]用来管理socket连接。
1.A监听到新的连接,创建socket,将连接socket传递给B,B将新的socket连接放到一个fd_set结构体中。
2.B对象中一个线程循环对fd_set的副本用select函数进行读操作测试,如果fd_set副本中有socket,并且有数据到来,则select肯定会返回大于零的值,然后就对相应的socket进行数据接收处理。
3.有客户端断开连接后,则从fd_set集合中删除对应的socket。
4.问题出现了,在程序正常运行一段时间后,客户端继续发送数据,select函数的判断结果却是没有数据可读,如果此时用telnet连接一下服务器(忘记连接哪个端口了),则B对象“被激活后”继续接收数据,可读取到已经“堆积”的数据。请各位有经验的、有思路的、有创新的兄弟姐妹们,帮忙分析下到底是怎么回事,为什么数据会阻塞住,我已经无奈了。
1.A监听到新的连接,创建socket,将连接socket传递给B,B将新的socket连接放到一个fd_set结构体中。
2.B对象中一个线程循环对fd_set的副本用select函数进行读操作测试,如果fd_set副本中有socket,并且有数据到来,则select肯定会返回大于零的值,然后就对相应的socket进行数据接收处理。
3.有客户端断开连接后,则从fd_set集合中删除对应的socket。
4.问题出现了,在程序正常运行一段时间后,客户端继续发送数据,select函数的判断结果却是没有数据可读,如果此时用telnet连接一下服务器(忘记连接哪个端口了),则B对象“被激活后”继续接收数据,可读取到已经“堆积”的数据。请各位有经验的、有思路的、有创新的兄弟姐妹们,帮忙分析下到底是怎么回事,为什么数据会阻塞住,我已经无奈了。
解决方案 »
- HTML控件在dll中使用的问题
- 静态文本 视图
- CFileDialog打开文件的奇怪问题
- 关于 TAPI 编程的问题! 请进。。。。
- msflexgrid控件的ADDITEM方法具体怎么用,第二个参数该怎么填,基础不好看不太懂。
- 软件解决硬件问题
- Direct3D与OpenGL相比,各有什么优缺点,适合何种场合?
- 怎么用VARIANT传递long类型数组。
- 各位,知道怎么在程序中用listBox的水平滚动条吗?
- 请高手指教怎么把图像读入数据库,再从数据库里读出图像
- 请问怎样给mainframe中的rebar中的combox增加Ctrl+c和Ctrl+v功能
- 急:MSJET40报错!!VC+ACCESS
没有遇到过,可把相关代码贴出来看看。
//无限期等待套接字满足条件
int nRet = select(0, &readfd, &writefd, NULL, NULL);
if (nRet > 0)
{
//遍历所有套接字集合
for (int i = 0; i < allSockfd.fd_count; i++)
{
//存在可读的套接字
if (FD_ISSET(allSockfd.fd_array[i], &readfd))
{
//接受客户端连接请求
if (allSockfd.fd_array[i] == sListen)//sListen是监听套接字
{
SOCKADDR_IN addrClient;
int nAddrLen = sizeof(addrClient);
SOCKET sClient = accept(sListen, (sockaddr*)&addrClient, &nAddrLen);
//新建一个 CClient类实例
CClient *pClient = new CClient(sClient, pServer);
//加入客户端管理链表中
pServer->AddClient(pClient);
//加入套接字集合
FD_SET(sClient, &allSockfd);
//更新界面信息
pServer->ShowClientNumberInfor(allSockfd.fd_count);
}
else //接收客户端数据
{
//得到CClient类的实例
CClient* pClient = pServer->GetClient(allSockfd.fd_array[i]);
if (pClient != NULL)
{
//接收数据
BOOL bRet = pClient->RecvData();
//接收数据错误或者客户端关闭套接字
if (FALSE == bRet)
{
//取出套接字
SOCKET sTemp = allSockfd.fd_array[i];
//从集合中删除
FD_CLR(allSockfd.fd_array[i], &allSockfd);
//从客户端管理链表中删除该客户端
pServer->DeleteClient(sTemp);
//更新界面信息
pServer->ShowClientNumberInfor(allSockfd.fd_count);
}
}
}//else
}//if
select返回值==0吗?
“如果此时用telnet连接一下服务器(忘记连接哪个端口了),则B对象“被激活后”继续接收数据,可读取到已经“堆积”的数据。”
B对象“被激活后”是什么意思?是不是你的线程在运行一段时间后,哪里堵塞了,所以B对象没有继续接收数据呢?
// 1)初始化一个套节字集合fdSocket,添加监听套节字句柄到这个集合
fd_set fdSocket; // 所有可用套节字集合
FD_ZERO(&fdSocket);
FD_SET(sListen, &fdSocket);
while(TRUE)
{
// 2)将fdSocket集合的一个拷贝fdRead传递给select函数,
// 当有事件发生时,select函数移除fdRead集合中没有未决I/O操作的套节字句柄,然后返回。
fd_set fdRead = fdSocket;
int nRet = ::select(0, &fdRead, NULL, NULL, NULL);
if(nRet > 0)
{
// 3)通过将原来fdSocket集合与select处理过的fdRead集合比较,
// 确定都有哪些套节字有未决I/O,并进一步处理这些I/O。
for(int i=0; i<(int)fdSocket.fd_count; i++)
{
if(FD_ISSET(fdSocket.fd_array[i], &fdRead))
{
if(fdSocket.fd_array[i] == sListen) // (1)监听套节字接收到新连接
{
if(fdSocket.fd_count < FD_SETSIZE)
{
sockaddr_in addrRemote;
int nAddrLen = sizeof(addrRemote);
SOCKET sNew = ::accept(sListen, (SOCKADDR*)&addrRemote, &nAddrLen);
FD_SET(sNew, &fdSocket);
printf("接收到连接(%s)\n", ::inet_ntoa(addrRemote.sin_addr));
}
else
{
printf(" Too much connections! \n");
continue;
}
}
else
{
char szText[256];
int nRecv = ::recv(fdSocket.fd_array[i], szText, strlen(szText), 0);
if(nRecv > 0) // (2)可读
{
szText[nRecv] = '\0';
printf("接收到数据:%s \n", szText);
}
else // (3)连接关闭、重启或者中断
{
::closesocket(fdSocket.fd_array[i]);
FD_CLR(fdSocket.fd_array[i], &fdSocket);
}
}
}
}
}
else
{
printf(" Failed select() \n");
break;
}
}