Office中国论坛/Access中国论坛

标题: 请高手帮忙 [打印本页]

作者: 李寻欢    时间: 2002-12-18 22:38
标题: 请高手帮忙
我正在做的远程传送文件程序遇到了一个难题,就是文件读写的问题。
我原来的做法是做一个循环,把文件读到一个字符型变量里,然后传送出去。用这种方式
传送文本文件没有问题,但其它文件都不行,传过去大小不一样。后来我用这种方式把文件读出来写在本地磁盘上,一样的结果,除了文本文件外其它都不成功。
我又换了一种方式,不用字符变量,用字节变量,也就是byte,用这种方式是一个字节一个字节地读,这种方式在本地把文件读出来再写到另一个文件中,完全一样,支持任意类型的文件。但如果用这种方式来传送文件,那不是太慢了吗?谁有解决方法?请帮我一把!
作者: 李寻欢    时间: 2002-12-18 22:47
版主可以帮我置顶吗?
作者: xingzhihao    时间: 2002-12-19 06:16
能否象网络蚂蚁一样多线程?
作者: 李寻欢    时间: 2002-12-19 19:06
用VB可以,而Access甚至连多点连接都不支持。
作者: zhengjialon    时间: 2002-12-19 20:40
ACCESS里也可以用多线程,(API)可是我不知道如何分解程式再同时传。希望有人可以解决。
作者: zhengjialon    时间: 2002-12-19 20:41
"多点连接"是什么?
作者: 李寻欢    时间: 2002-12-19 20:48
就是多个客户端同时连接服务器端。
在VB里可以用Winsock1(0)、Winsock1(1)、Winsock1(2)……来回应每一个客户端的请求,
但在Access里好象不能这样做,只能引用控件名,而不能用控件名的索引来回应。也就是同一时间只能跟一个客户端通讯。
作者: WTM1    时间: 2002-12-19 23:25
用Visual Basic.Net可以创建多线程应用程序!
作者: WTM1    时间: 2002-12-19 23:26
需要相应资料,我可以提供!
作者: 李寻欢    时间: 2002-12-19 23:30
多谢WTM版主
现在还没到考虑多线程的时候,连单线程的文件都不知如何传送,只能传文本文件。
再说也不是要用VB.NET,只是用Access,尽力挖掘Access的潜能。
作者: WTM1    时间: 2002-12-19 23:30
标题: 1
让程序自动管理线程的代码
引言
多线程是一种很好的程序机制,使用线程可以充分的利用电脑资源,进行并行的业务处理。不过好的东西总有它的不足。线程是好,不过滥用,或管理不当就会造成线程混乱,内存漏洞,造成电脑速度变慢,反应迟钝。

想法
于是有人提出能不能让线程自己管理自己,把这复杂的工作交给电脑来处理。笔者经过多年的实践,终于用VC++实现了这一目的。
大家知道在VC++中我们可以用CreateThread创建一个线程,该函数返回这线程的Handle,以后我们就可以用这个Handle来管理这个线程的。于是我们可以做一个类名为ThreadManager,来管理这些Handle,并随时监控这些线程的状态。
总的思想就是这样,不过为了方便使用,我们最好把这个类封装成DLL的形式,这样以后我们在任何程序中都可以很方便的用该类来管理线程了(当然如果你有兴趣,也可以用COM模型来实现)。

实现
因为我们要把一切工作全交给ThreadManager,所以线程的创建,监控,删除都将在该类中实现,而我们仅要做的就是把线程函数名和线程参数传给ThreadManager类,于是我们定义该类构造函数为:

ThreadManager(ThreadPrc threadpro,LPVOID pParam);
该类还要能启动线程,于是我们又定义一个启动函数: RunThread();
另外我们有时还要能获得线程的Handle,于是又定义一个函数: HANDLE GetThreadHandle();
而该类唯一的成员参数就是Handle: HANDLE m_Handle;
于是ThreadManager定义如下: typedef DWORD (WINAPI *ThreadPro)(LPVOID);
class  CThreadManager : public CObject
{
        DECLARE_DYNAMIC( CThreadManager ) 
public:
        CThreadManager( ThreadPrc threadpro, LPVOID pParam);
        ~CThreadManager();
        CBOOL RunThread();
        HANDLE GetThreadHandle() const { return( m_Handle ); };  
private:
        HANDLE m_Handle;
};
显然,我们仅有这一个类还不能完成我们所需的工作,我们还要一个负责具体监控的ThreadTask类,ThreadTask类中有一个监控线程ThreadTaskFunc( )负责监控并删除线程。该类定义如下: class CThreadTask : public CObject
{
DECLARE_DYNAMIC( CThreadTask )
public:
        CThreadTask();  //构造函数
        ~CThreadTask();
        CBOOL IsValid();  
        void AddHandle( CONST HANDLE cHandle );  //添加线程句柄到m_ObList中
         
        void CloseThreadHandles();    //(关闭线程)
        static CThreadTask& GetCThreadTask();    //用于在Managerthread类中获得ThreadTask类的指针

        CObList        m_ObList;//线程句柄组
        HANDLE m_Handle;//线程句柄
         
        BOOL m_bKeepGoing;//是否已运行
};

