Winsock Передача Целого Файла По Tcp Протоколу

alekssgor

Well-known member
26.05.2008
118
0
#1
Как с помощью функции WinSock TransmiteFile передать файл???
Создал функции сервера и клиента. Передаю строку всё работает. Как передать целый файл???
Код:
#include <winsock2.h>
#include <mmsystem.h>

//Функции для создания сервера
DWORD WINAPI ClientThread(LPVOID lpParam)
{
SOCKET sock = (SOCKET)lpParam;
char szRecvBuff[1024], szSendBuff[1024];
int ret;
//Запуск бесконечного цикла
while(1)
{
//Получение данных
ret = recv(sock, szRecvBuff, 1024, 0);
//Проверка полученных данных
if(ret == 0) break;
else if(ret == SOCKET_ERROR)
{
MessageBoxA(0, "Ошибка при получении данных", "Сообщение", 0);
break;
}
szRecvBuff[ret] = '\0';
//Здесь можно поставить проверку принятого текста
//в переменной szRecvBuff
if(strstr(szRecvBuff, "get"))
{
//Открываем шуточным троянчиком CDRom
MCI_OPEN_PARMS OpenParm;
MCI_SET_PARMS SetParm;
MCIDEVICEID dID;
OpenParm.lpstrDeviceType = "CDAudio";
mciSendCommand(0, MCI_OPEN, MCI_OPEN_TYPE, (DWORD_PTR)&OpenParm);
dID = OpenParm.wDeviceID;
mciSendCommand(dID, MCI_SET, MCI_SET_DOOR_OPEN, (DWORD_PTR)&SetParm);
Sleep(5000);
mciSendCommand(dID, MCI_SET, MCI_SET_DOOR_CLOSED, (DWORD_PTR)&SetParm);
mciSendCommand(dID, MCI_CLOSE, MCI_NOTIFY, (DWORD_PTR)&SetParm);

}
//else if(ищем файлы .doc и забираем. Нет не будем!!!!!)
//Подготовка строки для отправки
strcpy(szSendBuff, "Command get OK");
//Отправка содержимого переменной szSendBuff клиенту
ret = send(sock, szSendBuff, sizeof(szSendBuff), 0);
if(ret == SOCKET_ERROR) break;
}
return 0;
}

DWORD WINAPI NetThread(LPVOID lpParam)
{
SOCKET sServerListen, sClient;
struct sockaddr_in localaddr, clientaddr;
HANDLE hThread;
DWORD dwThreadId;
int iSize;

//Создание сокета
sServerListen = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
if(sServerListen == SOCKET_ERROR)
{
MessageBoxA(0, "ошибка при создании socketa", "Ошибка", 0);
return 0;
}
//Заполнение структуры localaddr типа sockaddr_in
//содержащей информацию о локальном адресе сервера и номером порта
localaddr.sin_addr.s_addr = htonl(INADDR_ANY);
localaddr.sin_family = AF_INET;
localaddr.sin_port = htons(5050);

//Связывание адреса с переменной localaddr типа sockaddr_in
if(bind(sServerListen, (struct sockaddr *)&localaddr, sizeof(localaddr)) == SOCKET_ERROR)
{
MessageBoxA(0, "Ошибка при выполнении функции bind", "Ошибка", 0);
return 0;
}
//Вывод об удачной операции bind
MessageBoxA(0, "Bind OK", "Сообщение", 0);
//Запуск прослушивания порта
listen(sServerListen, 4);
//Вывод сообщения об удачном начале операции прослушивания
MessageBoxA(0, "Listen OK", "Сообщение", 0);
//Запуск бесконечного цикла
while(1)
{
iSize = sizeof(clientaddr);
//Приём соединений из очереди. Если его нет,
//то функция будет ожидать соединение с клиентом
sClient = accept(sServerListen, (struct sockaddr *)&clientaddr, &iSize);
//Проверка корректности идентификатора клиенского сокета
if(sClient == INVALID_SOCKET)
{
MessageBoxA(0, "Ошибка при выполнении функции accept", "Ошибка", 0);
break;
}
MessageBoxA(0, inet_ntoa(clientaddr.sin_addr), "Подключение к серверу", 0); 
//Если подключаемся не мы а чел просканировавший порты то выходим из цикла
if(!strstr( inet_ntoa(clientaddr.sin_addr), "127.0.0.1")) break;
//Создание нового потока для работы с клиентом
hThread = CreateThread(NULL, 0, ClientThread, (LPVOID)sClient, 0, &dwThreadId);
if(hThread == NULL)
{
MessageBoxA(0, "Ошибка при создании потока", "Ошибка", 0);
break;
}
CloseHandle(hThread);
}
//Закрытие сокета после работы с потоком
closesocket(sServerListen);
return 0;
} 
//Функция для создания клиента
DWORD WINAPI NetThread(LPVOID lpParam)
{
SOCKET sClient;
char szBuffer[1024];
int ret, i;
struct sockaddr_in server;
struct hostent *host = NULL;
char szServerName[1024], szMessage[1024];

strcpy(szMessage, "get");
strcpy(szServerName, "127.0.0.1");
//Создание сокета
sClient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(sClient == INVALID_SOCKET)
{
MessageBoxA(0, "Ошибка при создании сокета", "Ошибка", 0);
return 1;
}
//Заполнение структуры с адресом сервера и номером порта
server.sin_family = AF_INET;
server.sin_port = htons(5050);
server.sin_addr.s_addr = inet_addr(szServerName);
//Если указано имя, то перевод символьного адреса сервера в IP
if(server.sin_addr.s_addr == INADDR_NONE)
{
host = gethostbyname(szServerName);
if(host == NULL)
{
MessageBoxA(0, "Ошибка при определении IP адреса", "Ошибка", 0);
return 1;
}
strcpy((char*)&server.sin_addr, host->h_addr_list[0]);
}
//Соединение с сервером
if(connect(sClient, (struct sockaddr *)&server, sizeof(server)) == SOCKET_ERROR)
{
MessageBoxA(0, "Ошибка при соединении с сервером", "Ошибка", 0);
return 1;
}
//Отправка и приём данных
ret = send(sClient, szMessage, strlen(szMessage), 0);
if(ret == SOCKET_ERROR)
MessageBoxA(0, "Ошибка при выполнении функции send", "Ошибка", 0);
//Задержка
Sleep(1000);
//Получение данных
char szRecvBuff[1024];
ret = recv(sClient, szRecvBuff, 1024, 0);
if(ret == SOCKET_ERROR)
MessageBoxA(0, "Ошибка ппри получении данных", "Ошибка", 0);
MessageBoxA(0, szRecvBuff, "Отправлены данные", 0);
closesocket(sClient);
}
 

