CSocket

派生自 CAsyncSocket,继承其对 Windows 套接字套接字 API 的封装,并表示比 CAsyncSocket 对象更高级别的抽象。

语法

class CSocket : public CAsyncSocket

成员

公共构造函数

名称 描述
CSocket::CSocket 构造 CSocket 对象。

公共方法

名称 描述
CSocket::Attach SOCKET 句柄附加到 CSocket 对象。
CSocket::CancelBlockingCall 取消当前正在进行的阻塞调用。
CSocket::Create 创建套接字。
CSocket::FromHandle 在给定 SOCKET 句柄的情况下,返回指向 CSocket 对象的指针。
CSocket::IsBlocking 确定阻塞调用是否正在进行中。

受保护方法

名称 描述
CSocket::OnMessagePending 在等待阻塞调用完成时调用以处理挂起的消息。

备注

CSocket 与类 CSocketFileCArchive 一起管理数据的发送和接收。

CSocket 对象还提供阻塞,这对于 CArchive 的同步操作至关重要。 ReceiveSendReceiveFromSendToAccept(均继承自 CAsyncSocket)等阻塞函数不会在 CSocket 中返回 WSAEWOULDBLOCK 错误。 相反,这些函数会等到操作完成。 此外,如果在这些函数之一阻塞时调用 CancelBlockingCall,则原始调用将终止并返回错误 WSAEINTR。

若要使用 CSocket 对象,请调用构造函数,然后调用 Create 以创建基础 SOCKET 句柄(类型 SOCKET)。 Create 的默认参数创建一个流套接字,但如果不使用带有 CArchive 对象的套接字,可以指定一个参数来创建数据报套接字,或者绑定到特定端口以创建服务器套接字。 在客户端使用 Connect 和在服务器端使用 Accept 连接到客户端套接字。 然后创建一个 CSocketFile 对象并将其与 CSocketFile 构造函数中的 CSocket 对象相关联。 接下来,(根据需要)创建一个用于发送数据的 CArchive 对象和一个用于接收数据的对象,然后将它们与 CArchive 构造函数中的 CSocketFile 对象相关联。 通信完成后,销毁 CArchiveCSocketFileCSocket 对象。 Windows 套接字:背景一文中介绍了 SOCKET 数据类型。

当将 CArchiveCSocketFileCSocket 一起使用时,可能会遇到 CSocket::Receive 进入循环(通过 PumpMessages(FD_READ))等待请求的字节数的情况。 这是因为 Windows 套接字只允许每个 FD_READ 通知进行一次 recv 调用,但 CSocketFileCSocket 允许每个 FD_READ 进行多次 recv 调用。 如果在没有要读取的数据时获得 FD_READ,则应用程序挂起。 如果从未收到另一个 FD_READ,应用程序将停止通过套接字进行通信。

可以按如下所示解决此问题。 在 OnReceive 套接字类的方法中,当预期从套接字读取的数据超过一个 TCP 数据包的大小(网络介质的最大传输单元,通常至少为 1096 字节)时,在调用消息类的 Serialize 方法之前调用 CAsyncSocket::IOCtl(FIONREAD, ...)。 如果可用数据的大小小于所需,请等待接收所有数据,然后才启动读取操作。

在以下示例中,m_dwExpected 是用户期望接收的大致字节数。 假设你在代码中的其他位置声明它。

void CChatSocket::OnReceive(int nErrorCode)
{
   CSocket::OnReceive(nErrorCode);

   DWORD dwReceived;

   if (IOCtl(FIONREAD, &dwReceived))
   {
      if (dwReceived >= m_dwExpected) // Process only if you have enough data
         m_pDoc->ProcessPendingRead();
   }
   else
   {
      // Error handling here
   }
}

注意

在静态链接的 MFC 应用程序中的辅助线程中使用 MFC 套接字时,您必须在使用套接字的每个线程中调用 AfxSocketInit 来初始化套接字库。 默认情况下,仅在主线程中调用 AfxSocketInit

有关详细信息,请参阅 MFC 中的 Windows 套接字Windows 套接字:对存档使用套接字Windows 套接字:使用存档的套接字如何工作Windows 套接字:操作序列Windows 套接字:使用存档的套接字示例

继承层次结构

CObject

CAsyncSocket

CSocket

要求

标头afxsock.h

CSocket::Attach

调用此成员函数以将 hSocket 句柄附加到 CSocket 对象。

BOOL Attach(SOCKET hSocket);

参数

hSocket
包含套接字的句柄。

返回值

如果函数运行成功,则为非零。

备注

SOCKET 句柄存储在对象的 m_hSocket 数据成员中。

有关详细信息,请参阅 Windows 套接字:对存档使用套接字

示例

class CSockThread : public CWinThread
{
public:
   SOCKET m_hConnected;

protected:
   CChatSocket m_sConnected;

