ImageVerifierCode 换一换
格式:DOCX , 页数:39 ,大小:95.40KB ,
资源ID:5709165      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/5709165.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(基于TCPIP协议的Winsock编程原理.docx)为本站会员(b****5)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

基于TCPIP协议的Winsock编程原理.docx

1、基于TCPIP协议的Winsock编程原理用MFC实现局域网内点对点的大文件传输相信很多人都用过QQ吧?而QQ的里面“传送文件”的功能也应该有不少的人用过吧?而关于实现文件传输的方法也有很多。趁着暑假的空闲时间,我用VC 6.0 + SP5按照自己的思路也写了一个,程序的界面如图1所示。图1先给大家简单介绍一下基本的思路。这个程序所采用的是基于TCP/IP协议的Winsock编程原理,相信如果对这方面的程序设计有所了解的人都应该知道对于这种编程模型一般都是采用客户机/服务器(Client/Server)方式,在这个程序里面也正是采用这种基本的方法。为了方便使用,我把客户机和服务器合而为一,但其

2、实质还是一样的。 在通信的时候主要可以分为两个部分,一个部分是用于传送控制信息,例如发送文件的请求,文件的名称、大小等,由于这方面的数据量比较小,为了方便起见我采用了MFC所提供的CSocket类的串行化技术来实现;而另一个部分就是文件的传输部分,对于文件的传输,由于数据量相对来说比较大,所以我分别写了两个线程,一个用于发送,一个用于接收。这两个部分在具体实现的时候分别建立有自己的套接字(Socket)。下面,就让我为大家演示一下详细的实现步骤。一.建立一个新工程FileTransfers 使用 MFC AppWizard (exe) 建立一个新项目FileTransfers,选择基于对话框的

3、应用,并在向导的第四步中,选择“Windows Socket”选项,如图2所示其它步骤中都使用缺省值,然后按下“Finish”按钮,创建如图3所示属性的工程。图2图3AppWizard将自动创建如下的类。 类名 定义文件 实现文件 CAboutDlg FileTransfers.cpp FileTransfers.cpp CFileTransfersApp FileTransfers.h FileTransfers.cpp CFileTransfersDlg FileTransfersDlg.h FileTransfersDlg.cpp二.修改资源1.修改主对话框风格 修改AppWizard为

4、我们创建的对话框模风格。点击位于Dialog Properties对话框上面的Style标签,然后按照图4设置风格属性。图42.添加控件 按照图1所示在对话框中加入相应的控件。“服务选择”分组框(Group Box)。用于表明其中的两个单选按钮是属于一组的。它的标题(Caption)为“服务选择”,使用默认的ID值就行了。“服务器(S)”和“客户端(C)”单选按钮(Radio Button)。这两个单选按钮定位在“服务选择”分组框(Group Box)中,用于确定软件当前是服务器或是客户端。将“服务器(S)”按钮的ID设置为IDC_RADIO_SERVER,“客户端(C)”按钮的ID设置为ID

5、C_RADIO_CLIENT,其它的属性分别按照图5和图6所示进行设置。图5图6“IP地址”IP地址控件(IP Address)。当软件做为服务器端时,该控件所显示的是本地的IP地址;当软件做为客户端时,用于输入服务器的IP地址。其ID为IDC_IPADDRESS,其余属性采用默认值。“端口号”编辑控件(Edit Box)。用于确定通讯的端口号。所有属性均按照默认值既可。对话框中部分静态文本控件(Text)的属性如下所示。 ID 标题(Caption) 用途 IDC_FILE_NAME FileName 显示当前正在传输的文件名 IDC_FILE_SIZE 0 字节 显示当前正在传输的文件尺寸

6、IDC_RECEIVE_SIZE 0 字节 显示已经发送或接受的文件尺寸先删除对话框中原有的确定按钮,然后再按照图1所示添加和修改按钮的属性,最终对话框中按钮的属性如下所示。 ID 标题(Caption) 用途 IDC_BEGIN 启 动(&B) 启动服务程序/连接到服务器 IDC_DISCONNECT 关 闭(&D) 关闭服务程序/断开和服务器的连接 IDC_SELECT_FILE 选择文件(&F) 选择要发送的文件IDC_STOP_TRANSFERS 停止传输(&T) 停止文件的传输 IDCANCEL 退出(&Q) 退出程序三.几个辅助类的介绍1.CMessage类 在前面我们说过程序传送

