MFC 下使用 CSocket 或者 CAsyncSocket 进行 Socket 通信,CSocket 继承自
CAsyncSocket。这两者的区别在于,CSocket 是同步的 Socket,CAsyncSocket 则是异步的。使用
时,CSocket::Receive()和 CSocket::Send()函数会阻塞当前线程,直至操作完成;而
CAsyncSocket::Receive()和 CAsyncSocket::Send()函数则不阻塞线程,函数立即返回。所以
这两者在使用方式上有所不同。这里探讨一种使用 CSocket 配合 CSocketFile、CArchive 和
CThread 的多线程 C/S 模式。
CSocket 通过 CSocketFile 由 CArchive 管理,可以得到类似 iostream 方式的流输入输出。
这种方式的主要过程有:创建连接、接受数据、发送数据和断开连接。CSocket 必须附加在与其一起工
作的线程上,不能通过其他线程调用,所以主要通过在线程之间的传递消息和加锁实现线程的通信和同
步。我们将分服务端(Server)和客户端(Client)分别讨论具体实现。
服务端
服务端有一个主界面,其类为 CSCEServerDlg,继承自 CDialog,它保存线程池和锁。为了简单
起见,后面的类声明中大部分的成员变量访问控制都是 public。声明类似如下:
typedef list<CWinThread*> PThreadList;
class CSCEServerDlg : public CDialog
{
...
public:
CCriticalSection m_csThrdList; // 线程池锁
PThreadList m_thrdList; // 线程池
int m_thrdIndex; // 线程计数器
CServerSocket m_socketListen // 监听 CSocket
...
};
和 CSocket 一起工作的线程类为 CSerSocketThread,继承自 CWinThread。这里使用
CWinThread 是因为它可以处理消息,这样便于线程间通信。重载了
CWinThread::InitInstance(),在线程建立时做处理,具体实现在后面会有。声明如下:
class CSerSocketThread : public CWinThread
{
DECLARE_DYNCREATE(CSerSocketThread)
public:
CSerSocketThread(void);
~CSerSocketThread(void);
virtual int ExitInstance();
virtual BOOL InitInstance();
int m_thrdIndex;
CSCEServerDlg* m_pSerDlg; // 主界面指针
SOCKET m_hSocket; // Socket 句柄