IMPLEMENT_DYNAMIC( CThreadCareTaker, CObject )
其中IsValid()是用于检验ThreadTaskFunc()是否已动行了,其它意思都很明显。

流程图
总的流程图如下:


具体实现
下面给出它的具体实现。


ThreadTask::ThreadTask()
{
  m_bKeepGoing = TRUE;
  //表示已运行
  DWORD nThreadId = 0;
  //创建管理线程
  m_Handle = (HANDLE)::CreateThread(NULL,0,ThreadTaskpro,0,0,&nThreadId );
}
void ThreadTask::AddHandle( CONST HANDLE cHandle )
{
        CHandle *pHandle = new CHandle;
        pHandle->m_ThreadHandle = cHandle;
        m_ObList.AddTail( pHandle );
         
}
void ThreadTask::CloseThreadHandles()
{
        if ( m_ObList.GetCount() )
        {
                POSITION pos1, pos2;
                CHandle *pHandle = (CHandle *)NULL;  
                //(CHandle类相当简单,只有一个成员函数m_ThreadHandle)
                DWORD dwExitCode = 0L;
                for( pos1=m_ObList.GetHeadPosition(); (pos2=pos1)!=POSITION(NULL); )
                {
                        //历遍所有已有的线程句柄
                        pHandle = DYNAMIC_DOWNCAST( CHandle, m_ObList.GetNext( pos1 ) );
                        //获得第pos1个handle
                        VERIFY( ::GetExitCodeThread( pHandle->m_ThreadHandle, &dwExitCode ) );
                        //获得线程pHandle的当前状态
                        if ( dwExitCode != STILL_ACTIVE )
                        //如果已完成
                        {
                                //释放当前句柄
                                m_ObList.RemoveAt( pos2 );         
                 
                                VERIFY( ::CloseHandle( pHandle->m_ThreadHandle ) );
                                delete pHandle;
                                pHandle = (CHandle *)NULL;
                        }
                }
        }
}

ThreadTask::~ThreadTask()
{

}

ThreadTask & ThreadTask::GetThreadTask()
{
        //返回静态ThreadTask对象,以便ThreadManager类调用
        static ThreadTask  Taker;
        return(Taker);
}

BOOL ThreadTask::IsValid()
{
        //是否已运行
        BOOL bValid_Status = FALSE;
        if ( (this != NULL) && AfxIsValidAddress( this, sizeof( ThreadTask ) ) )
                bValid_Status = TRUE;
        return( bValid_Status );
}

