简述

TransmitFile是一个扩展的 API,它允许在套接字连接上发送一个打开的文件。这使得应用程序可以避免亲自打开文件,重复地在文件执行读入操作,再将读入的那块数据写入套接字。相反,已打开的文件的句柄和套接字连接一起给出的,在套接字上,文件数据的读入和发送都在模式下进行。这就避免了多次的用户/内核模式切换。与linux的sendfile函数类似。

TransmitFile通过已经连接的SOCKET句柄传输文件,使用操作系统的缓冲管理器来接收数据并提供高质量的文件传输。

https://msdn.microsoft.com/en-us/library/windows/desktop/ms740565(v=vs.85).aspx

参数

  • hSocket

    一个连接的套接字句柄。函数将文件数据写向这个套接字。其必须是面向连接(TCP)的SOCKET。如果hFile为NULL,lpTransmitBuffers将被传输
  • hFile

    已打开的文件句柄。由系统内核读取文件数据,可以通过FILE_FLAG_SEQUENTIAL_SCAN提高处理缓存性能。
  • nNumberOfBytesToWrite

    要传送的字节数。0值表示传送整个文件。发生错误时,以已发送数据为准。
  • nNumberOfBytesPerSend

    每次传送的数据块的大小。0值表示使用SOCKET LAYER的默认值。
  • lpOverlapped

    指向OVERLAPPED结构的指针。如果hSocket以打开重叠(默认),可指定这个参数,以实现一个重叠IO操作(异步)。NULL值表示不开启overlapped(重叠) I/O模式。
  • lpTransmitBuffers

    指向TRANSMIT_FILE_BUFFERS结构指针。NULL值表示仅仅传输文件。

    dwFlags

    用于修改TransmitFile函数调用行为的标识。可以包含下表中的定义(在mswscok.h文件中)
标识 含义
TF_DISCONNECT 在所有文件数据已排队等待传输之后,启动传输层断开连接
TF_REUSE_SOCKET 准备要重复使用的socket句柄。 此标志仅在指定了TF_DISCONNECT时有效。
当TransmitFile请求完成时,套接字句柄可以传递到以前用于建立连接的函数调用,例如AcceptEx或ConnectEx。 这种重用是互斥的; 例如,如果为套接字调用了AcceptEx函数,则仅允许重复使用对AcceptEx函数的后续调用,并且不允许对ConnectEx的后续调用。
注意套接字级文件传输受底层传输的行为的影响。 例如,TCP套接字可能受到TCP TIME_WAIT状态的影响,导致TransmitFile调用被延迟。
TF_USE_DEFAULT_WORKER 指示要使用系统的默认线程来处理长 TransmitFile 请求的 Windows 套接字服务提供程序。可以使用以下注册表参数作为 REG_DWORD 调整系统默认线程︰
HKEY_LOCAL_MACHINE\CurrentControlSet\Services\AFD\Parameters\TransmitWorker
TF_USE_SYSTEM_THREAD 指示Windows Sockets服务提供程序使用系统线程来处理长的TransmitFile请求。
TF_USE_KERNEL_APC 指示驱动程序使用内核异步过程调用(APC)而不是工作线程来处理长的TransmitFile请求。 Long TransmitFile请求定义为需要从文件或缓存中进行多次读取的请求; 因此请求取决于文件的大小和发送数据包的指定长度。
使用TF_USE_KERNEL_APC可以提供显着的性能优势。 然而,可能(虽然不太可能),启动上下文TransmitFile的线程正用于大量计算; 这种情况可能会阻止APC发射。 请注意,Winsock内核模式驱动程序使用正常的内核APC,每当线程处于等待状态时启动,这与用户模式APC不同,每当线程处于用户模式启动的警报等待状态时启动。
TF_WRITE_BEHIND 立即完成TransmitFile请求,无待处理。 如果指定此标志并且TransmitFile成功,则数据已被系统接受,但不一定由远程端确认。 不要在指定TF_DISCONNECT和TF_REUSE_SOCKET标志时使用此设置。

