Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > IT форум > Помощь студентам
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 10.04.2012, 20:08   #1
refinderoth
 
Регистрация: 10.04.2012
Сообщений: 3
По умолчанию Прием UDP пакетов (visual c++)

Здравствуйте!
Ранее с си дела практически не имел и, вообще говоря, иметь не собирался. Но обстоятельства сложились

Общая задача стояла так, принять от блока пакеты данных, используя протокол UDP. Результаты нужно записать в текстовые файлы в виде 0х1234 (16). Ах да, принципиально на версии VC6.0.

Долго ковыряясь, худо-бедно собрал код:

Код:
#include <iostream>	//	основной набор библиотек
#include <string>	//	для строк
#include <fstream>	//	для работы с файлами
#include <iomanip>	//	для конвертации

#include "socket.hpp"

using namespace std;

int main ()
{
	int i;		// переменная для работы с циклом
	int j=1;	// переменная для заполнения одного тевстового файла
	try
	{	  _ws_init();	// инициализация сокета
	       _sock_addr*sock_addr=new _sock_addr("127.0.0.1", 4096);	        // адрес и порт
		_sock_addr * sock_dest = new _sock_addr ();
                _sock * sock = new _sock (SOCK_DGRAM);					 	 	                                // протокол передачи udp
		sock->bind (sock_addr);											// привязка сокета

///////////////////// для первого файла Data1.txt
		ofstream file("16dat01.dat", ios::out);						// открываем файл для записи
		if (! file)													// ошибка открывания файла
		{
			cout << "File 16dat01.dat could not be opened" << endl;
			return -1;
		}
		cout << "File 16dat01.dat was opened" << endl;				// Извещение о том, что файл открыт и готов к записи
		char * buffer = new char [10000000];						// буфер данных
		while(j < 4)												// цикл получения данных от клиента
		{
			for (i = 1; i <= 20; i++)								//	первые двадцать слов
			{
				sock->recv (sock_dest, buffer, 10000000);			// операция получения слова
				cout<< buffer << endl;								// вывод слова на экран
				file << buffer << endl;								// запись слова в файл
			}
			file << endl;											// пустая строка для разделения блоков слов в файле
			cout << "Received a message" << endl					// уведомление о получении данных
			<< "\tsource IP: " << sock_dest->get_ip() << endl			
			<< "\tsource port: " << sock_dest->get_port() << endl;
			if (buffer == "end of transfer")						// по сигналу с Клиента прерываем цикл (для теста)
				break;
			j = j + 1;												// для повторения цикла while
		}
		file << "transfer complete" << endl;						// Уведомление в файле о завершении передачи
		file.close ();												// закрываем файл
		j = 1;														// возвращаем переменную к исходному значению

		delete buffer;												// удаляем буфер, сокет и лишние данные
		delete sock;
		delete sock_dest;
		delete sock_addr;
		_ws_cleanup ();

///////////////////////////////////// конвертация файлов
		ifstream in1("16dat01.dat", ios::binary);					// открываем первый записанный файл
		ofstream out1("Data1.txt");									// открываем первый итоговый файл
		if( !in1.is_open() || !out1.is_open()) return -1;			// проверяем на ошибку открывания файлов
		out1 << uppercase << hex << setfill('0') ;
		char ch1; 
		while( !in1.eof() )											// пословно преобразуем данные
		{ 
			in1.read(&ch1, sizeof(char)); 
			out1 << setw(2) << (int)ch1 << " ";
		}
		in1.close();												// закрываем файл записи
		out1.close();												// закрываем итоговый файл
		
	}
	catch (_sock_exception & err)									
	{
		err.print ();
	}
	catch (...)
	{
		cerr << "Unknown error" << endl;							// стандартный вызов ошибки при работе с файлами
	}
	return 0;
}
refinderoth вне форума Ответить с цитированием
Старый 10.04.2012, 20:09   #2
refinderoth
 
Регистрация: 10.04.2012
Сообщений: 3
По умолчанию

Описание socket:
Код:
#include <cstring>		// для работы со строками
#include <iostream>		// набор стандартных библиотек ввода-вывода

