SFML и C++ Уроки \ Разработка игр › Форумы › SFML Network › Ряд вопросов
В этой теме 23 ответа, 5 участников, последнее обновление tyman 8 года/лет, 6 мес. назад.
-
АвторСообщения
-
Всем доброго времени суток)
Какой функцией получить ип адресс (адресса) клиентов моего сервера (Уже UDP)
Есть ли в SFML готовые списки ип адресов? Если нету, что более вероятно то что лучше использывать Массив или Список. И если есть примеры или мысли то натолкните на нужную или примером помогите.
Буду вам очень признателен)
sf::IpAddress::getPublicAddress() для WWW(если соединение с клиентом через интернет) или sf::IpAddress::getLocalAddress() в LAN(если по локальной сети).
Эти функции возвращают Ип адресс той программы в которой они используются, а мне нужно На стороне сервера узнать подключенных клиентов.
C++123456789101112131415161718192021UdpSocket socket;socket.bind(55002);// Создание пакета, с помощью которого можно будет общатся с клиентомPacket packet;// Запрос и вывод СВОЕГО Ip адресаIpAddress ip = IpAddress::getLocalAddress();cout << "Server created with ip: " << ip << endl;char buffer[1024];std::size_t received = 0;IpAddress sender;unsigned short port;// Прием первого сообщения от клиента с Ип адресомsocket.receive(buffer, sizeof(buffer), received, sender, port);cout << buffer << ":" << port << std::endl;// Отправка клиенту успешного подключенияstd::string message = "Connected to " + sender.toString();socket.send(message.c_str(), message.size() + 1, sender, port);cout << "blalala: " << ip << ":" << port << endl;cout << socket.getLocalPort();Вот как тут видно, я получаю сообщение от клиента и тем самым могу узнать его ип и порт. Но от этого легче не стало..
Поскольку появился ряд вопросов.
Как сделать список клиентов?
Как узнать отключился ли клиент?
Как отсылать всем клиентам сообщения?
C++12345678910111213141516171819while (true){socket.receive(buffer, sizeof(buffer), received, sender, port);packet >> buffer;cout << "Client: " << buffer << endl;packet << buffer; //Пакуем значения координат в Пакетsocket.send(buffer, sizeof(buffer) + 1, sender, port); //Отправка данныхpacket.clear(); //Чистим пакетsleep(sf::milliseconds(10));//Задержка}Как видно из цикла то при получении сообщения от клиента, я могу отправить только ему обратное сообщение.
Действует некий прицип
Клиент1 >> Сервер
Сервер >> Клиент1
Но если подключится еще один клиент то получается так
Клиент1 >> Сервер
Сервер >> Клиент1
Клиент2 >> Сервер
Сервер >>Клиент 1
А мне нужно что бы сервер работал со всеми клиентами и отправлял пакеты всем клиентам
Клиент1 >> Сервер
Сервер >> Клиент2, Клиент3, Клиент16….
Для этого нужно сделать Массив Ип адресов ну или список, но немогу понять как???
C++1sf::IpAddress sender;как сделать список?
C++12345struct comp {IpAddress ip;int timer;comp* next; //Ссылка на следущий элемент списка};Список http://www.codenet.ru/progr/cpp/dlist.php
Пускай когда клиент подключается ты проверяешь ip на наличие в списке.
Если такой ip есть то обновляешь таймер если нету то добавляешь элемент в список.
Если таймер закончился то удаляешь элемент
Проходишь по списку и всем отправляешь нужные данные
C++12345678910111213141516171819struct a{...a *next;};....a *p = new a;p->next = 0;...a *list1 = p, *list2 = p;....//Вот тут проходишь по спискуwhile (list1->next != 0){list2 = list1;while (list2->next != 0){...//удаляешь где таймер не подходит...//отправляешь,list2 = list2->next;}list1 = list1->next;}Спасибо) Сделал через список, правда для ип адресса использовал string, но я не понял зачем тут таймер, можешь обьяснить?
Если у кого нибудь возник такой же вопрос ( как запихнуть в список ип адреса) то вот рабочий код
C++123456789101112131415161718192021222324252627282930313233struct List{string ip;int port;List *Next, *Head;};void Add(string ip, int port, List *&MyList){List *temp = new List;temp->ip = ip;temp->port = port;temp->Next = MyList->Head;MyList->Head = temp;}void Show(List *MyList){List *temp = MyList->Head;while (temp != NULL){cout << temp->ip << ":" << temp->port << endl;temp = temp->Next;}}void ClearList(List *MyList){while (MyList->Head != NULL){List *temp = MyList->Head->Next;delete MyList->Head;MyList->Head = temp;}}Чтобы получить Ип в клиенте вам нужно отправить данные на сервер (любые)
socket.receive(buffer, sizeof(buffer), received, sender, port);
таким образом принимаем сообщение и добавляем в список
Add(sender.toString(), port, MyList);
Если у кого есть идеи получше пишите)
String не выгодно. Как ты общался используя string? Отправка принимает ip, а не string
Как узнать отключился ли клиент? Тут поможет таймер, если клиент не обновляет данные других игроков в течении 10 секунд, то клиент умер.
А что же тогда использовать вместо string??
C++1234567891011void Proof(List *MyList,string isip,int isport){List *temp = MyList->Head;while (temp != NULL){if (temp->ip != isip || temp->port != isport){Add(isip,isport, MyList);}return;}Вот функция которая проверяет и добавляет нового клиента в список.
Как по мне это оптимальный вариант, я не знаю что можно использовать вместо string.
Ведь Ip (0.0.0.0) не целочисленный тип а кроме как string лучше варианта не вижу, поскольку не знаю..
С таймером понял, но его пока не делал. Наверное сейчас буду реализовывать.
Да, спасибо! Ты был прав по поводу Ip я не знал что что можно так сделать. Если бы ты не подсказал пришлось бы переводить string в ip, каким нибудь образом)
Я столкнулся с парой проблем.
1. Если ты отправляешь данные, а клиент не принимает то программа стоит афк.
2. При передаче матрицы int больше 45×45 последнии строки не передается. Сервер пишет, что отправил, а клиент ждет приема.
В документации были какие-то розетки с таймером ожидания передачи, но я так и не понял как ними пользоваться, по этому оптимальным есть передавать данные тому кто просит, а не всем по списку.
А ты с чем мучаешься TCP/UDP?
Я до этого не дошел, но мне кажется что пинговать сервер/клиент (чтобы знать есть клиент или нету) нужно через некий отдельный канал. то есть: клиент отправляет (в цикле естественно) конкретный пакет! А на сервере его сравнивать. допустим если клиент отправил пакет и этот пакет == нашему пакету. то не удалять из списка.
1. Если ты отправляешь данные, а клиент не принимает то программа стоит афк.
Вот этого не понял , с кодом может быть пойму. Может у тебя проблема с ожиданием
ведь если у сервера/клиента в цикле такая строка то программа замирает пока не получит пакет и строки дальше не читаются.
C++1socket.receive(packet, sender, port);Но это можно легко исправить таким if`ом
C++1234if (socket.receive(packet, sender, port) == sf::Socket::Done){cout << "если пакет получен, то ...";}И тогда даже если пакет не пришел то выполнение кода не стоит а продолжается.
2. При передаче матрицы int больше 45×45 последние строки не передается. Сервер пишет, что отправил, а клиент ждет приема.
Опиши тут то я точно не понял. Массив[45][45]?
А передача частями?
В документации были какие-то розетки с таймером ожидания передачи, но я так и не понял как ними пользоваться, по этому оптимальным есть передавать данные тому кто просит, а не всем по списку.
Можно ссылку. по документации вообще нужно быть осторожным, я оттуда код скописатил, а там была в какойто сторке ошибка имени переменной Func — func как то так. И я 2 часа мучался, и библиотеки подключал( что я короче не делал) но нашел))) злой был пи….ц!)
А вот по поводу Розеток(socket) мне кажется это касалось TCP. Но не уверен.
1. На виртуальных серверах ограниченое количество подключений tcp. Здесь выгодней udp так как не надо резервировать места.
Ссылка на розетки http://www.sfml-dev.org/tutorials/2.3/network-socket.php
Начинается с надписи Blocking on a group of sockets
2. У меня сервер генерировал карту и отправлял клиенту. Нужно передать всю карту, mas[45][45]. Отправлял цыклом, по 45 элементов за передачу. Если масив 46×46 то 46-тая передача не доходила. Клиент знает, что должно прийти 46 писем, по 46 элементов, по этому ждёт, а сервер пишет, что все отправлено. Тут надо быть окуратным.
1. На виртуальных серверах ограниченое количество подключений tcp. Здесь выгодней udp так как не надо резервировать места.
Тут ты имеешь ввиду хостинг??
2. У меня сервер генерировал карту и отправлял клиенту. Нужно передать всю карту, mas[45][45]. Отправлял цыклом, по 45 элементов за передачу. Если масив 46×46 то 46-тая передача не доходила. Клиент знает, что должно прийти 46 писем, по 46 элементов, по этому ждёт, а сервер пишет, что все отправлено. Тут надо быть окуратным.
А ты уверен что карта должна генерироватся на сервере?? Мне кажется что это не целесообразно, как по мне карта генерируется у клиента и все обьекты. и при запросе клиента сервер говорит есть ли некий обьект на карте (моб,дерево,трава) или же нету. Хотя это зависит от твоей задачи, наверно.
Такой вопрос, как ты сделал (если сделал) такую функцию
Клиент 1 >> Сервер
Cервер >> Клиент 2, 3, 4 …
Не могу решить проблем.
socket.recieve(); программа замирает в этом месте если нету принятых пакетов.
думал что if (socket.recieve() != sf::Socket::Done)
исправит это но нифига, все равно программа останавливается в этом месте и ждет пакета, может есть варианты??
mypmyp, в данном случае тебе нужно использовать sf::SocketSelector. Добавляешь в него сокеты, а затем проверяешь методом isReady, если возвращают true => в сокет была записана информация. Вот пример из документации:
C++1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253// Create a socket to listen to new connectionssf::TcpListener listener;listener.listen(55001);// Create a list to store the future clientsstd::list<sf::TcpSocket*> clients;// Create a selectorsf::SocketSelector selector;// Add the listener to the selectorselector.add(listener);// Endless loop that waits for new connectionswhile (running){// Make the selector wait for data on any socketif (selector.wait()){// Test the listenerif (selector.isReady(listener)){// The listener is ready: there is a pending connectionsf::TcpSocket* client = new sf::TcpSocket;if (listener.accept(*client) == sf::Socket::Done){// Add the new client to the clients listclients.push_back(client);// Add the new client to the selector so that we will// be notified when he sends somethingselector.add(*client);}else{// Error, we won't get a new connection, delete the socketdelete client;}}else{// The listener socket is not ready, test all other sockets (the clients)for (std::list<sf::TcpSocket*>::iterator it = clients.begin(); it != clients.end(); ++it){sf::TcpSocket& client = **it;if (selector.isReady(client)){// The client has sent some data, we can receive itsf::Packet packet;if (client.receive(packet) == sf::Socket::Done){...}}}}}}А разве это проканает с UDP???
-
АвторСообщения
Для ответа в этой теме необходимо авторизоваться.