⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 jkl.txt

📁 this a c progrmmme ,and under unix programmme
💻 TXT
📖 第 1 页 / 共 5 页
字号:
我本想把发送和接收分开作为两部分,但是最后我决定只略微解释一下 FD_READ ,留下更多的时间来说明更复杂的 FD_WRITE , FD_READ 事件非常容易掌握. 当有数据发送过来时, WinSock 会以 FD_READ 事件通知你, 对于每一个 FD_READ 事件, 你需要像下面这样调用 recv() :

int bytes_recv = recv(wParam, &data, sizeof(data), 0);

基本上就是这样, 别忘了修改上面的 wParam. 还有, 不一定每一次调用 recv() 都会接收到一个完整的数据包, 因为数据可能不会一次性全部发送过来. 所以在开始处理接收到的数据之前, 最好对接收到的字节数 ( 即 recv() 的返回值) 进行判断, 看看是否收到的是一个完整的数据包.

FD_WRITE 相对来说就麻烦一些. 首先, 当你建立了一个连接时, 会产生一个 FD_WRITE 事件. 但是如果你认为在收到 FD_WRITE 时调用 send() 就万事大吉, 那就错了. FD_WRITE 事件只在发送缓冲区有多出的空位, 可以容纳需要发送的数据时才会触发.

上面所谓的发送缓冲区,是指系统底层提供的缓冲区. send() 先将数据写入到发送缓冲区中, 然后通过网络发送到接收端. 你或许会想, 只要不把发送缓冲区填满, 让发送缓冲区保持足够多的空位容纳需要发送的数据, 那么你就会源源不断地收到 FD_WRITE 事件了. 嘿嘿, 错了.上面只是说 FD_WRITE 事件在发送缓冲区有多出的空位时会触发, 但不是在有足够的空位时触发, 就是说你得先把发送缓冲区填满.

通常的办法是在一个无限循环中不断的发送数据, 直到把发送缓冲区填满. 当发送缓冲区被填满后, send() 将会返回 SOCKET_ERROR , WSAGetLastError() 会返回 WSAWOULDBLOCK . 如果当前这个 SOCKET 处于阻塞(同步)模式, 程序会一直等待直到发送缓冲区空出位置然后发送数据; 如果SOCKET是非阻塞(异步)的,那么你就会得到 WSAWOULDBLOCK 错误. 于是只要我们首先循环调用 send() 直到发送缓冲区被填满, 然后当缓冲区空出位置来的时候, 系统就会发出FD_WRITE事件. 有没有想过我能指出这一点来是多么不容易, 你可真走运. 下面是一个处理 FD_WRITE 事件的例子.

case FD_WRITE:  // 可以发送数据了
  {
    // 进入无限循环
    while(TRUE)
    {
      // 从文件中读取数据, 保存到 packet.data 里面.
      in.read((char*)&packet.data, MAX_PACKET_SIZE);

      // 发送数据
      if (send(wparam, (char*)(&packet), sizeof(PACKET), 0) == SOCKET_ERROR)
      {
        if (WSAGetLastError() == WSAEWOULDBLOCK)
        {
          // 发送缓冲区已经满了, 退出循环.
          break;
        }
        else // 其他错误
        {
          // 显示出错信息然后退出.
          CleanUp();
          return(0);
        }
      }
    }
  } break;

看到了吧, 实现其实一点也不困难. 你只是弄混了一些概念而已. 使用这样的发送方式, 在发送缓冲区变满的时候就可以退出循环. 然后, 当缓冲区空出位置来的时候, 系统会触发另外一个 FD_WRITE 事件, 于是你就可以继续发送数据了.

