Передача файлов с помощью TransmitFile. Функция TransmitFile служит для быстрой передачи данных из файлов, благодаря тому, что она работает в режиме ядра(kernel mode), и не происходят частые переключения между режимами. Данная функция это дополнение к WinSock, то есть если Вы пишите программу для Win32 и после хотите перенести код на Unix-системы, то придется значительно изменять код.
Плюсом функции является то, что программисту не приходится заботиться о правильном чтении и отправки данных, всю работу возлагает на себя WinSock2. Определение функции:
BOOL TransmitFile( SOCKET hSocket, HANDLE hFile, DWORD nNumberOfBytesToWrite, DWORD nNumberOfBytesPerSend, LPOVERLAPPED lpOverlapped, LPTRANSMIT_FILE_BUFFERS lpTransmitBuffers, DWORD dwFlags );
Параметры:
hSocket – подключенный сокет, через который будет иди передача данных, тип сокета должен быть ориентированным на соединение. TransmitFile не поддерживает UDP сокеты;
hFile – описатель открытого файла, данные которого будут передаваться;
nNumberOfBytesToWrite – количество записываемых из файла байт, если 0 то отправляется файл целеком;
nNumberOfBytesPerSend – размер блоков данных для операции записи, если 2048 то передаче будет идти блоками по 2 килобайта, если 0 то размер блоков устанавливается по умолчанию;
lpOverlapped – определяет структуру OVERLAPPED, для перекрытого ввода/вывода;
lpTransmitBuffers – представляет структуру TRANSMIT_FILE_BUFFERS, содержащую информацию, которая передается до и после отправки данных из файла:
typedef struct _TRANSMIT_FILE_BUFFERS { PVOID Head; DWORD HeadLength; PVOID Tail; DWORD TailLength; } TRANSMIT_FILE_BUFFERS;</code>
Head – указатель на данные которые передаются до отправки;
HeadLength – количество передаваемой информации;
Tail – указатель на данные которые передаются после отправки;
TailLength — количество передаваемой информации.
dwFlags – флаги для управления работой TransmitFile:
TF_DISCONNECT – закрыть сокет после передачи;
TF_REUSE_SOCKET – использовать сокет для повторной передачи;
TF_USE_DEFAULT_WORKER, TF_USE_SYSTEM_THREAD – передача должна идти в контексте системного процесса, используются при передаче больших файлов;
TF_USE_KERNEL_APC – передача будет идти при помощи асинхронных вызовов процедур(APC), используется если нужна лишь одна процедура чтения;
TF_WRITE_BEHIND – завершить работу без подтверждения о приеме данных.
Для демонстрации работы функции создано тестовое приложение на MFC, которое всю принимаемую информацию будет выводить на экран, исходник приложения находится в архиве к данной статье. Теперь код программы передачи файлов:
#include <Winsock2.h>//ws2_32.lib #include <Mswsock.h>//Mswsock.lib #include <windows.h> #include <iostream.h> #include <conio.h> int main() { SOCKET sTransmit; SOCKADDR_IN InetAddr; HANDLE hFile; WSADATA wsaData; if(!WSAStartup(0x0202,&wsaData)) { if((sTransmit = socket(AF_INET,SOCK_STREAM,0)) != INVALID_SOCKET) { InetAddr.sin_family = AF_INET; InetAddr.sin_addr.s_addr = inet_addr("127.0.0.1");//htonl(INADDR_ANY); InetAddr.sin_port = htons(4004); if(connect(sTransmit,(struct sockaddr *)&InetAddr,sizeof(InetAddr)) != SOCKET_ERROR) { hFile=CreateFile("---.cpp",GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL); if(hFile != INVALID_HANDLE_VALUE) { BOOL bResult = TransmitFile(sTransmit,hFile,0/*целеком*/,1024,NULL,0,TF_DISCONNECT); if(!bResult){cout<<"Error TransmitFile"<<endl;} }else{cout<<"Error CreateFile"<<endl;} }else{cout<<"Error connect"<<endl;} }else{cout<<"Error socket"<<endl;} }else{cout<<"Error WSAStartup"<<endl;} CloseHandle(hFile); if(closesocket(sTransmit)==SOCKET_ERROR){cout<<"Error closesocket"<<endl;} WSACleanup(); cout<<"Press any key to continue"<<endl; while (!_getch()); return 0; }