Извините, ничего не найдено.

Не расстраивайся! Лучше выпей чайку!
Регистрация
Справка
Календарь

Вернуться   forum.boolean.name > Программирование игр для компьютеров > C++

Ответ
 
Опции темы
Старый 16.11.2015, 05:36   #1
Okay
Знающий
 
Регистрация: 21.11.2011
Сообщений: 284
Написано 17 полезных сообщений
(для 74 пользователей)
Вопрос С++ Sockets

Суть простая. Сервер получает по 4 байта. То бишь при отправки "how are you?" получает 3 сообщения сразу, а не одно


#include <iostream>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <vector>
#include <string>
#include <Windows.h>

#pragma comment(lib, "ws2_32.lib")
using namespace std;
SOCKET Connections[512];
SOCKET Connect;

SOCKET Listen;
SOCKET RECV;

int ClientCount = 0;



struct Data
{
	int ID;
	char * Name;
	
};

vector<Data> Players;
vector<string> ReadyMessage;

void ReadMessage(char * buffer);
void SetClientName(char * name);
void DeleteClient(int getID);
bool IsConnected(int getID);
void Work(int getID);



void SetClientName(char * name)
{

	return;
}

void DeleteClient(int getID)
{
	std::cout << "EZ DISCONNECT!" << std::endl;
	int size = Players.size();
	for (int i = 0; i < size; i++)
	{
		if (Players[i].ID == getID)
		{
			Players.erase(Players.begin() + i);
		}
	}
	Connections[getID] = NULL;
	closesocket(getID);
	return;
}

bool IsConnected(int getID)
{
	char * buffer = new char[1];
	int nSendBytes = send(getID, buffer, strlen(buffer), NULL);
	if (nSendBytes == SOCKET_ERROR)
	{
		DeleteClient(getID);
		return false;
	}
	else return true;
}

void Input()
{
	char * buffer = new char[512];
	while (true)
	{
		
		cin >> buffer;
		cout << "SENT: " << buffer << "[" << strlen(buffer) << "]" << endl;
		int size = Players.size();
		if (strcmp(buffer, "quit") == 0)
		{
			exit(0);
		}
		else
		{
			for (int i = 0; i < size; i++)
			{
				send(Players[i].ID, buffer, strlen(buffer), NULL);
			}
		}	
	}
}


void Work(int getID)
{
	std::cout << "Thread created" << std::endl;
	char * buffer = new char[512];
	int result;
	string rMessage = "";
	while (IsConnected(getID) == true)
	{
		Sleep(50);

		result = recv(getID, buffer, sizeof(buffer), NULL);
		
		if (result > 0)
		{
			
			buffer[result] = '\0';
			std::cout << "Message from " << getID << ": " << buffer << std::endl;
			int size = Players.size();
			for (int i = 0; i < size; i++)
			{
				send(Players[i].ID, buffer, strlen(buffer), NULL);
			}
			ZeroMemory(buffer, sizeof(buffer));
			//std::cout << result << std::endl;
		}


	}

	closesocket(getID);
	return;
}



int main()
{
	setlocale(LC_ALL, "RU");
	WSADATA wsa;
	SOCKET s, new_socket;
	struct sockaddr_in server, client;
	int c;
	char *message;

	printf("\nInitialising Winsock...");
	if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0)
	{
		printf("Failed. Error Code : %d", WSAGetLastError());
		return 1;
	}

	printf("Initialised.\n");

	//Create a socket
	if ((s = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
	{
		printf("Could not create socket : %d", WSAGetLastError());
	}
	CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)Input, NULL, 0, NULL);
	printf("Socket created.\n");

	//Prepare the sockaddr_in structure
	server.sin_family = AF_INET;
	server.sin_addr.s_addr = INADDR_ANY;
	server.sin_port = htons(2372);

	//Bind
	if (bind(s, (struct sockaddr *)&server, sizeof(server)) == SOCKET_ERROR)
	{
		printf("Bind failed with error code : %d", WSAGetLastError());
	}

	puts("Bind done");

	//Listen to incoming connections
	listen(s, 3);

	//Accept and incoming connection
	puts("Waiting for incoming connections...");

	c = sizeof(struct sockaddr_in);

	while (true)
	{
		Sleep(50);
		new_socket = accept(s, NULL, NULL);
		if (new_socket == INVALID_SOCKET)
		{
			printf("accept failed with error code : %d", WSAGetLastError());
		}
		else
		{
			Data newClient;
			newClient.ID = new_socket;
			//closesocket(new_socket);
			cout << "Client with ID " << newClient.ID << " connected!" << endl;
			CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)Work, (LPVOID)newClient.ID, 0, NULL);
			Players.push_back(newClient);
			
		}
	}
	getchar();

	closesocket(s);
	WSACleanup();


}
(Offline)
 