#include <winsock2.h>	// набор библиотек для работ с сокетом по протоколу UDP
#include "socket.hpp"

	
using namespace std;

////////////////////////////////////////////////////////////////////////////////
// Ниже идут функции, которые выполняют базовую инициализацию и очистку winsock

void _ws_init ()
{
	WORD winsock_version = MAKEWORD (2,0);		// запрашиваем winsock версии 2.0
	WSADATA winsock_data;						// сюда будут помещены данные 
												// об инициализированном интерфейсе winsock

	int error = WSAStartup (winsock_version, &winsock_data);	// непосредственно инициализция
	if (error != 0)
		throw _sock_exception ("_winsock_intialize - could not initialize winsock");
}

void _ws_cleanup ()
{
	int error = WSACleanup ();					// очистка и деинициализация winsock
	if (error == SOCKET_ERROR)
		throw _sock_exception ("_winsock_cleanup - could not perform cleaning up");
}

////////////////////////////////////////////////////////////////////////////////
// определение исключений, генерируемых нашими классами
	
_sock_exception::_sock_exception (const char * error_string)
{
	error_code = GetLastError ();			// мы используем более общую функцию
											// вместо WSAGetLastError, потому что
											// исключение может быть сгенерировано
											// в случае неудачной инициализации winsock,
											// и тогда мы не смогли бы использовать 
											// функцию WSAGetLastError()
	error_description = error_string;
}
	
void _sock_exception::print ()
{
	cerr << "*** Error in " << error_description << endl			
        << "\tCode: " << error_code << endl;			// вывести сообщение об ошибке и код
														// ошибки в небуферизуемый стандартный поток
														// вывода ошибок
														// описание ошибки можно узнать с помощью утилиты
														// ErrorLookup из средств MS Visual Studio,
														// либо при помощи функции FormatMessage
}

////////////////////////////////////////////////////////////////////////////////
// определение класса для инкапсуляции нашей адресной структуры

_sock_addr::_sock_addr ()
{
	address = new struct sockaddr_in;
	address->sin_family = AF_INET;
}

_sock_addr::_sock_addr (unsigned short port)
{
	address = new struct sockaddr_in;
	address->sin_family = AF_INET;
	address->sin_addr.s_addr = INADDR_ANY;
	address->sin_port = htons (port);
}

_sock_addr::_sock_addr (const char * ip, unsigned short port)
{
	address = new struct sockaddr_in;
	address->sin_family = AF_INET;
	address->sin_addr.s_addr = inet_addr (ip);
	if (address->sin_addr.s_addr == INADDR_NONE)
	{
		throw _sock_exception ("_socket_address - the provided IP address seems to be invalid");
		delete address;
	}
	address->sin_port = htons (port);
}

_sock_addr::~_sock_addr ()
{
	delete address;
}

void _sock_addr::set_ip (const char * ip)
{
	address->sin_addr.s_addr = inet_addr (ip);
	if (address->sin_addr.s_addr == INADDR_NONE)
		throw _sock_exception ("_socket_address - the provided IP address seems to be invalid");
}

////////////////////////////////////////////////////////////////////////////////
// определение интерфейса класса _socket

_sock::_sock (int type)
{
	sd = socket (PF_INET, type, 0);				// создаем сокет
	if (sd == SOCKET_ERROR)
		throw _sock_exception ("_socket - could not create a socket");
	
}

_sock::~_sock ()
{
	int error = closesocket (sd);				// закрываем сокет
	if (error == SOCKET_ERROR)
		throw _sock_exception ("_socket - could not close socket properly");
}

void _sock::bind (_sock_addr * addr)			// привязка сокета
{
	int error = ::bind (sd, reinterpret_cast <struct sockaddr*> (addr->get_addr()), sizeof (struct sockaddr_in));
	if (error == SOCKET_ERROR)
		throw _sock_exception ("_socket::bind - could not bind socket to a provided name");
}

void _sock::send (_sock_addr * dest, const char * const data, int len)		// послать пакет
{
	int error = sendto (sd, data, len, 0, reinterpret_cast <sockaddr *> (dest->get_addr()), sizeof (struct sockaddr_in));
	if (error == SOCKET_ERROR)
		throw _sock_exception ("_sock::send - could not send data");
}

