<<点对点通信及文件传输软件>>课程设计

这是大一写的课程设计。

 

点对点通信及文件传输软件

一、软件分析

        软件主要功能为通信及文件传输,通信不局限于局域网,文件传输功能适合小文件发送,传输大文件速度较慢。

        软件可以方便的用于校园内(比如宿舍间,宿舍内)的文件传送,这样就解决了xp系统和win7系统的共享难题,也避免了频繁使用U盘对电脑USB接口的损伤。

        软件为点对点式,即每次通信只有两个用户,其中一个为客户端,另一个为服务端,因此也就对应了两个应用程序,分别将其命名为“TcpServer”和“TcpClient”。

二、软件实现方案

1.网络传输协议的选择

        软件要实现通信及文件传输功能,就必然要通过网络传输协议,协议是架于硬件以及操作系统之上的。在此使用了最为广泛应用的TCP/IP协议。

        在TCP/IP协议栈中,有两个高级协议是我们网络应用程序编写者应该了解的,它们是“传输控制协议”(Transmission Control Protocol,简称TCP)和“用户数据报协议”(User Datagrm Protocol,简称UDP)。

        TCP是面向连接的通信协议,TCP提供两台计算机之间的可靠无错的数据传输。应用程序利用TCP进行通信时,源和目标之间会建立一个虚拟连接。这个连接一但建立,两台计算机之间就可以把数据当作一个双向字节流进行交换。

        UDP是无连接通信协议,UDP不保证可靠数据的传输,但能够向若干个目标发送数据,接收发自若干个源的数据。简单地说,如果一个主机向另外一台主机发送数据,这一数据就会立即发出,而不管另外一台主机是否已准备接收数据。如果另外一台主机收到了数据,它不会确认收到与否。

由于此软件为点对点通信,并且为了使两台计算机之间传输的文件数据不会丢失或发生错误,应该采用TCP协议。

2.如何用VC++实现

        在VC++中,针对软件主要功能即网络之间的通信的实现方法有以下两种:(1)使用WinSock  API函数(2)使用MFC提供的类CAsyncSocket或CSocket。

        对于第一种方法,具体实现为服务器端首先要调用socket()函数建立一个流式套接字,再用bind()函数与本机的一个端口建立关联,继续调用listen()函数将套接字置于被动的侦听方式以监听连接,然后调用accept()函数进入等待状态之后才可以接收来自客户端的请求,一旦接收到客户端通过connect()发出的连接请求,accept()将返回一个新的套接字描述符。通过此套接字描述符调用send()或recv()函数即可与客户端进行数据收发。待数据传送完成,服务器客户端调用closesocket()关闭套接字。

        该方法在编程过程工作量大,编程效率低,但却可以加深对网络协议的认识。

        第二种方法,MFC提供了两个类CSocket和CAsyncSocket,他们封装了有关Socket的Windows  API。其中CSocket是CAsyncSocket的子类。CAsyncSocket提供了对API的初步封装,CSocket提供了对API的高度封装。使用这两个类都相对直接使用WinSock API简单了许多。

        默认CSocket是同步的而CAsyncSocket是异步的,因此当调用CSocket的对象的accept等函数时会阻塞主线程,从而使用户界面停止响应,所以需要新建子线程来执行这些操作,编程时发现在不同线程对同一个CSocket对象进行操作时总会发生错误。经过查阅MSDN发现:CSocket并不是线程安全的,不同线程是不能传递MFC的Object的,只能传递Object的handle,因此对同一个CSocket的对象操作只能在同一线程中进行,这样在新线程中就无法对主线程的CSocket对象进行操作。若直接使用WinSock API来进行,同时设置SOCKET为异步模式,就不必为SOCKET新建线程。

2.软件中采用的工具

        通过上面的讨论及对软件编写情况分析决定:(1)通信时在服务端使用WinSock API并将SOCKET的I/O模式设为非阻塞模式,在客户端使用CSocket,这样双方都不会导致主线程阻塞也就不用新建线程。(2)进行文件传输时,双方新建子线程进行,双方各有两个线程函数RecvFile和SendFile,在子线程中使用WinSock API建立SOCKET来传输文件,这样在文件传输的过程中仍然不会影响到双方通信。

        编程环境为Win7+VS2008,客户端和服务端各有两个类。UML图如下:

                TcpClient方

CMySocket

+ OnClose(nErrorCode : int)

