异步模式的socket在connect之后如何知道connect成功还是失败?

时间:2022-09-14 19:08:36
代码:

BOOL CAMIClient::Create( CString strServerIP,int nPort )
{
Destroy();

m_strServerIP = strServerIP;
m_nPort = nPort;

while( true )
{
// 创建套接字
m_socket = socket(AF_INET,SOCK_STREAM,0);
if( m_socket == INVALID_SOCKET )
break;
// 设置为非阻塞模式
DWORD ul = 1;
if( 0 != ioctlsocket( m_socket, FIONBIO, &ul) ) 
break;
// 创建通知监听线程退出的事件句柄
m_wsaSocketClose = WSACreateEvent();
if( m_wsaSocketClose == WSA_INVALID_EVENT )
break;
// 创建监听线程收到消息的事件句柄
m_wsaSocketEvent = WSACreateEvent();
if( m_wsaSocketEvent == WSA_INVALID_EVENT )
break;
// 将UNICODE的IP地址转换为多字节字符的IP地址
char szServerIP[16] = { 0 };
if( WideCharToMultiByte( CP_ACP,0,m_strServerIP,m_strServerIP.GetLength(),szServerIP,sizeof(szServerIP),NULL,NULL ) == 0 )
break;
// 连接指定的IP地址和端口
SOCKADDR_IN sin;
sin.sin_family = AF_INET;
sin.sin_port = htons(m_nPort);
sin.sin_addr.s_addr = inet_addr( szServerIP );
if( ! ( SOCKET_ERROR == connect( m_socket, (SOCKADDR *)&sin, sizeof(sin)) && WSAGetLastError() == WSAEWOULDBLOCK ) )
break;
// 给监听线程的消息到达事件句柄配置要通知的事件类型
if( WSAEventSelect( m_socket,m_wsaSocketEvent,FD_READ|FD_WRITE|FD_CONNECT|FD_CLOSE ) != 0 )
break;
// 创建消息事件监听线程
DWORD dwThreadId;
m_hThreadSocketEvent = CreateThread( NULL, 0, ThreadProc_SocketEvent, this, 0, &dwThreadId );
if( m_hThreadSocketEvent == NULL )
break;
// 创建定时发送心跳包的事件句柄
m_hEventHeartbeat= CreateEvent( NULL,TRUE,FALSE,NULL );
if( m_hEventHeartbeat == NULL )
break;
// 创建定时发送心跳包的线程
m_hThreadHeartbeat = CreateThread( NULL,0,ThreadProc_Heartbeat,this,0, &dwThreadId );
if( m_hThreadHeartbeat == NULL )
break;
// 全部创建成功,返回TRUE
return TRUE;
}

ShowMessage();

Destroy();

return FALSE;
}
// 下面是接收消息事件的线程:
DWORD WINAPI CAMIClient::ThreadProc_SocketEvent( LPVOID lpParameter)
{
CAMIClient * pThis = ( CAMIClient * )lpParameter;
while( true )
{
WSAEVENT wsaEventAry[2] = { WSA_INVALID_EVENT };
wsaEventAry[0] = pThis->m_wsaSocketClose;
wsaEventAry[1] = pThis->m_wsaSocketEvent;
DWORD dwIndex = WSAWaitForMultipleEvents( 2,wsaEventAry,FALSE,WSA_INFINITE,FALSE );
if( WSA_WAIT_FAILED == dwIndex )
continue;
dwIndex = dwIndex - WSA_WAIT_EVENT_0;
if( dwIndex == 0 )
break;

WSANETWORKEVENTS wsaEvents;
if( 0 != WSAEnumNetworkEvents( pThis->m_socket,pThis->m_wsaSocketEvent,&wsaEvents ) )
continue;
if( wsaEvents.lNetworkEvents & FD_READ )
{
if( wsaEvents.iErrorCode[FD_READ_BIT] == 0 )
{
pThis->OnReceiveData();
}
}
else if( wsaEvents.lNetworkEvents & FD_WRITE )
{
if( wsaEvents.iErrorCode[FD_WRITE_BIT] == 0 )
{
CString s;
}
}
else if( wsaEvents.lNetworkEvents & FD_CONNECT )
{
if( wsaEvents.iErrorCode[FD_CONNECT_BIT] == 0 )
{
CString s;
}
}
else if( wsaEvents.lNetworkEvents & FD_CLOSE )
{
if( wsaEvents.iErrorCode[FD_CLOSE_BIT] == 0 )
{
CString s;
}
}
}
return 0L;
}


我的想法是:用户点击登录时显示一个滚动条,等待登录成功或失败,关键是这个异步里面我怎么知道connect成功了还是失败了呢?没有好办法啊!

7 个解决方案

#1


select啊

#2


用WSAAsyncSelect,看这的例子有:
http://download.csdn.net/detail/geoff08zhang/4571358

#3


select判断读集合,严格点再用getsockopt取SO_ERROR判断

#4


该回复于2013-04-10 16:03:06被管理员删除

#5


1,事件
2,消息
3,回调

#6


     if( WSAEventSelect( m_socket,m_wsaSocketEvent,FD_READ|FD_WRITE|FD_CONNECT

这里关注了m_socket 的FD_CONNECT , wait枚举event时 wsaEvents.lNetworkEvents & FD_CONNECT
就是异步连接成功的消息了. 可能也是连接失败.- -一般我喜欢阻塞连接. 异步模式的socket在connect之后如何知道connect成功还是失败?

#7


已解决,谢谢各位,代码如下:


m_strServerIP = strServerIP;
m_nPort = nPort;

while( true )
{
// 创建套接字
m_socket = socket(AF_INET,SOCK_STREAM,0);
if( m_socket == INVALID_SOCKET )
break;
// 设置为非阻塞模式
DWORD ul = 1;
if( 0 != ioctlsocket( m_socket, FIONBIO, &ul) ) 
break;
// 将UNICODE的IP地址转换为多字节字符的IP地址
char szServerIP[16] = { 0 };
if( WideCharToMultiByte( CP_ACP,0,m_strServerIP,m_strServerIP.GetLength(),szServerIP,sizeof(szServerIP),NULL,NULL ) == 0 )
break;
// 连接指定的IP地址和端口
SOCKADDR_IN sin;
sin.sin_family = AF_INET;
sin.sin_port = htons(m_nPort);
sin.sin_addr.s_addr = inet_addr( szServerIP );
if( ! ( SOCKET_ERROR == connect( m_socket, (SOCKADDR *)&sin, sizeof(sin)) && WSAGetLastError() == WSAEWOULDBLOCK ) )
break;
// 异步connect不会等待就直接返回了,用select的方式来判断connect是否成功,select会阻塞,只到connect连接成功或失败后select才返回
fd_set fs_read;
FD_ZERO( &fs_read );
FD_SET( m_socket,&fs_read );
fd_set fs_write;
fs_write.fd_count = 1;
fs_write.fd_array[0] = m_socket;
fd_set fs_error;
fs_error.fd_count = 1;
fs_error.fd_array[0] = m_socket;
int ret = select( 0,&fs_read,&fs_write,&fs_error,NULL );
if( ret == SOCKET_ERROR )
break;
// 判断socket句柄是否可写
if( !FD_ISSET( m_socket,&fs_write ) )
break;
int optval = -1;
int optlen = sizeof(optval);
ret = getsockopt( m_socket,SOL_SOCKET,SO_ERROR,(char*)(&optval),&optlen );
if( ret != 0 || optval != 0)
break;
// 直到这里connect才是真正成功
// 创建监听线程收到消息的事件句柄
m_wsaEvent = WSACreateEvent();
if( m_wsaEvent == WSA_INVALID_EVENT )
break;
// 给监听线程的消息到达事件句柄配置要通知的事件类型
if( WSAEventSelect( m_socket,m_wsaEvent,FD_READ|FD_WRITE|FD_CONNECT|FD_CLOSE ) != 0 )
break;
// 创建通知监听线程退出的事件句柄
m_wsaClose = WSACreateEvent();
if( m_wsaClose == WSA_INVALID_EVENT )
break;
// 创建消息事件监听线程
DWORD dwThreadId;
m_hThreadEvent = CreateThread( NULL, 0, ThreadProc_SocketEvent, this, 0, &dwThreadId );
if( m_hThreadEvent == NULL )
break;
// 创建定时发送心跳包的事件句柄
m_hEventHeartbeat= CreateEvent( NULL,TRUE,FALSE,NULL );
if( m_hEventHeartbeat == NULL )
break;
// 创建定时发送心跳包的线程
m_hThreadHeartbeat = CreateThread( NULL,0,ThreadProc_Heartbeat,this,0, &dwThreadId );
if( m_hThreadHeartbeat == NULL )
break;
// 全部创建成功,返回TRUE
return TRUE;
}

#1


select啊

#2


用WSAAsyncSelect,看这的例子有:
http://download.csdn.net/detail/geoff08zhang/4571358

#3


select判断读集合,严格点再用getsockopt取SO_ERROR判断

#4


该回复于2013-04-10 16:03:06被管理员删除

#5


1,事件
2,消息
3,回调

#6


     if( WSAEventSelect( m_socket,m_wsaSocketEvent,FD_READ|FD_WRITE|FD_CONNECT

这里关注了m_socket 的FD_CONNECT , wait枚举event时 wsaEvents.lNetworkEvents & FD_CONNECT
就是异步连接成功的消息了. 可能也是连接失败.- -一般我喜欢阻塞连接. 异步模式的socket在connect之后如何知道connect成功还是失败?

#7


已解决,谢谢各位,代码如下:


m_strServerIP = strServerIP;
m_nPort = nPort;

while( true )
{
// 创建套接字
m_socket = socket(AF_INET,SOCK_STREAM,0);
if( m_socket == INVALID_SOCKET )
break;
// 设置为非阻塞模式
DWORD ul = 1;
if( 0 != ioctlsocket( m_socket, FIONBIO, &ul) ) 
break;
// 将UNICODE的IP地址转换为多字节字符的IP地址
char szServerIP[16] = { 0 };
if( WideCharToMultiByte( CP_ACP,0,m_strServerIP,m_strServerIP.GetLength(),szServerIP,sizeof(szServerIP),NULL,NULL ) == 0 )
break;
// 连接指定的IP地址和端口
SOCKADDR_IN sin;
sin.sin_family = AF_INET;
sin.sin_port = htons(m_nPort);
sin.sin_addr.s_addr = inet_addr( szServerIP );
if( ! ( SOCKET_ERROR == connect( m_socket, (SOCKADDR *)&sin, sizeof(sin)) && WSAGetLastError() == WSAEWOULDBLOCK ) )
break;
// 异步connect不会等待就直接返回了,用select的方式来判断connect是否成功,select会阻塞,只到connect连接成功或失败后select才返回
fd_set fs_read;
FD_ZERO( &fs_read );
FD_SET( m_socket,&fs_read );
fd_set fs_write;
fs_write.fd_count = 1;
fs_write.fd_array[0] = m_socket;
fd_set fs_error;
fs_error.fd_count = 1;
fs_error.fd_array[0] = m_socket;
int ret = select( 0,&fs_read,&fs_write,&fs_error,NULL );
if( ret == SOCKET_ERROR )
break;
// 判断socket句柄是否可写
if( !FD_ISSET( m_socket,&fs_write ) )
break;
int optval = -1;
int optlen = sizeof(optval);
ret = getsockopt( m_socket,SOL_SOCKET,SO_ERROR,(char*)(&optval),&optlen );
if( ret != 0 || optval != 0)
break;
// 直到这里connect才是真正成功
// 创建监听线程收到消息的事件句柄
m_wsaEvent = WSACreateEvent();
if( m_wsaEvent == WSA_INVALID_EVENT )
break;
// 给监听线程的消息到达事件句柄配置要通知的事件类型
if( WSAEventSelect( m_socket,m_wsaEvent,FD_READ|FD_WRITE|FD_CONNECT|FD_CLOSE ) != 0 )
break;
// 创建通知监听线程退出的事件句柄
m_wsaClose = WSACreateEvent();
if( m_wsaClose == WSA_INVALID_EVENT )
break;
// 创建消息事件监听线程
DWORD dwThreadId;
m_hThreadEvent = CreateThread( NULL, 0, ThreadProc_SocketEvent, this, 0, &dwThreadId );
if( m_hThreadEvent == NULL )
break;
// 创建定时发送心跳包的事件句柄
m_hEventHeartbeat= CreateEvent( NULL,TRUE,FALSE,NULL );
if( m_hEventHeartbeat == NULL )
break;
// 创建定时发送心跳包的线程
m_hThreadHeartbeat = CreateThread( NULL,0,ThreadProc_Heartbeat,this,0, &dwThreadId );
if( m_hThreadHeartbeat == NULL )
break;
// 全部创建成功,返回TRUE
return TRUE;
}