示例代码

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <winsock2.h>
  4. #include <ws2tcpip.h>
  5. #pragma comment(lib,"Ws2_32.lib")
  6. #include <MSWSock.h>
  7. #pragma comment(lib, "Mswsock.lib ")
  8. int main(int c, char** v)
  9. {
  10. if (c != 4) {
  11. printf("用法:%s filename ip port\n", v[0]);
  12. return 0;
  13. }
  14. // 创建并初始化winsock数据变量
  15. WSADATA wsaData = { 0 };
  16. int iResult = 0;
  17. SOCKET hSocket = INVALID_SOCKET;
  18. int iFamily = AF_INET;
  19. int iType = SOCK_STREAM;
  20. int iProtocol = IPPROTO_TCP;
  21. // 初始化 Winsock
  22. iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
  23. if (iResult != 0) {
  24. printf("WSAStartup failed: %d\n", iResult);
  25. return -1;
  26. }
  27. // 打开socket
  28. hSocket = socket(iFamily, iType, iProtocol);
  29. if (hSocket == INVALID_SOCKET) {
  30. printf("socket function failed with error = %d\n", WSAGetLastError());
  31. WSACleanup();
  32. return -2;
  33. }
  34. do {
  35. // 打开文件
  36. HANDLE hFile = CreateFile(v[1], GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL);
  37. if (hFile == INVALID_HANDLE_VALUE){
  38. iResult = -3;
  39. break;
  40. }
  41. // 获取文件大小
  42. //GetFileSize(hFile, NULL);
  43. LARGE_INTEGER liFileSize;
  44. if (GetFileSizeEx(hFile, &liFileSize) == FALSE) {
  45. iResult = -4;
  46. break;
  47. }
  48. // 设置远程段地址
  49. sockaddr_in remoteAddr;
  50. remoteAddr.sin_family = AF_INET;
  51. //remoteAddr.sin_addr.s_addr = inet_addr(v[2]);
  52. inet_pton(AF_INET, v[2], &remoteAddr.sin_addr);
  53. remoteAddr.sin_port = htons(atoi(v[3]));
  54. // 连接到远程端
  55. iResult = connect(hSocket, (SOCKADDR *)& remoteAddr, sizeof(remoteAddr));
  56. if (iResult == SOCKET_ERROR) {
  57. printf("connect function failed with error: %ld\n", WSAGetLastError());
  58. iResult = -5;
  59. break;
  60. }
  61. // 使用TransmitFile发送文件
  62. if (TransmitFile(hSocket, hFile, 0, 0, NULL, NULL, TF_USE_DEFAULT_WORKER) == FALSE) {
  63. printf("TransmitFile function failed with error: %ld\n", WSAGetLastError());
  64. iResult = -6;
  65. break;
  66. }
  67. } while (0);
  68. // 关闭socket
  69. iResult = closesocket(hSocket);
  70. if (iResult == SOCKET_ERROR) {
  71. printf("closesocket failed with error = %d\n", WSAGetLastError());
  72. iResult = -7;
  73. }
  74. // 清理
  75. WSACleanup();
  76. return iResult;
  77. }

TransmitFile函数的简单使用的更多相关文章

  1. Shell函数的简单应用

    Shell函数的简单应用 在脚本内给函数传参: #!/bin/bash . /etc/init.d/functions CheckUrl (){ curl -I -s $ | head - } Che ...

  2. posix 线程(一):线程模型、pthread 系列函数 和 简单多线程服务器端程序

    posix 线程(一):线程模型.pthread 系列函数 和 简单多线程服务器端程序 一.线程有3种模型,分别是N:1用户线程模型,1:1核心线程模型和N:M混合线程模型,posix thread属 ...

  3. c语言中函数的简单介绍

    c语言中函数的介绍: 函数,简单的说就是代码的打包.存放在一个地方,当需要的时候调用. 函数分类: 1.无参无返回值函数 void func() 2.无参有返回值函数  int func() 3.有参 ...

  4. Swift学习之函数和简单地控件的创建

     今天还是重复昨天做的事情--敲代码,但唯一的不同就是所学的知识不同了,我们又进一步往深得层次学习了,感觉越来越有意思了,虽然临近结束了看着大家积极性越来越低了,但是我知道我不能这样,我要比别人付出的 ...

  5. 字符编码知识简介和iconv函数的简单使用

    字符编码知识简介和iconv函数的简单使用 字符编码知识简介 我们知道,在计算机的世界其实只有0和1.期初计算机主要用于科学计算,而我们知道一个数,除了用我们常用对10进制表示,也可以用2进制表示,所 ...

  6. tf.nn.embedding_lookup TensorFlow embedding_lookup 函数最简单实例

    tf.nn.embedding_lookup TensorFlow embedding_lookup 函数最简单实例 #!/usr/bin/env python # -*- coding: utf-8 ...

  7. ffplay.c函数结构简单分析(画图)

    最近重温了一下FFplay的源代码.FFplay是FFmpeg项目提供的播放器示例.尽管FFplay只是一个简单的播放器示例,它的源代码的量也是不少的.之前看代码,主要是集中于某一个"点&q ...

  8. python内置函数的简单使用和介绍

    """内置函数的简单使用和介绍参考链接:https://docs.python.org/3/library/functions.html ""&quo ...

  9. 【JavaScript】使用setInterval()函数作简单的轮询操作

    轮询(Polling)是一种CPU决策怎样提供周边设备服务的方式,又称"程控输出入"(Programmed I/O). 轮询法的概念是.由CPU定时发出询问.依序询问每个周边设备是 ...

随机推荐

  1. 占位符行为 PlaceHolderBehavior 的实现以及使用

    这个效果我不太会描述 PlaceHolder直译占位符 也有人把这个效果叫水印效果 就是和HTML5的PlaceHolder属性一样的效果 上图直观: 使用方法: 首先下载 占位符行为dll.rar  ...

  2. redis学习笔记

    Redis 命令 Redis 命令用于在 redis 服务上执行操作. 要在 redis 服务上执行命令需要一个 redis 客户端.Redis 客户端在我们之前下载的的 redis 的安装包中. 语 ...

  3. Oracle数据库基础知识

    oracle数据库plsql developer   目录(?)[-] 一     SQL基础知识 创建删除数据库 创建删除修改表 添加修改删除列 oracle cascade用法 添加删除约束主键外 ...

  4. 【20161203-20161208】清华集训2016滚粗记&&酱油记&&游记

    先挖坑(这个blog怎么变成游记专用了--) 已更完 #include <cstdio> using namespace std; int main(){ puts("转载请注明 ...

  5. django 补充篇

    from验证 django中的Form一般有两种功能: 输入html-----------不能你自己写一些标签,而帮你自动生成 验证用户输入-------将用户验证信息保存起来,可以传到前端 # !/ ...

  6. BZOJ 4390: [Usaco2015 dec]Max Flow

    4390: [Usaco2015 dec]Max Flow Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 177  Solved: 113[Submi ...

  7. CTRL-Space always toggles Chinese IME (Windows 7、10)

    一.window占用了ctrl+空格的快捷键,影响开发工具的只能提示的使用. 二.解决方式: Go to Start > Type in regedit and start it (打开运行输入 ...

  8. Oracle to_date()函数的用法

    Oracle to_date()函数的用法 to_date()是Oracle数据库函数的代表函数之一,下文对Oracle to_date()函数的几种用法作了详细的介绍说明,供您参考学习. 在Orac ...

  9. 关于MapReduce中自定义分区类(四)

    MapTask类 在MapTask类中找到run函数 if(useNewApi){       runNewMapper(job, splitMetaInfo, umbilical, reporter ...

  10. chrome谷歌浏览器插件制作简易教程

    1.在磁盘上创建一个目录,用来放应用的代码和资源 2.在这个目录中,创建一个文本文件,命名为manifest.json,其内容为: { "manifest_version": 2, ...