7、控制信息的时候采用的是CSocket类的串行化技术,这样一来使得发送和接收网络数据就像普通的数据串行化一样简单。因此封装一个可以串行化的消息类是必要的,后面我们将会看到有了这个类,消息的发送和接收只需使用流操作符对缓冲区进行存取就可以了。根据程序的需要,消息类CMessage的定义如下:class CMessage : public CObjectpublic: void Serialize(CArchive& ar); CMessage(); CMessage(int nType); CMessage(int nType, CString strFileName, DWORD dwFileS

8、ize); virtual CMessage();public: int m_nType; CString m_strFileName; DWORD m_dwFileSize;其中,m_nType用于标识消息的类型;m_strFileName为文件的名称;m_dwFileSize为文件的大小。 为了方便使用,我对消息类的CMessage的构造函数进行了重载,CMessage()为默认的构造函数,如果只是发送一般的控制信息我们可以使用CMessage(int nType)构造函数,当需要发送文件名及大小的时候我们可以使用CMessage(int nType, CString strFileNam

9、e, DWORD dwFileSize)构造函数,三个构造函数的源代码如下:/默认的构造函数CMessage:CMessage() m_nType = -1; m_strFileName = _T(); m_dwFileSize = 0;/只需发送一般的控制信息是使用CMessage:CMessage(int nType) m_nType = nType; m_strFileName = _T(); m_dwFileSize = 0;/需要发送文件名及大小时使用CMessage:CMessage(int nType, CString strFileName, DWORD dwFileSize)