Ответить с цитированием
Старый 16.11.2015, 06:05   #2
Жека
Дэвелопер
 
Регистрация: 04.09.2005
Адрес: Красноярск
Сообщений: 1,376
Написано 491 полезных сообщений
(для 886 пользователей)
Ответ: С++ Sockets

Проверь чему равно sizeof(buffer).
(Offline)
 
Ответить с цитированием
Сообщение было полезно следующим пользователям:
Okay (16.11.2015)
Старый 16.11.2015, 06:42   #3
Okay
Знающий
 
Регистрация: 21.11.2011
Сообщений: 284
Написано 17 полезных сообщений
(для 74 пользователей)
Ответ: С++ Sockets

Сообщение от Жека Посмотреть сообщение
Проверь чему равно sizeof(buffer).
Thanks!
Ошибка была в
char * buffer = new char[512];
Изменил на
сhar buffer[512];
(Offline)
 
Ответить с цитированием
Старый 16.11.2015, 08:04   #4
Жека
Дэвелопер
 
Регистрация: 04.09.2005
Адрес: Красноярск
Сообщений: 1,376
Написано 491 полезных сообщений
(для 886 пользователей)
Ответ: С++ Sockets

Можно сделать переменную
int buf_size 512
чтобы не дёргать sizeof(buffer).

Ещё - в функции Work есть строка
send(Players[i].IDbufferstrlen(buffer), NULL); 
подумалось, что strlen(buffer) всегда будет равна result. но для utf я не уверен. это тоже к вопросу о целесообразности каждый раз дёргать функцию.
(Offline)
 
Ответить с цитированием
Сообщение было полезно следующим пользователям:
Okay (16.11.2015)
Старый 16.11.2015, 09:36   #5
Okay
Знающий
 
Регистрация: 21.11.2011
Сообщений: 284
Написано 17 полезных сообщений
(для 74 пользователей)
Ответ: С++ Sockets

Сообщение от Жека Посмотреть сообщение
Можно сделать переменную
int buf_size 512
чтобы не дёргать sizeof(buffer).

Ещё - в функции Work есть строка
send(Players[i].IDbufferstrlen(buffer), NULL); 
подумалось, что strlen(buffer) всегда будет равна result. но для utf я не уверен. это тоже к вопросу о целесообразности каждый раз дёргать функцию.
В принципе как вариант Даже не обратил внимание

Еще вопрос есть по обработке сообщений. То бишь нужно научить сервер разбирать сообщения по типам, почти как игровой. Сообщения типа "Я передвинулся", "Я нажал какую то кнопку" и тд

Думал парсить каждое сообщение, но по скорости не знаю как выйдет. Быть может есть способ легче?
(Offline)
 
Ответить с цитированием
Старый 16.11.2015, 12:18   #6
Жека
Дэвелопер
 
Регистрация: 04.09.2005
Адрес: Красноярск
Сообщений: 1,376
Написано 491 полезных сообщений
(для 886 пользователей)
Ответ: С++ Sockets

Зависит от того, какой тип протокола хочешь - текстовый или бинарный.
Текстовый легко парсить, бинарный не пробовал, наверное тоже легко.
Про скорость - хз, зависит от количества команд в единицу времени.
Если команд не сильно много, то среди прочих временных затрат будет не заметно.
(Offline)
 
Ответить с цитированием
Старый 16.11.2015, 13:47   #7
impersonalis
Зануда с интернетом
 
Аватар для impersonalis
 
Регистрация: 04.09.2005
Сообщений: 14,014
Написано 6,798 полезных сообщений
(для 20,935 пользователей)
Ответ: С++ Sockets