在你开始使用新学到的知识之前, 我还想说明一下 FD_WRITE 事件的使用时机. 如果你不是一次性发送大批量的数据的话, 就别想着使用 FD_WRITE 事件了, 原因很简单 - 如果你寄期望于在收到 FD_WRITE 事件时发送数据, 但是却又不能发送足够的数据填满发送缓冲区, 那么你就只能收到连接刚刚建立时触发的那一次 FD_WRITE - 系统不会触发更多的 FD_WRITE 了. 所以当你只是发送尽可能少的数据的时候, 就忘掉 FD_WRITE 机制吧, 在任何你想发送数据的时候直接调用 send() .

结论
这是我写过的最长的一篇文章. 我也曾试图尽可能把它写短一些来吸引你的注意力, 但是有太多的内容要包括. 在刚刚使用异步 SOCKET 时, 如果你没有正确地理解它, 真的会把自己搞胡涂. 我希望我的文章教会了你如何使用它们. ___________________________________

这是我在 GOOGLE 上搜到的一篇文章中的一部分. 虽然原作者的部分观点似乎并不正确, 但是文章写得很易懂. 其实, 如果你想收到 FD_WRITE  事件而你又无法先填满发送缓冲区, 可以调用 WSAAsyncSelect( ..., FD_WRITE ). 如果当前发送缓冲区有空位, 系统会马上给你发 FD_WRITE 事件.

FD_WRITE 消息, MFC 的 CAsyncSocket 类将其映射为 OnSend() 函数. FD_READ 消息, 被映射为 OnReceive() 函数. 

 
  
++++++++++++++++++++++++++++++++++++++++
第3章  文件传送
3.1  FTP概述
       Internet是一个信息资源的大宝库。一般来说,信息资源都是以文件的形式存放的。因此,在Internet上各主机间传送文件,实现资源共享就成为一个很普遍的要求。文件传输协议(FTP,File Transfer Protocol)就是为了规范主机间文件拷贝服务而制定的一个TCP/IP协议簇应用协议。

       FTP在Internet上使用极为广泛,其数据传输量是Internet上网络流量的主要部分,对一个熟练的Internet用户来说,他几乎离不开FTP。由于FTP的重要性,几乎所有的TCP/IP实现都提供FTP服务。

       FTP是一个客户/服务器系统,和用户直接打交道的是客户程序ftp,它是一个交互式的用户程序,用户通过该程序和远程主机上的ftp服务器相连接,并发出相应指令来实现文件传送。服务器程序在愿意提供FTP服务的主机上运行,一般来说Unix主机上都运行有服务器程序ftpd(ftp daemon),它是一个Unix守护进程。而对DOS和Windows下的TCP/IP实现来说,它们可能不提供FTP服务器程序,即使提供,该程序也不会长期处于运行状态,如果用户要使用PC机作FTP服务器,他必须主动执行TCP/IP实现提供的FTP服务器程序(如ftp公司pctcp 软件包提供的ftpsrv.exe)。

       FTP是一个双向的文件传输协议,一般来说,从远程主机拷贝文件到本地主机叫下载(download)文件,相反的过程,即从本地主机拷贝文件到远程主机叫上载(upload)文件。我们常常使用ftp来从Internet网络下载文件,因为Internet上有许多FTP服务器,它们包含了大量的共享软件(shareware)和自由软件(freeware),这些软件都是免费提供给Internet用户的,我们可以充分利用这些资源为自己的学习和工作服务。

       使用FTP传送文件要求在远程机上有一个帐号,只有当FTP服务器通过用户帐号和口令验证了用户的身份合法后,它才和ftp客户程序建立会话,只有在这时候用户才能进行文件传送。一般来说,一个用户在Internet上可能只有一个帐号,那么他怎么能使用ftp进行文件传送呢?解决个问题的办法是,Internet上有许多FTP服务器提供匿名服务。提供匿名FTP服务的主机上有一个公共的anonymous帐号,它一般要求用户输入自己的电子函件地址作为口令。使用匿名帐号anonymous连接至远程主机后,用户可享有受限权限的操作,一般来说是对某些指定目录的读权限和可能有的特定目录的写权限。有关匿名ftp的详细情况我们将在后面讨论。

 



