具体代码见
http://download.csdn.net/detail/qwertyuj/5233800
是从别人例子上略加修改。
server 端:
建个类作为server socket,主要处理OnAccept消息。
class CMySocket : public CAsyncSocket
其中包含几个虚函数
virtual void OnAccept(int nErrorCode);
virtual void OnConnect(int nErrorCode);
virtual void OnReceive(int nErrorCode);
建立类代表client socket,每个client的连接都有一个此类的一个实例。
主要处理此连接的OnConnect、OnReceive和OnClose消息。
class CClientSock : public CAsyncSocket
其中包含几个虚函数
virtual void OnConnect(int nErrorCode);
virtual void OnReceive(int nErrorCode);
virtual void OnClose(int nErrorCode);
初始化
AfxSocketInit()
建变量
CMySocket m_Svr
建立
m_Svr.Create(atoi(strPort),SOCK_STREAM,FD_READ | FD_WRITE | FD_OOB | FD_ACCEPT | FD_CONNECT | FD_CLOSE))
监听
m_Svr.Listen()
有client连接进来后,就建立一个代表此连接的实例。
CClientSock* pNewConn = new CClientSock;
并通过Accept()导入此连接的实例。
m_Svr.Accept(*pNewConn);
获取此client的ip和端口
pNewConn->GetPeerName(strip,nPort);
若连接发来数据,则CClientSock中的OnReceive()被调用,使用Receive()函数
从缓冲区中取出数据。
若要发送数据,用CClientSock中的Send()进行发送。
当客户端断开socket,则server端的CClientSock中的OnClose()会被调用,
可以在主框架中析构CClientSock代表此连接的实例。
关闭server端的socket使用CMySocket继承来的的Close()函数。
client端:
只需建立一个类,而不像server端要给自身建立一个类,还要为连接建立一个类。
class CClientSock : public CAsyncSocket
其中包含几个虚函数
virtual void OnClose(int nErrorCode);
virtual void OnConnect(int nErrorCode);
virtual void OnReceive(int nErrorCode);
初始化
AfxSocketInit()
建变量
CClientSock m_Conn;
连接server端
先使用m_Conn.Create()建立socket,然后再m_Conn.Connect("127.0.0.1",6100)连接到server。
连接成功后,CClientSock 的OnConnect()函数会被调用。
发送数据使用
m_Conn.Send(SendBuf,strlen(SendBuf));
收到数据后CClientSock 的OnReceive()函数会被调用,
使用m_Conn.Receive(szRcv,200)进行接收。
断开连接使用m_Conn.Close()函数。
若是server端先主动断开的连接,则CClientSock 的OnClose()函数会被调用,
来通知client连接断开。
以上只是大体介绍,具体还是需要参考MSDN上对CAsyncSocket类的说明。
网上找的对CAsyncSocket的一段说明:
CAsyncSocket是一个异步非阻塞Socket封装类,CAsyncSocket::Create()有一个参数指明了你想要处理哪些Socket事件,你关心的事件被指定以后,这个Socket默认就被用作了异
步方式。
CAsyncSocket的Create()函数,除了创建了一个SOCKET以外,还创建了个CSocketWnd窗口对象,并使用WSAAsyncSelect()将这个SOCKET与该窗口对象关联,以让该窗口对象处理来
自Socket的事件(消息),然而CSocketWnd收到Socket事件之后,只是简单地回调CAsyncSocket::OnReceive()等虚函数。所以CAsyncSocket的派生类,只需要在这些虚函数里添加发
送和接收的代码。
然而,最不容易被初学Socket编程的人理解的,也是本文最要提醒的一点是,客户方在使用CAsyncSocket::Connect()时,往往返回一个WSAEWOULDBLOCK的错误(其它的某些函数调
用也如此),实际上这不应该算作一个错误,它是Socket提醒我们,由于你使用了非阻塞Socket方式,所以(连接)操作需要时间,不能瞬间建立。既然如此,我们可以等待呀,等它
连接成功为止,于是许多程序员就在调用Connect()之后,Sleep(0),然后不停地用WSAGetLastError()或者CAsyncSocket::GetLastError()查看Socket返回的错误,直到返回成功
为止。这是一种错误的做法,断言,你不能达到预期目的。事实上,我们可以在Connect()调用之后等待CAsyncSocket::OnConnect()事件被触发,CAsyncSocket::OnConnect()是要
表明Socket要么连接成功了,要么连接彻底失败了。至此,我们在CAsyncSocket::OnConnect()被调用之后就知道是否Socket连接成功了,还是失败了。
类似的,Send()如果返回WSAEWOULDBLOCK错误,我们在OnSend()处等待,Receive()如果返回WSAEWOULDBLOCK错误,我们在OnReceive()处等待,以此类推。
还有一点,也许是个难点,那就是在客户方调用Connect()连接服务方,那么服务方如何Accept(),以建立连接的问题。简单的做法就是在监听的Socket收到OnAccept()时,用一个
新的CAsyncSocket对象去建立连接,例如:
void CMySocket::OnAccept( int ErrCode )
{
CMySocket* pSocket = new CMySocket;
Accept( *pSocket );
}
于是,上面的pSocket和客户方建立了连接,以后的通信就是这个pSocket对象去和客户方进行,而监听的Socket仍然继续在监听,一旦又有一个客户方要连接服务方,则上面的
OnAccept()又会被调用一次。当然pSocket是和客户方通信的服务方,它不会触发OnAccept()事件,因为它不是监听Socket。
CAsyncsocket好处CAsyncSocket类为我们使用Socket提供了极大方便。建立Socket的WSAStartup过程和bind过程被简化成为Create过程,IP地址类型转换、主机名和IP地址转换的
过程中许多复杂的变量类型都被简化成字符串和整数操作,特别是CAsyncSocket类的异步特点,完全可以替代繁琐的线程操作。MFC提供了大量的类库,我们若能灵活的使用他们,
便会大大提高编程的效率。