Код не читал @ сразу отвечал.
Кол-во принятых и прочитанных байт при асинхронном сокете tcp (и, надо полагать, udp - не работал с ним) никто не гарантирует. Надо постоянно проверять.
Ещё раз повторю: и для отправленного тоже. То есть вы должны убедиться, что отправлен весь указанный буфер, а не его часть. Соответственно, часть буфера возможно придётся "отправлять" (передавать в функцию отправки) ещё раз. Последнее - довольно частый баг, т.к. может не проявлять себя сколь угодно долго (пока сеть не будет забита => часть инфы не будет фактически отправлена с первого раза => потеряется часть информации и принимающая система упадёт): http://habrahabr.ru/post/213063/
__________________
http://nabatchikov.com
Мир нужно делать лучше и чище. Иначе, зачем мы живем? tormoz
А я растила сына на преданьях
о принцах, троллях, потайных свиданьях,
погонях, похищениях невест.
Да кто же знал, что сказка душу съест?
(Offline)
 
Ответить с цитированием
Сообщение было полезно следующим пользователям:
St_AnGer (16.11.2015)
Старый 17.11.2015, 05:43   #8
Жека
Дэвелопер
 
Регистрация: 04.09.2005
Адрес: Красноярск
Сообщений: 1,376
Написано 491 полезных сообщений
(для 886 пользователей)
Ответ: С++ Sockets

Почему TCP не гарантирует доставку? Должен.
Я полагаю, при загруженной сети может дойти кусок, и когда сеть просрётся, то дойдёт оставшаяся часть.
Поэтому парсить сразу каждый принятый кусок не нужно, нужно накапливать данные в буфере до тех пор, пока не встретим признак_окончания_команды. Для текстового формата этим признаком может служить \r\n .
(Offline)
 
Ответить с цитированием
Старый 17.11.2015, 12:31   #9
impersonalis
Зануда с интернетом
 
Аватар для impersonalis
 
Регистрация: 04.09.2005
Сообщений: 14,014
Написано 6,798 полезных сообщений
(для 20,935 пользователей)
Ответ: С++ Sockets

Сообщение от Жека Посмотреть сообщение
Почему TCP не гарантирует доставку?
читай внимательнее:
Сообщение от impersonalis Посмотреть сообщение
при асинхронном сокете tcp (и, надо полагать, udp - не работал с ним)
и да - он гарантированно доставит то, что он отметил (путём указания длины в возвращаемом значении) как отправленное. Синхронный заблокирует вызывающий поток до конца отправки всего буфера. Для большого количества приложений это очень неудобно.
Суть такова: ты хочешь отправить команду "12345". Но в момент отправки сеть едва скрипит, поэтому за малое время, выделенное на отправку, уходит только "123", и функция возвращает тебе число 3, как индикатор количества отправленных байт. Очень часто, это число никто не проверяет (ограничиваясь только проверкой на отсутствие сбоя), считая что асинхронный сокет будет сам как-то выкручиваться и отправлять оставшееся "45". НЕТ. При следующем вызове надо будет отправить* "45" ещё раз. И опять убедиться - что отправилось.

Про контроль прочитанного мы знаем ещё по блитцу. В общем-то никто не гарантирует какими порциями информация будет уходить по сети. Как правило, происходит некая аккумуляция данных, чтобы не забивать сетку маленькими пакетами. Но при необходимости, это можно изменить. Но это отдельная большая тема.
Я бы не советовал в общем случае привязываться к разделителю строк. Сепаратор надо выбирать исходя из передаваемого контента. Возможно, его получится сделать более коротким, или наоборот - проще сделать подлиннее (например, исходя из больших размеров "строки").
__________________
http://nabatchikov.com
Мир нужно делать лучше и чище. Иначе, зачем мы живем? tormoz
А я растила сына на преданьях
о принцах, троллях, потайных свиданьях,
погонях, похищениях невест.
Да кто же знал, что сказка душу съест?
(Offline)
 
Ответить с цитированием
Эти 2 пользователя(ей) сказали Спасибо impersonalis за это полезное сообщение:
St_AnGer (17.11.2015), Жека (17.11.2015)
Ответ


Опции темы

Ваши права в разделе
Вы не можете создавать темы
Вы не можете отвечать на сообщения
Вы не можете прикреплять файлы
Вы не можете редактировать сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.


Часовой пояс GMT +4, время: 23:33.


vBulletin® Version 3.6.5.
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Перевод: zCarot
Style crйe par Allan - vBulletin-Ressources.com