10、 m_nType = nType; m_strFileName = strFileName; m_dwFileSize = dwFileSize; 重载CObject类中的Serialize函数,其源代码如下:void CMessage:Serialize(CArchive &ar) if (ar.IsStoring() ar m_nType; ar m_strFileName; ar m_nType; ar m_strFileName; ar m_dwFileSize; 在写这个类的时候,我们可以使用任何一个文本编(如记事本或是UltraEdit等)辑器进行编写,把类的定义保存在Messag

11、e.h中,把类的实现保存在Message.cpp文件中。要注意的是我们还需要在Message.cpp文件的首部加上#include stdafx.h和#include Message.h两行代码,将stdafx.h文件和Message.h文件包含进来。最后我们还需要把这个类加到工程中,先把Message.h和Message.cpp文件复制到工程目录下,然后在VC中通过Project菜单-Add To Project-Files把这两个文件添加到工程中。2.CListenSocket类 负责监听管理的套接字类CListenSocket。使用ClassView或ClassWizard进行创建,如图

12、7所示。图7 使用ClassView或手工加入如下的函数及成员变量的定义:public: CListenSocket(CFileTransfersDlg* pdlgMain);protected: CFileTransfersDlg* m_pdlgMain; CListenSocket(CFileTransfersDlg* pdlgMain)为重载的构造函数;m_pdlgMain为指向主对话框类CFileTransfersDlg的指针。添加完后我们还需要对类中的两个构造函数的内容进行修改以实现对类的初始化,其源代码如下:CListenSocket:CListenSocket(CFileTran

13、sfersDlg* pdlgMain) m_pdlgMain = pdlgMain;CListenSocket:CListenSocket() m_pdlgMain = NULL; 重载基类的OnAccept函数以使对来自客户的连接请求作出响应,OnAccept函数的源代码如下:void CListenSocket:OnAccept(int nErrorCode) m_pdlgMain-ProcessAccept(); CSocket:OnAccept(nErrorCode); 当该套接字接收到客户的连接请求时,就调用CFileTransfersDlg对象的ProcessAccept()函数进

14、行处理。由于该类中使用到了CFileTransfersDlg类,因此在文件ListenSocket.h的首部还需加入如下头文件的包含语句:#include FileTransfersDlg.h3.CClientSocket类 该类用于连接的管理,其创建的方法与CListenSocket相似,其定义如下:class CClientSocket : public CSocket/ Attributespublic:/ Operationspublic: CClientSocket(); virtual CClientSocket();/ Overridespublic: CSocketFile*

15、m_pFile; CArchive* m_pArchiveIn; CArchive* m_pArchiveOut; void Init(); void Abort(); BOOL SendMsg(CMessage* pMsg); void ReceiveMsg(CMessage* pMsg); CClientSocket(CFileTransfersDlg* pdlgMain); / ClassWizard generated virtual function overrides /AFX_VIRTUAL(CClientSocket) public: virtual void OnReceiv

16、e(int nErrorCode); /AFX_VIRTUAL / Generated message map functions /AFX_MSG(CClientSocket) / NOTE - the ClassWizard will add and remove member functions here. /AFX_MSG/ Implementationprotected: CFileTransfersDlg* m_pdlgMain; 在CClientSocket套接字类封装了串行化功能,这也就是说,该类封装了客户应用程序的大部分功能,因此可以认为该套接字类所管理的就是一个客户应用程序

17、。其中,m_pFile为一个CSocketFile类型的指针用于连接到一个CSocket对象;m_pArchiveIn和m_pArchiveOut均为CArchive类型的指针,分别用于接受和发送。 两个构造函数的源代码如下:CClientSocket:CClientSocket(CFileTransfersDlg* pdlgMain) m_pdlgMain = pdlgMain; m_pFile = NULL; m_pArchiveIn = NULL; m_pArchiveOut = NULL;CClientSocket:CClientSocket() m_pdlgMain = NULL;

18、m_pFile = NULL; m_pArchiveIn = NULL; m_pArchiveOut = NULL; Init成员函数用于串行化的初始化,其源代码如下:void CClientSocket:Init() m_pFile = new CSocketFile(this); m_pArchiveIn = new CArchive(m_pFile,CArchive:load); m_pArchiveOut = new CArchive(m_pFile,CArchive:store); Abort成员函数用于对m_pArchiveOut指针进行释放,其源代码如下:void CClient

19、Socket:Abort() if (m_pArchiveOut != NULL) m_pArchiveOut-Abort(); delete m_pArchiveOut; m_pArchiveOut = NULL; SendMsg成员函数用于发送信息,其源代码如下:BOOL CClientSocket:SendMsg(CMessage *pMsg) if (m_pArchiveOut != NULL) TRY /采用串行化技术进行信息的发送 pMsg-Serialize(*m_pArchiveOut); m_pArchiveOut-Flush(); return TRUE; CATCH(CF

20、ileException, e) m_pArchiveOut-Abort(); delete m_pArchiveOut; m_pArchiveOut = NULL; END_CATCH return FALSE; ReceiveMsg成员函数用于接受信息,其源代码如下:void CClientSocket:ReceiveMsg(CMessage *pMsg) /采用串行化技术进行信息的接收 pMsg-Serialize(*m_pArchiveIn); 重载基类函数OnReceive,使用此函数接受Socket连接另一端发送的信息,其源代码如下:void CClientSocket:OnRec

21、eive(int nErrorCode) m_pdlgMain-ProcessReceive(this); CSocket:OnReceive(nErrorCode); 代码的作用是当有信息发送到时,调用主对话框类的ProcessReceive函数进行信息的接收。由于用到了CMessage和CFileTransfersDlg类,所以在ClientSocket.h文件首部还需加入如下的头文件包含:#include Message.h#include FileTransfersDlg.h四.两个线程 上面所定义的类只实现了控制信息的传送,我们还需要写两个线程_SendThread和_ListenT

22、hread,它们分别用于发送和接收文件。1.发送文件线程UINT _SendThread(LPVOID lparam) CFileTransfersDlg* pDlg = (CFileTransfersDlg*) lparam; /创建套接字 CSocket sockClient; if(!sockClient.Create() pDlg-TransfersFailed(); :MessageBox(HWND)lparam, pDlg-GetError(GetLastError(), _T(错误), MB_ICONHAND|MB_OK); return -1; CString strIPAdd

23、ress; UINT nPort; pDlg-m_psockClient-GetPeerName(strIPAddress, nPort); /连接到服务器端 if(!sockClient.Connect(strIPAddress, pDlg-m_wPort + PORT) pDlg-TransfersFailed(); :MessageBox(HWND)lparam, pDlg-GetError(GetLastError(), _T(错误), MB_ICONHAND|MB_OK); return -1; /调用主对话框类中的SendFile成员函数进行文件的发送 pDlg-SendFile(

24、sockClient); return 0;2.接收文件线程UINT _ListenThread(LPVOID lparam) CFileTransfersDlg* pDlg = (CFileTransfersDlg*)lparam; /创建套接字 CSocket sockSrvr; if(!sockSrvr.Create(pDlg-m_wPort + PORT) pDlg-TransfersFailed(); :MessageBox(HWND)lparam, pDlg-GetError(GetLastError(), _T(错误), MB_ICONHAND|MB_OK); return -1

25、; /开始监听 if(!sockSrvr.Listen() pDlg-TransfersFailed(); :MessageBox(HWND)lparam, pDlg-GetError(GetLastError(), _T(错误), MB_ICONHAND|MB_OK); return -1; /向主对话框发送一个自定义消息WM_ACCEPT_TRANSFERS /发送一个信息告诉发送方可以开始发送文件 pDlg-SendMessage(WM_ACCEPT_TRANSFERS); /接受连接 CSocket recSo; if(!sockSrvr.Accept(recSo) :MessageB

26、ox(HWND)lparam, pDlg-GetError(GetLastError(), _T(错误), MB_ICONHAND|MB_OK); return -1; sockSrvr.Close(); /调用主对话框类中的ReceiveFile成员函数进行文件的接受 pDlg-ReceiveFile(recSo); return 0; 这两个函数只需要放在FileTransfersDlg.cpp文件中,在该文件中还需要加入两个CWinThread*类型的全局变量pThreadListen和pThreadSend用于对线程进行管理。五.在主对话框类内组织程序1.添加成员变量 使用ClassW

27、izard为控件添加成员变量,其对应关系如下所示。 控件ID 变量类型 变量名 IDC_FILE_NAME CString m_strFileName IDC_FILE_SIZE CString m_strFileSize IDC_PORT UINT m_wPort IDC_IPADDRESS CProgressCtrl m_ctrlProgress IDC_RADIO_SERVER int m_nServerType2.添加按钮消息的处理函数 添加按钮消息的处理函数,如下所示。 资源ID 消息类型 函数名称 IDC_RADIO_SERVER BN_CLICKED OnRadioServer

28、IDC_RADIO_CLIENT BN_CLICKED OnRadioClient IDC_BEGIN BN_CLICKED OnBegin IDC_DISCONNECT BN_CLICKED OnDisconnect IDC_SELECT_FILE BN_CLICKED OnSelectFileIDC_STOP_TRANSFERS BN_CLICKED OnStopTransfers IDCANCEL BN_CLICKED OnCancel3.添加WM_TIMER消息控制函数 使用ClassWizard为CFileTransfersDlg类中加一个WM_TIMER消息控制函数。4.加入必要的

29、宏 在定义文件FileTransfersDlg.h的首部加入如下的宏,以增强程序的可读性。#define PORT 1024 /文件传输套接字的端口号#define BLOCKSIZE 1024 /每次要发送或是接受的文家大小#define SERVER 0 /表示当前为服务器端#define CLIENT 1 /表示当前为客户端#define CONNECT_BE_ACCEPT 0x00 /客户端的连接申请被接受#define CONNECT_BE_REFUSE 0x01 /客户端的连接申请被拒绝#define DISCONNECT 0x02 /连接被断开#define REQUEST 0x03 /请求发送文件#define ACCEPT 0x04 /同意发送文件#define REFUSE 0x05 /拒绝发送文件#define CANCEL 0x06 /取消文件的发送5.自定义消息 自定义一个消息WM_ACCEPT_TRANSFERS,用于当文件接收方同意接收文件且文件接收线程_ListenThread已经准备好接收文件是,发送一个信息给文件发送方,说可以开始发送文件。 第一步,我需要在主窗口类CFileTransfersDlg的实现文件FileTransfersDlg.cpp的首部加入一句:#define WM_ACCEPT_TRANSFERS WM_USER + 1

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1