3.2  ftp的连接与退出
       我们已经知道,使用ftp是为了和远程主机交换文件,在交换文件之前,还必须先和远程主机建立连接,如要从域名为tirc.dcs.tsinghua.edu.cn的计算机上拷贝文件,则可键入下述命令:

$ ftp tirc.dcs.tsinghua.edu.cn

如果我们知道tirc.dcs.tsinghua.edu.cn的IP地址是166.111.80.16,也可以键入下面的命令:

$ ftp 166.111.80.16

这两个命令是等价的,它们都将连接到同一主机。连接建立后,屏幕将提示如下信息请求用户输入帐号:

$ ftp tirc.dcs.tsinghua.edu.cn

Connected to tirc.dcs.tsinghua.edu.cn.

220 tirc FTP server (Version wu-2.4(1) Wed May 10 21:00:32 CDT 1995) ready.

Name (tirc.dcs.tsinghua.edu.cn:jdx):

       第一行告诉我们连接已经建立,并且给出了远程主机的实际全名;第二行内容给出了FTP服务器主机名及FTP服务器软件的版本信息;最后一行提示用户输入帐号,并且它将本地主机上的用户帐号当作默认帐号。如果我们在远程主机上的帐号名相同,则直接键入Enter键即可,否则键入远程机上的帐号及Enter键,这时系统提示:

331 Password required for jdx.

Password:

用户输入自己的口令字并按下Enter键,如果口令正确,则系统提示:

230 User jdx logged in.

ftp>

登录成功,在ftp>提示符后,用户可以输入各种子命令,如设置传输参数,传输文件,或简单地输入quit命令退出ftp系统。

      我们还可以使用另外一种办法来启动ftp程序,即不指定任何主机,只执行ftp命令。在Unix命令提示下简单地键入ftp:

$ ftp

ftp>

程序启动后直接出现ftp>提示符,要求用户输入子命令,这时候,我们可以使用open子命令来和一指定远程主机建立连接:

ftp> open tirc.dcs.tsinghua.edu.cn

这时,用户就可以看到和前面一样的连接登录过程。在用户登录成功后,他可以进行各种文件传送活动。如果用户在结束和远程主机的文件传送后,又想和另外一台远程主机进行文件传送,在这种情况下,他不必退出ftp程序,而只需使用子命令close关闭和远程主机的当前连接,如

ftp>close

221 Goodbye.

ftp>

连接关闭后,用户又可以使用open子命令和另一台远程主机建立连接了。

3.3  使用ftp传送文件
       在启动ftp程序和远程主机建立连接后,用户接下来的主要任务就是文件传送了。ftp程序提供了好几对用于文件传送的子命令,但用户最常用的只有两对:get和put,mget和mput。

       get和mget用于从远程主机上拷贝文件到本地主机(下载),而put和mput正相反,它们将本地主机上文件拷贝到远程主机(上载)。使用get和 put一次只能拷贝一个文件,并且指定的文件名必须是文件全名,而不能有通配符(如*,?等);mget和mput则不同,它们可以用来一次传输一批文件,文件名可以带通配符,但它们不能指定目的文件名。比如有一个实际的例子,我们要从远程主机上拷贝3个文件到本地主机,文件名分别为:file1.txt、fil2.txt和file3.txt,则我们可以使用下面的命令:

ftp> get file1.txt

200 PORT command successful.

150 Opening ASCII mode data connection for file1.txt (81470 bytes).

226 Transfer complete.

83164 bytes received in 0.5335 seconds (152.2 Kbytes/s)

ftp> get file2.txt

200 PORT command successful.

150 Opening ASCII mode data connection for file2.txt (28064 bytes).

226 Transfer complete.

28957 bytes received in 0.4005 seconds (70.61 Kbytes/s)

ftp> get file3.txt

200 PORT command successful.

150 Opening ASCII mode data connection for file3.txt (2416 bytes).

226 Transfer complete.

