Socket C++ TCP阻塞 非阻塞总结(3)

2019-05-26 17:31

{

if (Bind(nSocketPort,lpszSocketAddress))

return TRUE;

int nResult = GetLastError();

Close();

WSASetLastError(nResult);

}

return FALSE;

}

其中:

参数1表示本socket的端口,缺省是0,如果要创建数据报的socket,则必须指定一个端口号 。

参数2表示本socket的类型,缺省是SOCK_STREAM,表示面向连接类型。

参数3是屏蔽位,表示希望对本socket监测的事件,缺省是FD_READ | FD_WRITE | FD_OOB | FD_ACCEPT | FD_CONNECT | FD_CLOSE。

参数4表示本socket的IP地址字符串,缺省是NULL。

Create调用Socket函数创建一个socket,并把它捆绑在this所指对象上,监测指定的网络事 件。参数2和3被传递给Socket函数,如果希望创建数据报的socket,不要使用缺省参数,指 定参数2是SOCK_DGRM。

如果上一步骤成功,则调用bind给新的socket分配端口和IP地址。

(2)Socket函数

接着,分析Socket函数,其实现如下:

BOOL CAsyncSocket::Socket(int nSocketType, long lEvent,

int nProtocolType, int nAddressFormat)

{

ASSERT(m_hSocket == INVALID_SOCKET);

m_hSocket = socket(nAddressFormat,nSocketType,nProtocolType);

if (m_hSocket != INVALID_SOCKET)

{

CAsyncSocket::AttachHandle(m_hSocket, this, FALSE);

return AsyncSelect(lEvent);

}

return FALSE;

}

其中:

参数1表示Socket类型,缺省值是SOCK_STREAM。

参数2表示希望监测的网络事件,缺省值同Create,指定了全部事件。

参数3表示使用的协议,缺省是0。实际上,SOCK_STREAM类型的socket使用TCP协议, SOCK_DGRM的socket则使用UDP协议。

参数4表示地址族(地址格式),缺省值是PF_INET(等同于AF_INET)。对于TCP/IP来说, 协议族和地址族是同值的。

在socket没有被创建之前,成员变量m_hSocket是一个无效的socket句柄。Socket函数把协 议族、socket类型、使用的协议等信息传递给WinSock API函数socket,创建一个socket。 如果创建成功,则把它捆绑在this所指对象。

(3)捆绑(Attatch)

捆绑过程类似于其他Windows对象,将在模块线程状态的WinSock映射中添加一对新的映射: this所指对象和新创建的socket对象的映射。

另外,如果本模块线程状态的“socket窗口”没有创建,则创建一个,该窗口

在异步操作时 用来接收WinSock的通知消息,窗口句柄保存到模块线程状态的m_hSocketWindow变量中。函 数AsyncSelect将指定该窗口为网络事件消息的接收窗口。

函数AttachHandle的实现在此不列举了。

(4)指定要监测的网络事件

在捆绑完成之后,调用AsyncSelect指定新创建的socket将监测的网络事件。AsyncSelect实 现如下:

BOOL CAsyncSocket::AsyncSelect(long lEvent)

{

ASSERT(m_hSocket != INVALID_SOCKET);

_AFX_SOCK_THREAD_STATE* pState = _afxSockThreadState;

ASSERT(pState->m_hSocketWindow != NULL);

return WSAAsyncSelect(m_hSocket, pState->m_hSocketWindow,

WM_SOCKET_NOTIFY, lEvent) != SOCKET_ERROR;

}

函数参数lEvent表示希望监视的网络事件。

_ afxSockThreadState得到的是当前的模块线程状态,m_ hSocketWindow是本模块在当前线 程的“socket窗口”,指定监视m_hSocket的网络事件,如指定事件发生,给窗口 m_hSocketWindow发送WM_SOCKET_NOTIFY消息。

被指定的网络事件对应的网络I/O将是异步操作,是非阻塞操作。例如:指定FR_READ导致 Receive是一个异步操作,如果不能立即读到数据,则返回一个错误WSAEWOULDBLOCK。在数 据到达之后,WinSock通知窗口m_hSocketWindow,导致OnReceive被调用。

指定FR_WRITE导致Send是一个异步操作,即使数据没有送出也返回一个错误WSAEWOULDBLOCK 。在数据可以发送之后,WinSock通知窗口m_hSocketWindow,导致OnSend被调用。

指定FR_CONNECT导致Connect是一个异步操作,还没有连接上就返回错误信息 WSAEWOULDBLOCK,在连接完成之后,WinSock通知窗口m_hSocketWindow,导致OnConnect被 调用。

对于其他网络事件,就不一一解释了。

所以,使用CAsyncSocket时,如果使用Create缺省创建socket,则所有网络I/O都是异步操 作,进行有关网络I/O时则必须覆盖以下的相关函数:

OnAccept、OnClose、OnConnect、OnOutOfBandData、OnReceive、OnSend。

(5)Bind函数

经过上述过程,socket创建完毕,下面,调用Bind函数给m_hSocket指定本地端口和IP地址 。Bind的实现如下:

BOOL CAsyncSocket::Bind(UINT nSocketPort, LPCTSTR lpszSocketAddress)

{

USES_CONVERSION;

//使用WinSock的地址结构构造地址信息

SOCKADDR_IN sockAddr;

memset(&sockAddr,0,sizeof(sockAddr));

//得到地址参数的值

LPSTR lpszAscii = T2A((LPTSTR)lpszSocketAddress);

//指定是Internet地址类型

sockAddr.sin_family = AF_INET;

if (lpszAscii == NULL)

//没有指定地址,则自动得到一个本地IP地址

//把32比特的数据从主机字节序转换成网络字节序

sockAddr.sin_addr.s_addr = htonl(INADDR_ANY);

else

{

//得到地址

DWORD lResult = inet_addr(lpszAscii);

if (lResult == INADDR_NONE)

{

WSASetLastError(WSAEINVAL);

return FALSE;

}

sockAddr.sin_addr.s_addr = lResult;

}

//如果端口为0,则WinSock分配一个端口(1024—5000)

//把16比特的数据从主机字节序转换成网络字节序

sockAddr.sin_port = htons((u_short)nSocketPort);

//Bind调用WinSock API函数bind

return Bind((SOCKADDR*)&sockAddr, sizeof(sockAddr));

}

其中:函数参数1指定了端口;参数2指定了一个包含本地地址的字符串,缺省是NULL。

函数Bind首先使用结构SOCKADDR_IN构造地址信息。该结构的域sin_family表示地址格式 (TCP/IP同协议族),赋值为AF_INET(Internet地址格式);域


Socket C++ TCP阻塞 非阻塞总结(3).doc 将本文的Word文档下载到电脑 下载失败或者文档不完整,请联系客服人员解决!

下一篇:带式运输机上的 同轴式二级圆柱齿轮 减速器 之课程设计

相关阅读
本类排行
× 注册会员免费下载(下载后可以自由复制和排版)

马上注册会员

注:下载文档有可能“只有目录或者内容不全”等情况,请下载之前注意辨别,如果您已付费且无法下载或内容有问题,请联系我们协助你处理。
微信: QQ: