学习,c++有2个星期了。本来,本人是做php出身的。做php快2年了,最近身边多了很多高手。让自己对c开始感兴趣了,就开始学习c++了。首先接触的就是mfc。前几天,看到了一个博文,是有关,mfc网络编程的。可对方,的实例只能是多对多,出于兴趣,自己改写了下它的程序,实现了点对点的聊天。所以,本实例并非纯原创的。这个还请大家见谅,尤其是作者。我在他程序基础上,增加了1对1的聊天,同时还保留了群聊。而且,最关键的是,我增加了很多备注。很适合新手学习。。。本人也是新手,还请各位高手提出宝贵建议。。。先谢谢大家了。
如果要转载请注明原地址:http://blog.csdn.net/open520yin/article/details/8222279
实例下载地址:http://download.csdn.net/detail/open520yin/4808903(为了自己能有点下载积分,客户端和服务端一起打包5个积分不算贵吧。。呵呵。。。)
大家要是想看懂这个可能还需要先了解一下mfc的socket的一些基本使用规则我也有一篇博文写了
c++/MFC 极为简单的socket实例:http://blog.csdn.net/open520yin/article/details/8202465
MFC的CSocket编程,利用CSocket实现一个基于TCP实现一个QQ聊天程序。
/ 服务端 start ///
先讲讲服务端,一切先从服务端开始:
首先就是要使用AfxSocketInit初始化winsocket,
//初始化winSock库,成功则返回非0否则返回0
WSAData wsData;
if(!AfxSocketInit(&wsData))
{
AfxMessageBox(_T("Socket 库初始化出错!"));
return false;
}
m_iSocket 是一个 CServerSocket*的 指针 ,CServerSocket类是一个我们自己的类我会在后面给出相应代码,他继承于CSocket类。
//创建服务器端Socket、采用TCP
m_iSocket = new CServerSocket();
if(!m_iSocket)
{
AfxMessageBox(_T("动态创建服务器套接字出错!"));
return false;
}
实例socket好了,就要创建套接字了。。这里的端口要和客户端连接的端口一致,不然就连接不上。而且,这个端口,要和服务器的其他软件端口不能冲突,怎么去判断冲突,可以自己谷歌一下,很简单的。我这里就直接写死了,这个端口一般不会被占用的。。
//端口使用8989
if(!m_iSocket->Create(8989))
{
AfxMessageBox(_T("创建套接字错误!"));
m_iSocket->Close();
return false;
}
创建好了就要,开始监听这个端口了。这个是一般的,socket必须建立的几个过程。。
if(!m_iSocket->Listen())
{
AfxMessageBox(_T("监听失败!"));
m_iSocket->Close();
return false;
}
走完上面的几个步骤,这样,服务端,就能和客户端接受和发送消息了。大家可能会很奇怪,上面那个怎么没有绑定端口,直接listen了。。。这个我那个简单socket里有介绍,因为,Create 方法已经包含了 Bind 方法,如果是以 Create 方法创建socket的前提下不能再调用 Bind ,要不一定出错。
然后重载ExitInstance,退出时对进行清理
int CNetChatServerApp::ExitInstance()
{
if(m_iSocket)
{
delete m_iSocket;
m_iSocket = NULL;
}
return CWinApp::ExitInstance();
}
我再去看看上面用到的CServerSocket类,这个是用来,服务端接收消息用的。开启了监听这里的OnAccept()方法就会一直被循环调用。这个方法其实是重写CSocket类的OnAccept()方法。只要socket开启了监听,OnAccept就会被循环调用,我那个简单的socket实例,是开启一个while进行死循环来达到这个目的。大家不要介意,我也是新手。这里OnAccept方法为什么能一直被循环执行,我到现在也没弄明白,如果有高手知道请告诉我下。但是我知道,这里就是如果服务器有收到消息就会调用这里,提示ClientSocket接受消息。
void CServerSocket::OnAccept(int nErrorCode)
{
//接受到一个连接请求
CClientSocket* theClientSock(0);
//初始化在初始化里把m_listSockets赋值到m_pList里
theClientSock = new CClientSocket(&m_listSockets);
if(!theClientSock)
{
AfxMessageBox(_T("内存不足,客户连接服务器失败!"));
return;
}
Accept(*theClientSock); //接受
//加入list中便于管理,这个很关键
m_listSockets.AddTail(theClientSock);
CSocket::OnAccept(nErrorCode);
}
OnAccept收到消息,就会实例CClientSocket类,这里其实主要是,服务端发送消息和接受消息的主要部分。也是服务端,最核心的部分。OnAccept收到消息后,就会通知CClientSocket来接受消息。注意了,CserverSocket是接收消息而CClientSocket是接收消息。接收,接受还是有区别的。这个关系我们要理解清楚。这个是我自己的理解,不时候是否有错误。还请高手赐教。。我学c++最多不过半个月,有些东西,都真是靠自己的理解。下面的接受消息OnReceive方法怎么调用的,我也有点模糊,这个方法好像是重写Socket的。就有数据来,他就会自动调用。m_listSockets.AddTail(theClientSock);这个很关键,m_listSockets是CPtrList类型,我对这个也还不太了解,经过我一些认识,这个是存放socket连接,成功一个就会加入这个,是一个链表。用来存放所有连接到服务器的socket连接的,这个后面会经常用到。
下面的HEADER是一个结构体,定义如下
typedef struct tagHeader{
int type ;//协议类型
int nContentLen; //将要发送内容的长度
char to_user[20];
char from_user[20];
}HEADER ,*LPHEADER;
这个结构体,要和客户端保持一致,不然我担心会有问题。就算没有问题,我估计转换也麻烦。尽量保持一直吧,这个也算是一种协议吧。客户端传输的时候,也传递这样的结构体。下面的方法,具体就看看备注吧。我在备注里讲解了