一个使用CSocket类的网络通信实例
http://www.cppblog.com/changshoumeng/archive/2010/05/14/115413.html
3.8 一个使用CSocket类的网络通信实例
本例采用CSocket编程模型建立一个聊天程序的简单实例。建立项目时注意选上“Windows套接字”复选框。
3.8.1 服务器端应用程序设计(ServerDemo)
1)界面
各控件属性如下
|
控件类型 |
控件ID |
Caption属性 |
控件变量 |
变量类型 |
|
列表框 |
IDC_Log |
无 |
m_LogCtrl |
CListBox |
|
编辑框 |
IDC_Message |
无 |
m_MsgCtrl |
CEdit |
|
按钮 |
IDC_Send |
发送 |
M_SendCtrl |
CButton |
|
静态控件 |
IDC_STATIC |
记录 |
无 |
无 |
|
静态控件 |
IDC_STATIC |
待发消息 |
无 |
无 |
列表框控件IDC_Log属性“sort”值为false,属性“Horizontal Scroll”值为true。
按钮IDC_Send属性Disable值为true。
2)定义CSocket类的派生类CServSocket和CRecvSocket。
从CSocket编程模型知道,服务器端需要两种套接字,一个用来侦听连接请求,一个用来与请求连接的套接字建立连接。因此,为程序添加两个CSocket派生类:SServSocket和CRecvSocket,它们与对话框类密切配合,共同完成程序所要求实现的功能。
3)建立套接字与对话框类的关联
在程序中,对话框类要用到套接字类,而套接字类在响应某些消息,如在函数OnAccept、OnReceive中进行处理时,也要改变对话框的某些控件状态,以反映给用户这些事情的发生。
这里存在着两个类相互使用的情况,把套接字类对象定义成对话框类的成员变量,同时在套接字类中也把对话框类定义为成员变量。如何实现这样的用法呢?在对话框类头文件中加入套接字头文件的声明,然后在套接字类头文件中加入对话框类头文件的声明,这样的做法显然行不通。
具体做法应该如下:
首先,在ServerDemoDlg.h中加入套接字类头文件的声明,语句#pragma once的后面加入如下语句:
#include "ServSocket.h"
#include "RecvSocket.h"
然后在该文件中为CServerDemoDlg类增加两个公有成员变量,语句如下:
CServSocket *ServSock;
CRecvSocket *RecvSock;
这样在对话框类中就可以使用套接字类了。
继续在套接字类中加入对话框类信息。
首先,在ServSocket.h文件的开头,语句#pragma once的后面加入如下语句:
class CServerDemoDlg;
然后,在该文件中为CServSocket类添加一个公有成员变量和一个构造函数:
CServSocket(CServerDemoDlg *Dlg);
CServerDemoDlg *m_Dlg;
接着在ServSocket.cpp文件中添加新的构造函数的实现,并添加一条关于ServerDemoDlg.h文件的预编译声明,代码如下:
#include “ServerDemoDlg.h”
CServSocket::CServSocket(CServerDemoDlg *Dlg)
{
m_Dlg=Dlg;
}
这样,在套接字类中也可以通过成员变量使用对话框了。
使用同样的方法对CRecvSocket类进行设置,使其也可以通过成员变量使用对话框。
4)为套接字添加串行化读写信息的功能。在服务器端的两个套接字中,只有CRecvSocket套接字是真正与客户端套接字建立连接,发送与接收数据的,因此,我们只为该类添加串行化读写信息功能。在RecvSocket.h文件中为类CRecvSocket添加三个公有成员变量。
CSocketFile *m_File;
CArchive *m_ArIn;
CArchive *m_ArOut;
5)在对话框中初始化套接字并侦听连接请求。在OnInitDialog函数中添加如下代码:
// TODO: 在此添加额外的初始化代码
if(ServSock=new CServSocket(this))
{
if(ServSock->Create (9547))
{
m_LogCtrl.AddString ("等待连接......");
ServSock->Listen ();
}
else
{
m_LogCtrl.AddString ("初始化失败,请重新启动程序!");
delete ServSock;
}
}
else
{
m_LogCtrl.AddString ("初始化失败,请重新启动程序!");
}
上述代码主要是创建并初始化ServSock套接字,并开始侦听连接请求。
6)接受连接请求。由于是CServSocket类的ServSock对象在侦听连接请求,因此由该类来接受连接请求。
首先,在ServSocket.h文件中加入如下语句:
#iinclude “RecvSocket.h”
然后,重载该类的OnAccept函数,在该函数中添加如下代码:
CRecvSocket *tempSock;
if(tempSock=new CRecvSocket(this->m_Dlg ))
{
if(Accept(*tempSock))
{
tempSock->m_File =new CSocketFile(tempSock);
tempSock->m_ArIn =new CArchive(tempSock->m_File ,CArchive::load );
tempSock->m_ArOut =new CArchive(tempSock->m_File ,CArchive::store );
m_Dlg->RecvSock =tempSock;
tempSock=NULL;
m_Dlg->m_LogCtrl .AddString ("连接成功,可以开始传递消息");
m_Dlg->m_SendCtrl.EnableWindow (true);
}
else
{
m_Dlg->m_LogCtrl .AddString ("客户端当前的连接尝试失败");
delete tempSock;
}
}
else
{
m_Dlg->m_LogCtrl .AddString ("连接套接字初始化失败");
}
上述代码首先调用Accept函数接受连接请求,然后为该连接创建一个CRecvSocket类型的套接字,并为该套接字关联CArchive对象,使其能实现串行化传输信息的功能。最后把关联好的套接字传回给对话框对象供其使用。这样,对话框对象的成员变量RecvSock套接字便与客户端套接字之间建立了一条信息通道,信息将在两个套接字之间传递。
7)接收信息,连接建立成功后,当有信息到达服务器端时,就会引发RecvSock套接字对象的OnReceive函数,因此需要重载CRecvSocket类的OnReceive函数。添加代码如下:
CString str;
(*m_ArIn)>>str;
m_Dlg->m_LogCtrl .AddString ("对方发来的信息如下:");
m_Dlg->m_LogCtrl .AddString (str);
m_Dlg->m_LogCtrl .SetCurSel (m_Dlg->m_LogCtrl .GetCount() - 1);
8)发送信息。为对话框“发送”按钮添加事件处理函数OnBnClickedSend(),代码如下:
void CServerDemoDlg::OnBnClickedSend()
{
// TODO: 在此添加控件通知处理程序代码
CString str;
m_MsgCtrl.GetWindowText (str);
if(str.GetLength ()==0)
AfxMessageBox("空信息,所以不发出");
else
{
m_LogCtrl.AddString ("你发出的信息如下:");
m_LogCtrl.AddString (str);
m_LogCtrl.SetCurSel (m_LogCtrl.GetCount ()-1);
*(RecvSock->m_ArOut )<<str;
RecvSock->m_ArOut ->Flush ();
}
}
3.8.2 客户端应用程序设计(项目名称ClientDemo)
1)界面
各控件属性如下
|
控件类型 |
控件ID |
Caption属性 |
控件变量 |
变量类型 |
|
列表框 |
IDC_Log |
无 |
m_LogCtrl |
CListBox |
|
编辑框 |
IDC_Message |
无 |
m_MsgCtrl |
CEdit |
|
按钮 |
IDC_Send |
发送 |
M_SendCtrl |
CButton |
|
静态控件 |
IDC_STATIC |
记录 |
无 |
无 |
|
静态控件 |
IDC_STATIC |
待发消息 |
无 |
无 |
列表框控件IDC_Log属性“sort”值为false,属性“Horizontal Scroll”值为true。
按钮IDC_Send属性Disable值为true。
2)创建套接字类(从CSocket类派生)。客户端只需要一个套接字,命名为CClientSocket。
3)建立对话框类与套接字类的关联。
首先,在ClientDemoDlg.h文件的开头,语句#pragma once后面加入如下语句:
#include “ClientSocket.h”
然后,在该文件中为CClientDemoDlg类添加一个公有成员变量,语句如下:
CClientSocket *ClientSock;
接着,在ClientSocket.h文件的开头,语句#pragma once后面加入如下语句:
class CClientDemoDlg;
然后,在该文件中为CClientSocket类添加一公有成员变量和一个构造函数,语句如下:
CClientSocket(CClientDemoDlg *Dlg);
CClientDemoDlg *m_Dlg;
接着,在ClientSocket.cpp文件中添加新的构造函数的实现代码,并添加一条关于CClientDemoDlg.h文件的预编译声明,代码如下:
#include "ClientDemoDlg.h"
CClientSocket::CClientSocket(CClientDemoDlg *Dlg)
{
m_Dlg=Dlg;
}
这样,便完成了对话框和套接字之间的连接了。
4)为套接字添加串行化读写信息的功能。在ClientSocket.h文件中,为类CClientSocket添加三个公有成员变量,代码如下:
CSocketFile *m_File;
CArchive *m_ArIn;
CArchive *m_ArOut;
5)在对话框中初始化套接字并建立连接
在对话框类的OnInitDialog函数中添加如下代码
// TODO: 在此添加额外的初始化代码
m_LogCtrl.AddString ("正在连接......");
if(ClientSock=new CClientSocket(this))
{
if(ClientSock->Create())
{
if(ClientSock->Connect ("localhost",9547))
{
ClientSock->m_File =new CSocketFile(ClientSock);
ClientSock->m_ArIn =new CArchive(ClientSock->m_File ,CArchive::load );
ClientSock->m_ArOut =new CArchive(ClientSock->m_File,CArchive::store );
m_LogCtrl.AddString ("连接成功,可以开始传递消息");
m_SendCtrl.EnableWindow (true);
}
else
{
m_LogCtrl.AddString ("连接不成功");
delete ClientSock;
}
}
else
{
m_LogCtrl.AddString ("初始化失败,请重新启动程序");
delete ClientSock;
}
}
else
{
m_LogCtrl.AddString ("初始化失败,请重新启动程序");
}
6)接收消息。消息到来时,会引发套接字的OnReceive消息,因此要重载CClientSocket类的OnReceive函数,在其中添加代码如下
// TODO: 在此添加专用代码和/或调用基类
CString str;
m_Dlg->m_LogCtrl .AddString ("对方发来消息如下:");
*m_ArIn>>str;
m_Dlg->m_LogCtrl .AddString (str);
m_Dlg->m_LogCtrl .SetCurSel (m_Dlg->m_LogCtrl .GetCount ()-1);
7)发送信息。为对话框“发送”按钮添加事件处理函数OnBnClickedSend(),代码如下:
void CClientDemoDlg::OnBnClickedSend()
{
// TODO: 在此添加控件通知处理程序代码
CString str;
m_MsgCtrl.GetWindowText (str);
if(str.GetLength ()==0)
AfxMessageBox("空信息,所以不发出");
else
{
m_LogCtrl.AddString ("你发的信息如下:");
m_LogCtrl.AddString (str);
m_LogCtrl.SetCurSel (m_LogCtrl.GetCount ()-1);
*(ClientSock->m_ArOut )<<str;
ClientSock->m_ArOut ->Flush ();
}
}
if(ServSock=new CServSocket(this))
{
if(ServSock->Create (9547))
{
m_LogCtrl.AddString ("等待连接......");
ServSock->Listen ();
}
else
{
m_LogCtrl.AddString ("初始化失败,请重新启动程序!");
delete ServSock;
}
}
create失败,总是跳到else里面去了,请问是什么原因啊?如果方便的话,可以把源程序发我邮箱号码,我自己研究!zqxwce111@163.com
if (!AfxSocketInit())
{
AfxMessageBox(IDP_SOCKETS_INIT_FAILED);
return FALSE;
}
在资源头文件中加入
#define IDP_SOCKETS_INIT_FAILED 104
还要在string table中加入
ID IDP_SOCKETS_INIT_FAILED
Caption Windows 通信端口初始化失败。
一个使用CSocket类的网络通信实例的更多相关文章
- Spring自定义一个拦截器类SomeInterceptor,实现HandlerInterceptor接口及其方法的实例
利用Spring的拦截器可以在处理器Controller方法执行前和后增加逻辑代码,了解拦截器中preHandle.postHandle和afterCompletion方法执行时机. 自定义一个拦截器 ...
- CSocket类网络编程 MFC
Visual C++的MFC提供了CSocket类用来实现网络通信. 下面介绍VC++在Windows 95中实现Socket的 CSocket 类相关成员函数(这些成员函数实际上是从CAsyncSo ...
- Python类的特点 (2) :类属性与实例属性的关系
测试代码: #encoding:utf-8 class Parent(object): x=1 #x是Parent类的属性(字段) ls=[1,2] #ls是一个列表,也是Parent类的属性(字段) ...
- iOS之02-第一个OC的类
OC是一门面向对象的语言,因此它也有类.对象.静态\动态方法.成员变量的概念.这讲就来创建第一个OC的类. 第一个类的源码: /* 人 类名:Person 属性(成员变量\实例变量):体重.年龄 行为 ...
- Python类属性,实例属性
1.Python类数据属性:定义在类里面但在函数外面的变量,它们都是静态的. #一段很简单的代码,但反应了很多 >>> class A(): a=1 #一个类里面有个属性a > ...
- python—类对象和实例对象的区别
最近在对RF的通讯层的模块进行封装,需要将之前放在类似main里面的一个方法,如下所示:这段代码是开发提供,用于接口测试,模拟底层通讯,具体的通讯是在dll内,python这边只是做了个封装让RF进行 ...
- python 类属性和实例属性
class AAA(): aaa = 10 # 情形1 obj1 = AAA() obj2 = AAA() print obj1.aaa, obj2.aaa, AAA.aaa # 情形2 obj1.a ...
- Python:类属性,实例属性,私有属性与静态方法,类方法,实例方法
From: http://www.cnblogs.com/pengsixiong/p/4823473.html 属性分为实例属性与类属性 方法分为普通方法,类方法,静态方法 一:属性: 尽量把需要用户 ...
- 使用DataContractJsonSerializer类将类型实例序列化为JSON字符串和反序列化为实例对象 分类: JSON 前端 2014-11-10 10:20 97人阅读 评论(1) 收藏
一.JSON简介 JSON(JavaScript Object Notation,JavaScript对象表示法)是一种轻量级的数据交换格式. JSON是"名值对"的集合.结构由大 ...
随机推荐
- UVA253 Cube painting(数学)
题目链接. 分析: 用的<训练指南>上的方法.详见P17. 从6个面中选一个做顶面,再从剩下的4个面中选1个做正面,则此正方体唯一确定. 需要枚举共6*4=24种. #include &l ...
- BZOJ 1010 [HNOI2008]玩具装箱toy
1010: [HNOI2008]玩具装箱toy Time Limit: 1 Sec Memory Limit: 162 MBSubmit: 7184 Solved: 2724[Submit][St ...
- 【转】ubuntu打包压缩命令总结
原文网址:http://blog.csdn.net/renero/article/details/6428523 .tar解包:tar xvf FileName.tar打包:tar cvf FileN ...
- Java学习日记-3 Character和字符串
(先说几个小问题 1.在main方法中调用主类的其他方法时,必须先生成主类的对象 2.String s = new String("Hello") 生成了两个对象 3.熟用布尔+f ...
- C - A Simple Problem with Integers - poj 3468(区间更新)
题意:有一个比较长的区间可能是100000.长度, 每个点都有一个值(值还比较大),现在有一些操作,C abc, 把区间a-b内全部加上c, Qab,求区间ab的值. 分析:很明显我们不可能对区间的每 ...
- 微软下一代云环境Web开发框架ASP.NET vNext预览
微软在2014年5月12日的TechEd大会上宣布将会公布下一代ASP.NET框架ASP.NET vNext的预览.此次公布的ASP.NET框架与曾经相比发生了根本性的变化,凸显了微软"云优 ...
- 01标题背包水章 HDU2955——Robberies
原来是dp[i],它代表的不被抓的概率i这最大的钱抢(可能1-100) 客是dp[i]表示抢了i钱最大的不被抓概率,嗯~,弱菜水题都刷不动. 那么状态转移方程就是 dp[i]=max(dp[i],dp ...
- 关于PHP的curl开启问题 (转)
今天在做一个新浪登录功能,新浪提供的PHP SDK里需要用到curl_init()函数,在调试的时候报找不到curl_init()的方法. 经搜索得知需要开启curl的php扩展,那curl又是什么呢 ...
- 【酷Q插件制作】教大家做一个简单的签到插件
酷Q插件已经有很多了,社区分享一大堆,不过还是自己写才有乐趣,哈哈.不得不吐槽一下,酷Q竟然不更新了,出了个酷Q pro,还收费!!诶.不过这也影响不了咱写插件的心情,今天教大家写一个酷Q签到插件,虽 ...
- MySQL(14):Select-limit(限制获得的记录数量)
1. limit 限制获得记录的数量 2.limit 语法: (1) limit offset, row_count: offset偏移量,从0开始. row_count总记录数. 分析: 案例演示 ...