2511 bytes received in 0.3683 seconds (6.658 Kbytes/s)

另外,我们也可以使用成批传送文件的子命令mget,其用法如下:

ftp> mget file?.txt

get file 'file1.txt' as 'file1.txt'(y/n/q/name)? y

200 PORT command successful.

150 Opening ASCII mode data connection for file1.txt (81470 bytes).

Received 83164 bytes

226 Transfer complete.

Received 83164 bytes in 0.5000 seconds (162.430K / sec)

 

get file 'file2.txt' as 'file2.txt'(y/n/q/name)? y

200 PORT command successful.

150 Opening ASCII mode data connection for file2.txt (28064 bytes).

Received 28957 bytes

226 Transfer complete.

Received 28957 bytes in 0.2200 seconds (128.538K / sec)

 

get file 'file3.txt' as 'file3.txt'(y/n/q/name)? y

200 PORT command successful.

150 Opening ASCII mode data connection for file3.txt (2416 bytes).

Received 2511 bytes

226 Transfer complete.

Received 2511 bytes in 0.0000 seconds (2.452K / sec)

我们看到,ftp程序在传送一个文件之前,都提示用户是否传送该文件,这时,用户有四种选择:

y     ── 或直接键入<Enter>传送该文件,且用源文件名作为目标文件名;

n     ── 不传送该文件,继续下面的传送;

q     ── 结束此次成批文件传送;

name ── 传送该文件,以指定文件名name作为目标文件名。

有时候,我们不希望每个文件传送都要用户确认,而是希望ftp程序一个命令就将所有指定文件传送过来,这时就可用到子命令prompt。prompt是确认提示的触发开关,每执行一次prompt子命令开关值就变反,其默认值是on,即有确认提示,用户可以执行prompt或prompt off来禁止确认提示。同样是上面的文件传送,使用下面的命令:

ftp> prompt

Interactive mode off.

 

ftp> mget *.txt

200 PORT command successful.

150 Opening ASCII mode data connection for file1.txt (81470 bytes).

Received 83164 bytes

226 Transfer complete.

Received 83164 bytes in 0.4400 seconds (184.579K / sec)

200 PORT command successful.

150 Opening ASCII mode data connection for file2.txt (28064 bytes).

Received 28957 bytes

226 Transfer complete.

Received 28957 bytes in 0.2200 seconds (128.538K / sec)

200 PORT command successful.

150 Opening ASCII mode data connection for file3.txt (2416 bytes).

Received 2511 bytes

226 Transfer complete.

Received 2511 bytes in 0.2200 seconds (11.146K / sec)

这种办法传输就比前面效率高多了,尤其是在文件的个数很多时,就更显示出此方法的优越之处了。

       put(mput)的用法与get(mget)很类似,比如说,我们要将本地主机的文件file1.txt拷贝到远程主机,就可以使用下面的命令:

ftp> put file1.txt

200 PORT command successful.

150 Opening ASCII mode data connection for file1.txt.

226 Transfer complete.

83164 bytes sent in 0.1062 seconds (764.5 Kbytes/s)

       我们知道,不论是Unix的文件系统还是DOS的文件系统,它们都是具有目录结构的,因此,在文件传送时经常要通过改变目录、显示目录内容来查找用户需要的文件,这就要用到cd,dir和ls等子命令。

       cd子命令用来改变远程主机的当前工作目录,它的用法和Unix的shell命令cd很类似,比如说,我们要到子目录pub可使用命令:

ftp> cd pub

要回到上层父目录可用命令:

ftp> cd ..


ftp> cdup

如果要想知道远程主机的当前工作目录,可用pwd命令,如:

ftp> pwd

257 "/home/jdx" is current directory.

显示目录内容可用dir和ls命令,两者的差别仅在于dir是长格式显示目录内容,如:

ftp> dir

200 PORT command successful.

150 Opening ASCII mode data connection for /bin/ls.

total 316

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -