C++ Как отправить char [11] с помощью send другой программе?

Все о программировании под *nix
andrew-fr
Заглянувший
Сообщения: 3
Зарегистрирован: 31 дек 2008, 14:01

C++ Как отправить char [11] с помощью send другой программе?

Сообщение andrew-fr »

Мне нужно отправить структуру с клиента

Код: Выделить всё

 	struct BuffToSend
	{
		char flag;
		char type;
		int func;
		char msg [11];
	} s_buff;
другой программе (серверу). Отправляю buffer = (char*) &s_buff; Принимаю s_buff = *(BuffToSend*)b_in;
На сервере получаю 6 байт, приходит все кроме msg[11] он пустой. С клиента отправляется 6 байт. То есть получается, что я вообще не отправляю msg[11] . Скорее всего я пытаюсь отослать не данные, а адрес. Вопрос: как я могу отправить char msg [11]?

Сильно не бейте на си програмлю плохо. И скорее всего не понимаю очевидного из-за чего не отправляется.

Исходник сервера (который принимает)

Код: Выделить всё

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>

// Функции
int LoadConf ();

struct CFG_NET
{
	char backlog; // очередь ожидающих соединений
	int port;
	char * ip;
} cfg_net;

class NET
{
	private: int s_server, s_clients [2000];
	private: struct sockaddr_in si_server, si_clients [2000];
	private: timeval timeout;
	private: fd_set readset;
	private: char* b_in;

	public: NET ()
	{
		printf ("Net up... ");
		s_server = socket (PF_INET, SOCK_STREAM, 0);
		fcntl(s_server, F_SETFL, O_NONBLOCK);
		if (s_server == -1)
		{
			printf ("ERROR\n\r");
			perror("\n\rERROR");
			exit (1);
		}
		memset (&si_server, 0, sizeof si_server);
		si_server.sin_family = AF_INET;
		si_server.sin_addr.s_addr = inet_addr (cfg_net.ip);
		si_server.sin_port = htons (cfg_net.port);
		if (bind (s_server, (struct sockaddr*) &si_server, sizeof si_server) == -1)
		{
			printf ("ERROR\n\r");
			perror("\n\rERROR");
			exit (1);
		}
		if (listen (s_server, cfg_net.backlog) == -1)
		{
			printf ("ERROR\n\r");
			perror("\n\rERROR");
			exit (1);
		}
		for (int i = 0; i < 2000; i++)
		{
			s_clients[i] = 0;
		}
		timeout.tv_sec = 0;
		timeout.tv_usec = 100;
		b_in = (char*)malloc(20);
		printf ("OK\n\r");
	}

	public: void sel ()
	{
		FD_ZERO (&readset);
		FD_SET (s_server, &readset);
		int max = s_server;
		for (int i = 0; i < 2000; i++)
			if (s_clients[i] != 0)
			{
				FD_SET (s_clients[i], &readset);
				if (s_clients[i] > max)
					max = s_clients[i];
			}
		if (select (max+1, &readset, NULL, NULL, &timeout) > 0)
		{
			if (FD_ISSET (s_server, &readset))
			{
				acc ();
			}
			else
			{
				for (int i = 0; i < 2000; i++)
					if (FD_ISSET (s_clients[i], &readset))
					{
						rec (i);
						break;
					}
			}
		}
	}

	public: int acc ()
	{
		int i = 0;
		for (i; i < 2000; i++)
		{
			if (s_clients[i] == 0)
				break;
		}
		memset (&si_clients, 0, sizeof si_clients);
		socklen_t si_len = sizeof &si_clients[i];
		s_clients [i] = accept (s_server, (struct sockaddr*) &si_clients [i], &si_len);
		if (s_clients [i] == -1)
		{
			close (s_clients [i]);
			s_clients [i] = 0;
			exit (1);
		}
	}

	public: int rec (int in)
	{
		struct BuffToSend
		{
			char flag;
			char type;
			int func;
			char msg [11];
		} s_buff;

		int error = recv (s_clients[in], b_in, 16, 0);
		if (error > 0)
		{
			s_buff = *(BuffToSend*)b_in;
			puts (s_buff.msg);
			printf ("%i %i %i %s\n\r", s_buff.flag, s_buff.type, s_buff.func, s_buff.msg);
			puts ("OK");
		}
		else
			switch (error)
			{
				case -1:
					perror ("recv ()");
					exit (1);
					break;
				case 0:
					close (s_clients[in]);
					s_clients[in] = 0;
					puts ("Client disconect.");
					break;

			}
	}
};

class PROGRAMM
{
	private: NET net;

	public: PROGRAMM ()
	{
		printf ("Server is run.\n\r IP:   %s\n\r Port: %i\n\r", cfg_net.ip, cfg_net.port);
	}

	public: void kernel()
	{
		for (;;)
		{
			net.sel ();
		}
	}

	~PROGRAMM ()
	{
// 		exit (0);
	}
};

int main()
{
	LoadConf ();
	PROGRAMM programm;
	programm.kernel ();
}

int LoadConf ()
{
	cfg_net.backlog = 5;
	cfg_net.port = 1407;
	cfg_net.ip = "127.0.0.1";
	printf ("OK\n\r");
	return (0);
}
Исходник клиента, который отсылает:

Код: Выделить всё

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>

int s, error;

