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
与类 CSocketFile
和 CArchive
一起管理数据的发送和接收。
CSocket
对象还提供阻塞,这对于 CArchive
的同步操作至关重要。 Receive
、Send
、ReceiveFrom
、SendTo
和 Accept
(均继承自 CAsyncSocket
)等阻塞函数不会在 CSocket
中返回 WSAEWOULDBLOCK
错误。 相反,这些函数会等到操作完成。 此外,如果在这些函数之一阻塞时调用 CancelBlockingCall
,则原始调用将终止并返回错误 WSAEINTR。
若要使用 CSocket
对象,请调用构造函数,然后调用 Create
以创建基础 SOCKET
句柄(类型 SOCKET
)。 Create
的默认参数创建一个流套接字,但如果不使用带有 CArchive
对象的套接字,可以指定一个参数来创建数据报套接字,或者绑定到特定端口以创建服务器套接字。 在客户端使用 Connect
和在服务器端使用 Accept
连接到客户端套接字。 然后创建一个 CSocketFile
对象并将其与 CSocketFile
构造函数中的 CSocket
对象相关联。 接下来,(根据需要)创建一个用于发送数据的 CArchive
对象和一个用于接收数据的对象,然后将它们与 CArchive
构造函数中的 CSocketFile
对象相关联。 通信完成后,销毁 CArchive
、CSocketFile
和 CSocket
对象。 Windows 套接字:背景一文中介绍了 SOCKET
数据类型。
当将 CArchive
与 CSocketFile
和 CSocket
一起使用时,可能会遇到 CSocket::Receive
进入循环(通过 PumpMessages(FD_READ)
)等待请求的字节数的情况。 这是因为 Windows 套接字只允许每个 FD_READ
通知进行一次 recv 调用,但 CSocketFile
和 CSocket
允许每个 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 套接字:使用存档的套接字示例。
继承层次结构
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_STREAM
或 SOCK_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
对象的指针,如果没有附加到 hSocket
的 CSocket
对象,则为 NULL
。
备注
给定 SOCKET
句柄时,如果未将 CSocket
对象附加到句柄,则成员函数返回 NULL
并且不创建临时对象。
有关详细信息,请参阅 Windows 套接字:对存档使用套接字。
CSocket::IsBlocking
调用此成员函数以确定阻塞调用是否正在进行。
BOOL IsBlocking();
返回值
如果套接字为阻塞,则为非零;否则为 0。
备注
有关详细信息,请参阅 Windows 套接字:对存档使用套接字。
CSocket::OnMessagePending
重写此成员函数以查找来自 Windows 的特定消息并在套接字中对其进行响应。
virtual BOOL OnMessagePending();
返回值
如果已处理消息,则返回非零值;否则返回 0。
注解
这是一个高级可重写函数。
框架在套接字泵送 Windows 消息时调用 OnMessagePending
,让你有机会处理应用程序感兴趣的消息。 有关如何使用 OnMessagePending
的示例,请参阅 Windows 套接字:派生自套接字类一文。
有关详细信息,请参阅 Windows 套接字:对存档使用套接字。