+ OnConnect(nErrorCode : int)

+ OnReceive(nErrorCode : int)

 

 

CTcpClientDlg

# m_hIcon : HICON

+ m_ipAddress : CString

+ m_sendPath : CString

+ m_recvPath : CString

+ m_bAgree : bool

+ m_pThread : CwinThread*

+ m_bar : CstatusBarCtrl

+ m_server : SOCKET

+ m_client : SOCKET

+ CtcpClientDlg(pParent : CWnd* = NULL)

+ OnBnClickedExit() : afx_msg

+ OnBnClickedConnect() : afx_msg

+ OnBnClickedClear() : afx_msg

+ OnBnClickedSend() : afx_msg

+ OnBnClickedTransmit() : afx_msg

+ OnBnClickedBrowser() : afx_msg

+ OnOK()

+ CreateAndListen(nPort : int) : BOOL

# OnInitDialog() : BOOL

# OnPaint() : afx_msg

# OnQueryDragIcon() : afx_msg HCURSOR

 

 

 

 

 

 

                                               TcpServer方

CTcpClientDlg

# m_hIcon : HICON

+ m_ipAddress : CString

+ m_sendPath : CString

+ m_recvPath : CString

+ m_bAgree : bool

+ m_pThread : CwinThread*

+ m_bar : CStatusBarCtrl

+ m_client : CMySocket

+ CtcpClientDlg(pParent : CWnd* = NULL)

+ OnBnClickedExit() : afx_msg

+ OnBnClickedStart() : afx_msg

+ OnBnClickedClear() : afx_msg

+ OnBnClickedSend() : afx_msg

+ OnBnClickedTransmit() : afx_msg

+ OnBnClickedBrowser() : afx_msg

+ OnOK()

+ CreateAndConnect(nPort : int,lpAddress : LPCSTR) : BOOL

# OnSocket(wParam : WPARAM,lParam : LPARAM) : afx_msg long

# OnInitDialog() : BOOL

# OnPaint() : afx_msg

# OnQueryDragIcon() : afx_msg HCURSOR

三、具体代码分析

1.基础知识

        在整个代码编写过程中遇到很多问题,经过查阅MSDN以及网上搜寻资料找到解决方案,先列出三个方面,其余写在代码分析中:

        (1)CString.Format的用法说明:在MFC中使用CString来处理字符串是一个很好的选择,CString的Format方法为字符串的转换带来了很大的方便。Format用于转换的格式字符:%c单个字符,%d十进制整数(int),%ld十进制整数(long),%f十进制浮点数(float),%lf十进制浮点数(double),%o八进制数,%s字符串,%u无符号十进制数,%x十六进制数。

        (2)自定义类访问对话框控件:要在自定义的类中访问主对话框空间,须获得主对话的指针。主对话框的对象在app类的InitInstance()方法中声明。查看app类的cpp文件,在InitInstance()方法中有如下语句:

    CAppDlg dlg;

    m_pMainWnd = &dlg;

主对话框指针被传给m_pMainWnd 成员,按f12查看其定义,发现m_pMainWnd 是在afxwin.h中声明的成员:

    CWnd* m_pMainWnd;      

由于MFC中的自定义类会自动包含stdafx.h头文件,且stdafx.h包含afxwin.h,因此根据注释,在自定义类中可以直接使用AfxGetApp()->m_pMainWnd来获取主对话框的指针。之后可通过

    AfxGetApp()->m_pMainWnd()->GetDlgItem(***);

来获得要访问的主对话框控件的CWnd指针,在对该指针进行转化即可。

        (3)解决回车键默认关闭窗口的问题:在一般情况下编写的对话框程序,用户在运行的时候,如果不注意按下了Enter或者ESC键,程序就会立刻退出,之所以会这样,是因为按下Enter键时,Windows就会自动去找输入焦点落在了哪一个按钮上,当获得焦点的按钮的四周将被点线矩形包围。如果所有按钮都没有获得输入焦点,Windows 就会自动去寻找程序或资源所指定的默认按钮(默认按钮边框较粗)。如果对话框没有默认按钮,那么即使对话框中没有OK按钮,OnOK函数也会自动被调用,对于一个普通的对话框程序来说,OnOK函数的调用,以为着程序会立刻退出。为了使Enter键无效,最简单的办法就是将CXXXDlg的OnOK函数写成空函数,然后针对OK按钮写一个新的函数来响应。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值