int sendall (char type, int func, char * out_msg)
{
	struct BuffToSend
	{
		char flag;
		char type;
		int func;
		char msg [11];
	} s_buff;
	char * buffer;
	char out[11];
	char flag = 0;
	for (int i = 0; i < strlen (out_msg); i += 10)
	{
		out[0] = 0;
		strncat(out, out_msg + i, 10);
		if (i == 0 and strlen (out_msg) <= 10)
			flag = 0;
		else
		{
			if (i == 0 and strlen (out_msg) > 10)
				flag = 1;
			else
			{
				if (i+10 >= strlen (out_msg))
					flag = 3;
				else
					flag = 2;
			}
		}
		s_buff.flag = flag;
		s_buff.type = type;
		s_buff.func = func;
		strcpy(s_buff.msg, out);
		buffer = (char*) &s_buff;
		printf ("%i %i %i %s\n\r", s_buff.flag, s_buff.type, s_buff.func, s_buff.msg);

		if (send (s, buffer, strlen (buffer)+10, 0) == -1)
		{
			perror ("send ()");
			return (1);
		}
		printf ("%i\n\r", strlen (buffer));

	}
}

int main()
{
	struct sockaddr_in si;
	s = socket (PF_INET, SOCK_STREAM, 0);
	if (s == -1)
	{
		perror( "socket ()" );
		return 1;
	}
	puts ("Socket OK");
	memset (&si, 0, sizeof si);
	si.sin_family = AF_INET;
	si.sin_addr.s_addr = inet_addr ("127.0.0.1");
	si.sin_port = htons (1407);
	error = connect (s, (struct sockaddr*) &si, sizeof si);
	if (error == -1)
	{
		perror ("connect ()");
		return (1);
	}
	puts ("Connect OK");

	char * out_msg;
	out_msg = "Hello! This text.";
	sendall (5, 11090, out_msg);
	close (s);
	return 0;
}

Аватара пользователя
mend0za
Неотъемлемая часть форума
Сообщения: 2332
Зарегистрирован: 30 авг 2002, 12:33
Откуда: Minsk

Re: C++ Как отправить char [11] с помощью send другой программе?

Сообщение mend0za »

Дикий код, с непредсказуемым результатом.

Код: Выделить всё

send (s, buffer, strlen (buffer)+10, 0) == -1) 
Обычная практика, если посылается структура, то берётся её размер через sizeof. На recv - аналогично.

Код: Выделить всё

send (s, &s_buff, sizeof(s_buff), 0); 
И хорошо бы знать код возврата send(), он покажет сколько данных действительно отослано. На таких маленьких объёмах обычно уходит атомарно, одним куском.

Остальную логику не трогал, хотя там можно знвчительно упростить работу со строками.

andrew-fr
Заглянувший
Сообщения: 3
Зарегистрирован: 31 дек 2008, 14:01

Re: C++ Как отправить char [11] с помощью send другой программе?

Сообщение andrew-fr »

Изменил strlen на sizeof. sizeof - Говорит 4 байта. send тоже 4 байта.
recv принимает 4 байта.
Делаю

Код: Выделить всё

         s_buff = *(BuffToSend*)b_in;
         puts (s_buff.msg);
         printf ("%i %i %i %s\n\r", s_buff.flag, s_buff.type, s_buff.func, s_buff.msg);
Выводит все кроме char [11].

Клиент не отправляет char [11]

andrew-fr
Заглянувший
Сообщения: 3
Зарегистрирован: 31 дек 2008, 14:01

Re: C++ Как отправить char [11] с помощью send другой программе?

Сообщение andrew-fr »

Почему он не отправляет?

Аватара пользователя
mend0za
Неотъемлемая часть форума
Сообщения: 2332
Зарегистрирован: 30 авг 2002, 12:33
Откуда: Minsk

Re: C++ Как отправить char [11] с помощью send другой программе?

Сообщение mend0za »

sizeof(buffer) == 4, так как указатель

sizeof(s_buff) не будет 4

kreol
Увлекающийся
Сообщения: 99
Зарегистрирован: 02 июл 2007, 20:38
Откуда: Минск

Re: C++ Как отправить char [11] с помощью send другой программе?

Сообщение kreol »

Пардон, а зачем столько указателей? Взять хотя бы это

Код: Выделить всё

buffer = (char*) &s_buff;
Если мне память не изменяет, то структура сама по себе представляет указатель. Вообще структура в Си практически аналогична классу. Но даже если это не так, то к указателю на чар вы приводите адрес структуры, то есть как раз 4 байта указателя. Если у вас это хоть как-то работает, то скорее всего только потому что обе программы находятся на одном компьютере (хотя по идее у них разный базовый адрес и работать вообще не должно): реально по сети передаётся только 4 байта адреса, но никак не сама структура. По крайней мере, создаётся такое ощущение, лучше всегда дебаггером проверять.

Собственно не совсем понимаю, зачем вообще преобразовывать буффер в массив чаров. Байтам, которые вы по сети пересылать собираетесь, глубоко по барабану, какой тип они имеют на обоих концах провода в обеих ваших программах. Вот товарищ сверщу правильно показал, как посылать. А принимаете вы опять неправильно:

Код: Выделить всё

s_buff = *(BuffToSend*)b_in;
Вот, что вы делаете: полученную по сети строчку b_in преобразуете к указателю, то есть просто берёте первые 4 байта из полученных и записываете их в переменную типа "указатель", а потом ещё обращаетесь в память по этому, практически случайному адресу и записываете то, что там лежит в переменную s_buff. Ну, то есть, совсем не то, что нужно. Это вам чтобы разобраться немного. А так принимать лучше сразу в структуру:

Код: Выделить всё

int error = recv (s_clients[in], &s_buff, sizeof(BuffToSend), 0);
(или без амперсанда, уже точно не помню)

Ответить