void _sock::recv (_sock_addr * dest, char * data, int len)					// принять пакет
{
	int dest_len = sizeof (struct sockaddr_in);
	int error = recvfrom (sd, data, len, 0, reinterpret_cast <sockaddr *> (dest->get_addr()), &dest_len);
	if (error == SOCKET_ERROR)
		throw _sock_exception ("_sock::recv - could not receive data");
}
refinderoth вне форума Ответить с цитированием
Старый 10.04.2012, 20:10   #3
refinderoth
 
Регистрация: 10.04.2012
Сообщений: 3
По умолчанию

Ну и код для посылки пакетов (для теста, в принципе, не нужен):

Код:
#include <iostream>		// основной набор библиотек
#include <string>		// для строк
#include <fstream>		// для работы с файлами

#include "socket.hpp"

using namespace std;
int main ()
{
	int c;					// переменная для операции переключения блоков слов
	int i;					// переменная для работы с циклом
	char * buffer;			// буфер для хранения слов
	char filename [81];		// переменная для внешнего файла
	char input_line [81];	// переменная для одного слова из внешнего файла
	try						// соединение с сервером
	{
		_ws_init ();									// инициализация сокета
		_sock_addr * sock_dest = new _sock_addr ();
		sock_dest->set_ip("127.0.0.1");					// адрес сервера
		sock_dest->set_port(4096);						// порт
        _sock * sock = new _sock (SOCK_DGRAM);			// выбираем передачу по протоколу UDP
		cout << "enter a file name and press ENTER: ";
		cin.getline(filename, 80);						// запрос на текстовый файл
		ifstream file_in (filename);					// открываем внешний файл
		if (! file_in)									// проверка на ошибку при открывании файла
		{
			cout << "file" << filename;
			cout << "could not be opened";
			return -1;
		}

		while(1)	// цикл для пословной передачи
		{

			for (i = 1; i <= 20 && ! file_in.eof(); i++)			// передаем по 20 слов
			{
				file_in.getline (input_line, 80);					// считываем слово из файла
				cout << input_line << endl;							// выводим слово на экран
				buffer = input_line;								// передаем слово в буфер
				sock->send (sock_dest, buffer, strlen (buffer)+1);	// пересылаем слово на Сервер
			}
			if (file_in.eof())										// проверка на достижение конца файла
				break;
			cout << "More? (Press Q and ENTER to quit)";			// нажимаем enter для вывода следующих 20 слов
			cin.getline (input_line, 80);					
			c = input_line[0];	
 			if (c == 'Q' || c == 'q')								// Q и Enter для выхода из программы
				break;	
		}
			buffer = "end of transfer";								// сообщаем серверу о прекращении передачи
			cout << buffer << endl;									// выводим это сообщение на экран
			sock->send (sock_dest, buffer, strlen (buffer)+1);
			delete sock;											// удаляем сокет и лишние данные
			delete sock_dest;	
			_ws_cleanup ();
	}
	catch (_sock_exception & err)
	{
		err.print ();
	}
	catch (...)
	{
		cerr << "Unknown error" << endl;
	}
	return 0;
}
Понятно, что здесь можно много и по делу придираться. Но меня, уважаемые эксперты, интересует такая вещь. При приеме пакета считывается только первая строка пакета, потом принимается следующий пакет (и опять только первая строка) и т.д. Остальные ошибки меня сейчас не волнуют, но нужно разобраться с этим моментом, иначе все остальное - без толку.

Последний раз редактировалось refinderoth; 10.04.2012 в 22:23.
refinderoth вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Отправка пакетов. Маверик Работа с сетью в Delphi 6 30.11.2010 18:01
UDP Server - потеря пакетов. Возможно ли сделать прием более надежным MMaschine Работа с сетью в Delphi 2 06.09.2010 12:51
перехват TCP и UDP пакетов prog.delphin Работа с сетью в Delphi 4 31.03.2010 13:21
Получение и чтение входящих UDP пакетов XAOC-forever Работа с сетью в Delphi 6 03.06.2008 10:02