下面介绍线程ThreadTaskpro(); 该线程最主要的目的就是调用ThreadTask的CloseThreadHandles()函数,实现如下: DWORD WINAPI ThreadTaskpro( LPVOID pParam  )
{

        HANDLE hCurrentThread = GetCurrentThread();
        //
作者: WTM1    时间: 2002-12-19 23:38
标题: 1
哈哈哈!!找到了!!使用DAO可以解决!!



    DAO itself is not multithreaded, so you can't use the MFC DAO classes in multiple threads. Confine your DAO code to a single thread of execution. Otherwise, look for some other thread-safe database operations.
    More ideas regarding this question.
    As MFC document stated, the DAO classes are not thread safe. I thought probably finish the coding of your application and have tons of code there already, and don't have enough time to change to another database
    classes. So you really want to use DAO in your multi-thread application, there is a solution for you.
    And you should remember that this is not a true multithread database access, the Jet will serialize the database function calls. In order to operate the database using DAO in different threads, you have to create its own CDaoDatabase and CDaoRecordset instance in each thread.
    1. declare a global instance of critical section
     CCriticalSection g_CS;
    2. In your thread function
     // prevent multi-threads initialize the DAO simultaneously
     // it will be unlocked when out of scope
     CSingleLock lock(&g_CS, TRUE);
     // initialize DAO support of MFC
     AfxDaoInit();
     // initialize your Dao classes here
     CDaoDatabase db;
     CMyDaoRecordset rs( &db );
     // Open the database and recordset
     .....
     lock.Unlock(); // free lock to let other threads use Dao
     ///////////////////////////////////////////
     // your database operation goes here
     // when you doing this, you don't have to lock other threads
     .............................
     ///////////////////////////////////////////
     // After you finish the database operation
     // lock again and close your recordset and database
     lock.Lock();
     rs.Close();
     db.Close();
     return;
    3. In your CApp::ExitInstance(), add these two lines
     AfxDaoInit();
     AfxDaoTerm();
    Hope this will help you.


作者: zhengjialon    时间: 2002-12-20 21:02
解决了吗?
作者: txman    时间: 2002-12-21 11:29
斑竹老是把C语言的东西高上来。
用WINSOCK做二进制传送可以用字节数组,读取文件应该没有问题,当然是一次把文件度出来,对现在的机器来说,发送应该也不会慢。你不是向服务器发送吗?为何不试试INTERNET控件,用FTP不是更方便吗?
作者: 李寻欢    时间: 2002-12-21 17:17
标题: 文件读取已搞定
行家一伸手,就知有没有。
txman兄的一番话,讲得非常有道理,您好象对VB很熟?以后还请多多指教。
二进制读取已做成功了,真的可以读写任意文件,而不仅仅是文本文件,就是用字节数组来读写文件,在本地做得到,当然也可以传送了。源程序在下面:
http://klhome.vicp.net:5700/cdb/viewthread.php?tid=623&sid=b3283d98732d6e3729fdc6bfb868247a
作者: cg1    时间: 2002-12-21 18:30
但如果用这种方式来传送文件,那不是太慢了吗?谁有解决方法?请帮我一把!

-----------------------------------------------------------------------

老兄,你的问题好像根本没有解决啊?用byte复制文件的方法谁都知道(长二进制存储文件到ole字段里面就用的同样方法),但是太慢和断线后无法接着传的毛病一直没有人解决。
作者: 李寻欢    时间: 2002-12-21 18:50
用字节数组就不慢了,数组的大小可以根据网络状况来定,因我以前没想到用数组,只是字节类型,所以我原来说一个字节一个字节地传送太慢了,而用数组的话,可以把文件分成一块一块地传,这样就快多了。
用字节的方式来读文件,断点续传就不是什么大问题了。远程连接的突然断开会触发一些事件,在这些事件里记录已传送的字节数,下一次再从已传送的下一个字节读取就行了。
作者: cg1    时间: 2002-12-21 19:02
奥?请问你的所说的复制是以文件共享方式完成的?
不是以http协议或者ftp协议完成的?
作者: 李寻欢    时间: 2002-12-21 19:21
不是很明白您所说的意思。
文件从一部电脑传送到另一部电脑,其实也是一个复制的过程,这个过程是这样的:
先从传送端读取文件块,通过TCP(远程)或UDP(局域网)协议传送到接受端,直到所有的文件块传送完毕。
作者: cg1    时间: 2002-12-21 19:28
比如说我有一个向www.etang.com申请的免费ftp空间和主页存放空间,能否用你的方法传送文件过去?

不行吧?
作者: 李寻欢    时间: 2002-12-21 19:52
以下是引用cg1在2002-12-21 11:28:16的发言:
比如说我有一个向www.etang.com申请的免费ftp空间和主页存放空间,能否用你的方法传送文件过去?

您所说的应用是要用FTP协议,FTP协议处于TCP/IP模型的第四层:应用层,我所说的TCP、UDP协议在TCP/IP模型的第三层:传输层,FTP协议要传送的文件要通过传输层来传输。所以您当然可以用我所说的方法来传输文件,不过一般都不这么用。因为用我的方法是要自已编写服务器端及客户端,服务器端的端口及地址都可变。而标准的FTP服务器端口是不变的:21,如果想做FTP程序就不用编服务器端了,直接编写一个客户端就可以向网络上的服务器端传送文件了。


[此贴子已经被作者于2002-12-21 11:51:31编辑过]


作者: cg1    时间: 2002-12-21 20:06
奥,看来你对ftp等协议很熟悉,请问你有没有相关的参考资料,我需要编写一个http及ftp的客户端软件(其实已经写完了,但是缺少断点续传),但是一直没有找到关于多线程传输(vba的)和断点续传的资料,

tcp/ip的协议相关资料我没有。
作者: cg1    时间: 2002-12-21 20:13
我的msn号码是 cg1sh@hotmail.com 不知能否与你取得联系,这样一来一往太慢了
作者: 李寻欢    时间: 2002-12-21 20:13
可以买两本书看看:
1、《VB网络与远程控制编程实例教程》出版社:北京希望电子出版社
2、《Visual Basic网络编程从入门到精通》出版社:中国铁道出版社
作者: 李寻欢    时间: 2002-12-21 20:15
我只有QQ:750072
作者: cg1    时间: 2002-12-21 20:48
我没有qq,现申请了一个:190620662




欢迎光临 Office中国论坛/Access中国论坛 (http://www.office-cn.net/) Powered by Discuz! X3.3