   // remainder of class declaration omitted.

 

BOOL CSockThread::InitInstance()
{
   // Attach the socket object to the socket handle
   // in the context of this thread.
   m_sConnected.Attach(m_hConnected);
   m_hConnected = NULL;

   return TRUE;
}

 

// This listening socket has been constructed
// in the primary thread.
void CListeningSocket::OnAccept(int nErrorCode)
{
   UNREFERENCED_PARAMETER(nErrorCode);

   // This CSocket object is used just temporarily
   // to accept the incoming connection.
   CSocket sConnected;
   Accept(sConnected);

   // Start the other thread.
   CSockThread *pSockThread = (CSockThread*)AfxBeginThread(
       RUNTIME_CLASS(CSockThread), THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED);
   if (NULL != pSockThread)
   {
      // Detach the newly accepted socket and save
      // the SOCKET handle in our new thread object.
      // After detaching it, it should no longer be
      // used in the context of this thread.
      pSockThread->m_hConnected = sConnected.Detach();
      pSockThread->ResumeThread();
   }
}

CSocket::CancelBlockingCall

调用此成员函数可取消当前正在进行的阻塞调用。

void CancelBlockingCall();

备注

此函数取消此套接字的任何未完成的阻塞操作。 原始阻塞调用将尽快终止并出现错误 WSAEINTR

如果是阻塞 Connect 操作,Windows 套接字实现将尽快终止阻塞调用,但在连接完成或超时前可能无法释放套接字资源(然后重置)。只有当应用程序立即尝试打开一个新的套接字(如果没有可用的套接字)或连接到同一个对等方时,这才可能会引起注意。

取消 Accept 以外的任何操作都可能使套接字处于不确定状态。 如果应用程序取消对套接字的阻塞操作,则应用程序可以依赖的能够对套接字执行的唯一操作是调用 Close,但其他操作在某些 Windows 套接字实现上可能正常工作。 如果希望应用程序具有最大的可移植性,则必须注意不要依赖取消后执行的操作。

有关详细信息,请参阅 Windows 套接字:对存档使用套接字

CSocket::Create

构造套接字对象后调用 Create 成员函数以创建 Windows 套接字并附加它。

BOOL Create(
    UINT nSocketPort = 0,
    int nSocketType = SOCK_STREAM,
    LPCTSTR lpszSocketAddress = NULL);

参数

nSocketPort
要与套接字一起使用的特定端口,如果希望 MFC 选择端口,则为 0。

nSocketType
SOCK_STREAMSOCK_DGRAM

lpszSocketAddress
一个指向字符串的指针,该字符串包含已连接套接字的网络地址(以点分隔的数字,如“128.56.22.8”)。 传递此参数的 NULL 字符串表示 CSocket 实例应侦听所有网络接口上的客户端活动。

返回值

如果函数成功,则为非零值;否则为 0,并且可以通过调用 GetLastError 来检索特定的错误代码。

注解

Create 然后调用 Bind 将套接字绑定到指定地址。 支持以下套接字类型:

  • SOCK_STREAM 提供有序、可靠、双向、基于连接的字节流。 使用 Internet 地址系列的传输控制协议 (TCP)。

  • SOCK_DGRAM 支持数据报,即最大长度固定(通常很小)的无连接、不可靠缓冲区。 对 Internet 地址系列使用用户数据报协议 (UDP)。 要使用此选项,不能将套接字与 CArchive 对象一起使用。

    注意

    Accept 成员函数会引用一个新的空 CSocket 对象作为其参数。 必须先构造此对象,然后才能调用 Accept。 请记住,如果此套接字对象超出范围,则会关闭连接。 请勿为此新的套接字对象调用 Create

有关流和数据报套接字的更多信息,请参阅文章 Windows 套接字:背景Windows 套接字:端口和套接字地址Windows 套接字:对存档使用套接字

CSocket::CSocket

构造 CSocket 对象。

CSocket();

注解

构造后,必须调用 Create 成员函数。

有关详细信息,请参阅 Windows 套接字:对存档使用套接字

CSocket::FromHandle

返回一个指向 CSocket 对象的指针。

static CSocket* PASCAL FromHandle(SOCKET hSocket);

参数

hSocket
包含套接字的句柄。

返回值

指向 CSocket 对象的指针,如果没有附加到 hSocketCSocket 对象,则为 NULL

备注

给定 SOCKET 句柄时,如果未将 CSocket 对象附加到句柄,则成员函数返回 NULL 并且不创建临时对象。

有关详细信息,请参阅 Windows 套接字:对存档使用套接字

CSocket::IsBlocking

调用此成员函数以确定阻塞调用是否正在进行。

BOOL IsBlocking();

返回值

如果套接字为阻塞,则为非零;否则为 0。

备注

有关详细信息,请参阅 Windows 套接字:对存档使用套接字

CSocket::OnMessagePending

重写此成员函数以查找来自 Windows 的特定消息并在套接字中对其进行响应。

virtual BOOL OnMessagePending();

返回值

如果已处理消息,则返回非零值;否则返回 0。

注解

这是一个高级可重写函数。

框架在套接字泵送 Windows 消息时调用 OnMessagePending,让你有机会处理应用程序感兴趣的消息。 有关如何使用 OnMessagePending 的示例,请参阅 Windows 套接字:派生自套接字类一文。

有关详细信息,请参阅 Windows 套接字:对存档使用套接字

另请参阅

CAsyncSocket
层次结构图
CAsyncSocket
CSocketFile