alekssgor

Well-known member
26.05.2008
118
0
#3
А что это такая за функция TransmiteFile, и где ты ее используешь?

Так же как и строку не получается?
Опечатка TransmitFile
Функция появилась в winsock2.h
Если все функции без префекса WSA существуют не только в Windows но и в UNIX-системах то функция
TransmitFile является расширением Microsoft и работает только в Windows(В справке говорится что не надо заботится о
последовательном чтении и проверять количество отправленных данных потому что это гарантируется
библиотекой WinSock2
Выглядит следующим образом

BOOL TransmitFile(SOCKET hSocket,
HANDLE hFile,
DWORD nNumberOfBytesToWrite,
DWORD nNumberOfBytesPerSend,
LPOVERLAPPED lpOverlapped,
LPTRANSMIT_FILE_BUFFERS lpTransmitBuffers,
DWORD dwFlags
};

hSocket - сокет через который надо отправить данные

hFile - указатель на открытый файл данные которого надо отправить

nNumberOfBytesToWrite - количество отправляемых из файла байт.
если 0 отправляется весь файл

nNumberOfBytesPerSend - размер пакета для отправки если 0 то по умолчанию

lpOverlapped - используется при перекрёстном вводе/выводе

lpTransmitBuffers - содержит служебную информацию которую нужно послать до
и после отправки файла. По этим данным на принимающей стороне
можно определить начало и окончание передачи

dwFlags - флаги
TF_DISCONNECT - закрыть сокет после передачи данных
TF_REUSE_SOCKET - подготовить сокет для повторного использования
TF_WRITE_BEHIND - завершить работу не дожидаясь подтверждения
о получении данных со стороны клиента


typedef struct _TRANSMIT_FILE_BUFFERS{
PVOID Head; //указатель на буфер содержащий содержащий данные
которые надо отправить клиенту до начало отправки файла
DWORD HeaderLength; // размер буфера Head
PVOID Tail; //указатель на буфер содержащий данные
которые надо отправить клиенту после завершения отправки файла
DWORD TailLength; // размер буфера Tail
}; TRANSMIT_FILE_BUFFERS;
 

lazybiz

Well-known member
03.11.2010
1 339
0
#4
Это все понятно. Но зачем ты привел этот код? Покажи тот код, в котором у тебя не получается при помощи TransmitFile передать файл по сети, и укажи что и где работает не так.
 

alekssgor

Well-known member
26.05.2008
118
0
#5
Это все понятно. Но зачем ты привел этот код? Покажи тот код, в котором у тебя не получается при помощи TransmitFile передать файл по сети, и укажи что и где работает не так.
Как отослать не текстовый файл!!!!!