Архитектура приложения с асинхронными сокетами

Подключаем наши девайсы к компьютеру. Обсуждаются: порты, протоколы, драйвера, языки программирования и т.д.
Ответить
Поставщик валерьянки для Кота
Аватара пользователя
Сообщения: 2095
Зарегистрирован: Чт апр 08, 2010 18:50:01
Откуда: Краснодар

Сообщение Кислый »

Я не могу разобраться с асинхронными сокетами, прошу посильной помощи от вас.
Задача следующая :
1. Есть некий сервер, который после подключения клиента может в любой момент прислать данные, и клииент должен успеть их принять.
2. Если пришедший пакет требует ответа, то ответить не медля.
3. В случае некоторого евента ( например нажатия кнопки в окне клиента) отправляем пакет серверу.

Я позолил себе набросать небольшую схему, как я это вижу.

Изображение

Архитектура приложения с асинхронными сокетами
Receive - в цикле, Send - c кнопки и\или ответом. Чего не хватает ?

Чего я не понимаю:
1) как определить что в сокет пришли данные ?
2) можно ли не гонять цикл, а ждать некоторого interrupt , который оповестит о готовности некоторого обьема данных ?
3) ???

Очень надеюсь на вашу помощь. С наступающим новым годом и рождеством !!

Изображение
RETI ;рети-рети интеррапт, через шины данных тракт, через память, через порт, возвращайся в главный код
@hobbyelectronics
Контактная информация:
Реклама
Сверлит текстолит когтями
Аватара пользователя
Сообщения: 1262
Зарегистрирован: Пн дек 08, 2008 10:58:48
Откуда: Винница

Сообщение urry »

.Если винда, то генерируются winsock2.dll (надеюсь, правильно вспомнил, как пишется) 2 события - 1 пришли данные 2 сокет закрыл обмен. Да, это колбэк.
Я на вертепе статью писАл с примером http://vrtp.ru/index.php?act=categories ... ticle=3549



Политику убрал.
Если уж совсем не в "терпеж" то с этим в раздел МЯУ.
aen
Контактная информация:
Реклама
Поставщик валерьянки для Кота
Аватара пользователя
Сообщения: 2095
Зарегистрирован: Чт апр 08, 2010 18:50:01
Откуда: Краснодар

Сообщение Кислый »

Во-первых, не надо ругаться матом вне "Мяу". Во-вторых, матом ругаться вообще вредно : зубные протезы нынче стоят дорого. В третьих, не стоит говорить о людях плохо, тем более за глаза Это смахивает на мелкое пакостничество. В четвертых, я думаю не стоит кидать предьяву мне по поводу постороннего человека! (Собственно поэтому я не люблю фудбольных (и прочих) фанатов)

Да, возвращаясь к теме, я к сожалению забыл написать, что использую Mono : собственно никаких winsock там нет.
RETI ;рети-рети интеррапт, через шины данных тракт, через память, через порт, возвращайся в главный код
@hobbyelectronics
Контактная информация:
Друг Кота
Аватара пользователя
Сообщения: 3385
Зарегистрирован: Пн окт 11, 2010 19:00:08

Сообщение Мурик »

Кислый писал(а):может в любой момент прислать данные, и клииент должен успеть их принять.
Почему не успеет? Данные буферизируются и если что, сетевой протокол предусматривает повторный запрос пакета. Если возникли проблемы с потерей пакетов, то наверное в коде баг.
Кислый писал(а):Если пришедший пакет требует ответа, то ответить не медля.
Какова допустимая задержка? При этом учитываете что при некоторых условиях, даже если ваша программа ответит сразу же (в идеальном случае, в нулевой задержкой) ответ сервер может получить больше чем через секунду.

По моему, для этой задачи достаточно неблокирующих сокетов.
Реклама
Эиком - электронные компоненты и радиодетали
Поставщик валерьянки для Кота
Аватара пользователя
Сообщения: 2095
Зарегистрирован: Чт апр 08, 2010 18:50:01
Откуда: Краснодар

Сообщение Кислый »

Я и хочу использовать неблокирующие сокеты. Поробовал написать короткий код, возникла уйма дополнительных вопросов
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;

namespace l2packet
{
class SocketAsyncClient
{
public Socket client;

public byte[] in_data = new byte[0xFFFF];
public byte[] out_data = new byte[0xFFFF];


public SocketAsyncClient()
{
this.connect (ref client);
while (true) {
this.s_read ();

}
client.Shutdown (SocketShutdown.Both);
client.Close ();
}


public void connect(ref Socket sock)
{
sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
try
{
Console.WriteLine("Сокет успешно создан");
client.Connect("127.0.0.1", 2106);
Console.WriteLine("Соединение успешно установлено");
}
catch (SocketException ex)
{
Console.WriteLine("Ошибка при работе с сокетами: " + ex.Message);
}
}


public int s_read()
{
byte[] data = new byte[1024];
// … заполнение массива data опущено
SocketAsyncEventArgs async_e = new SocketAsyncEventArgs();
async_e.SetBuffer(data, 0, 1024);
async_e.Completed += SocketAsyncCompleted;
client.ReceiveAsync(async_e);
Console.WriteLine("Нажмите любую клавишу");
Console.ReadKey();
Console.WriteLine ("Приняты байты : {0} {1}", data [0], data [1]);
return 0;
}

public int s_send()
{
byte[] data = new byte[1024];
// … заполнение массива data опущено
SocketAsyncEventArgs async_e = new SocketAsyncEventArgs();
async_e.SetBuffer(data, 0, 1024);
async_e.Completed += SocketAsyncCompleted;
client.SendAsync(async_e);
return 0;
}

void SocketAsyncCompleted(object o, SocketAsyncEventArgs e)
{
if(e.LastOperation == SocketAsyncOperation.Send)
{
if(e.SocketError == SocketError.Success)
Console.WriteLine("Передача выполнена успешна");
else
Console.WriteLine("При передаче произошла ошибка");
}
if(e.LastOperation == SocketAsyncOperation.Receive)
{
if(e.SocketError == SocketError.Success)
Console.WriteLine("Прием выполнен успешно");

else
Console.WriteLine("При приеме произошла ошибка");
}
}


}
}
обьясните, почему если нет задержки, обусловленной Console.ReadKey();, то код возвращает пустой массив. как этого избежать ? прошу не путать вопрос с областью видимости. я сознательно обьявляю массив внутри функции, для частоты эксперемента.. так сказать.
Последний раз редактировалось Кислый Чт янв 01, 2015 17:36:46, всего редактировалось 1 раз.
RETI ;рети-рети интеррапт, через шины данных тракт, через память, через порт, возвращайся в главный код
@hobbyelectronics
Контактная информация:
Реклама
Сверлит текстолит когтями
Аватара пользователя
Сообщения: 1262
Зарегистрирован: Пн дек 08, 2008 10:58:48
Откуда: Винница

Сообщение urry »

для начала - мои соболезнования.
далее - насчет "сокетов там нет" - юзаются те же длл - судя по почерку
https://github.com/mono/mono/blob/maste ... /Socket.cs
колбэковские функции и не нужно изобретать велосипед.
Контактная информация:
Реклама
Поставщик валерьянки для Кота
Аватара пользователя
Сообщения: 2095
Зарегистрирован: Чт апр 08, 2010 18:50:01
Откуда: Краснодар

Сообщение Кислый »

urry, не надо хамить и хулиганить. Хочется трололо - идите в мяу.
С коллбаками получится какая-то херня поток на потоке и потоком погоняет.
RETI ;рети-рети интеррапт, через шины данных тракт, через память, через порт, возвращайся в главный код
@hobbyelectronics
Контактная информация:
Друг Кота
Аватара пользователя
Сообщения: 3385
Зарегистрирован: Пн окт 11, 2010 19:00:08

Сообщение Мурик »

Кислый писал(а):Я и хочу использовать неблокирующие сокеты.
Но в коде асинхронные.

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

SocketAsyncEventArgs async_e = new SocketAsyncEventArgs();
Кислый писал(а):обьясните, почему если нет задержки, обусловленной Console.ReadKey();, то код возвращает пустой массив.
Потому что сокет асинхронный. Данные в массив пишутся не в момент вызова функции (метода), а когда они будут приняты. Без задержки массив пустой потому что сервер еще ничего не успел прислать. Лучше используйте неблокирующие сокеты. Или прочитайте про асинхронные сокеты чтобы понимать как они устроены и работают.
Поставщик валерьянки для Кота
Аватара пользователя
Сообщения: 2095
Зарегистрирован: Чт апр 08, 2010 18:50:01
Откуда: Краснодар

Сообщение Кислый »

Хмм.. ничего не путаете ? Асинхронные = неблокирующие :)

подправил до :

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

		public int s_read()
		{
			byte[] data = new byte[1024];
			// … заполнение массива data опущено
			SocketAsyncEventArgs async_e = new SocketAsyncEventArgs();
			async_e.SetBuffer(data, 0, 1024);
			async_e.Completed += SocketAsyncCompleted;
			while (true) {
				if (client.Available > 0) {
					client.ReceiveAsync (async_e);
					Console.WriteLine ("Приняты байты : {0} {1}", data [0], data [1]);
					break;
				}
			}
			return 0;
		}
не слишком убого ?
RETI ;рети-рети интеррапт, через шины данных тракт, через память, через порт, возвращайся в главный код
@hobbyelectronics
Контактная информация:
Друг Кота
Аватара пользователя
Сообщения: 3385
Зарегистрирован: Пн окт 11, 2010 19:00:08

Сообщение Мурик »

Кислый писал(а):Асинхронные = неблокирующие
Это не одно и тоже. Читайте. http://www.programmersforum.ru/showthread.php?t=231061
http://samolisov.blogspot.com/2013/11/java.html
http://hashcode.ru/questions/371655/c-в ... инхронными
http://uinc.ru/articles/23/
Сверлит текстолит когтями
Аватара пользователя
Сообщения: 1262
Зарегистрирован: Пн дек 08, 2008 10:58:48
Откуда: Винница

Сообщение urry »

Я все равно не понимаю суть проблемы. В случае серверного варианта определяется максимальное количество сокетов, производных от листающего, который тот обязан обработать. Каждый новый сокет обмена открывается в своем потоке - это правило хорошего тона, да так, собственно, и проще. Евент акцепт - на открытие потока, евент рид - чтение, евент слозе - закрытие.
Никто ничего нового не придумал. С чего у вас создается сокет при чтении ??? Что он может читать, он не настроен ... При акцепте переписываются из листающего сокета в новый сокет данные - айпишник клиентского, порт...
Контактная информация:
Поставщик валерьянки для Кота
Аватара пользователя
Сообщения: 2095
Зарегистрирован: Чт апр 08, 2010 18:50:01
Откуда: Краснодар

Сообщение Кислый »

urry, должно быть потому, что у меня клиент.
RETI ;рети-рети интеррапт, через шины данных тракт, через память, через порт, возвращайся в главный код
@hobbyelectronics
Контактная информация:
Друг Кота
Аватара пользователя
Сообщения: 3385
Зарегистрирован: Пн окт 11, 2010 19:00:08

Сообщение Мурик »

urry писал(а):Каждый новый сокет обмена открывается в своем потоке - это правило хорошего тона
Что за ересь? :shock: :shock: :o :o
Знаете что число потоков ограничено? Если делать по нормальному, достаточно одного параллельного потока для множества коннектов, как в случае клиента, так в случае сервера.
За примером далеко ходить не надо. У вас есть торрент-клиент? Он кроме установки коннектов (т. е. выполнения роли клиента) создает так же сервер для входящих соединений. Посмотрите сколько создается потоков. Это расходится с вашим предложением! Правило хорошего тона, наоборот, использовать как можно меньше потоков если задачу можно решить без них.
Сверлит текстолит когтями
Аватара пользователя
Сообщения: 1262
Зарегистрирован: Пн дек 08, 2008 10:58:48
Откуда: Винница

Сообщение urry »

urry, должно быть потому, что у меня клиент.
И что ? После посылки коннекта серверу, если коннект прошел, кстати, только после этого разрешается взводить евент на прием данных. сколько серверов - столько и клиентских потоков. Один - достаточно одного.
Что за ересь?
:) Посмотрите количество потоков вашего браузера - любого...
Контактная информация:
Друг Кота
Аватара пользователя
Сообщения: 3385
Зарегистрирован: Пн окт 11, 2010 19:00:08

Сообщение Мурик »

urry писал(а):Посмотрите количество потоков вашего браузера - любого
Число потоков около десятка и не меняется при открытии/закрытии вкладок/страниц. Видимо число потоков не имеет прямого отношения к работе с сетью.
Сверлит текстолит когтями
Аватара пользователя
Сообщения: 1262
Зарегистрирован: Пн дек 08, 2008 10:58:48
Откуда: Винница

Сообщение urry »

http://msdn.microsoft.com/ru-ru/library/dd335942.aspx
:) У нас разные браузеры. По опыту работы - многопотоковый вывод быстрее. Я не имею в виду 4000 потоков, естественно, обычные рабочие задачи. 2 года назад пришлось очень плотно работать по этой теме, так что можете поверить на слово.
С другой стороны - никто не мешает наступить на грабли самостоятельно. :)
Контактная информация:
Друг Кота
Аватара пользователя
Сообщения: 3385
Зарегистрирован: Пн окт 11, 2010 19:00:08

Сообщение Мурик »

urry писал(а):многопотоковый вывод быстрее.
urry писал(а):никто не мешает наступить на грабли самостоятельно. :)
Про грабли могу аналогичное сказать когда будете синхронизировать 1500 потоков. И из-за этого скорость получится куда меньше чем для однопоточного режима.
Для работы сервера/клиента достаточно одного потока и неважно сколько будет соединений.
Сверлит текстолит когтями
Аватара пользователя
Сообщения: 1262
Зарегистрирован: Пн дек 08, 2008 10:58:48
Откуда: Винница

Сообщение urry »

я не буду синхронизировать 1500 потоков - нет такой задачи. До полсотни клиентов довольно резво вязались вместе - каждый на своем потоке. Эта задача мной была реализована, в одном потоке я бы ее не решал, образование не позволяет.
Впрочем, пошел флуд... Свой вариант в 1 потоке я показал в начале ветки, ваш ?
"Слова ничего не значат, покажите код" (с) Линус Торвальдс
Контактная информация:
Друг Кота
Аватара пользователя
Сообщения: 3385
Зарегистрирован: Пн окт 11, 2010 19:00:08

Сообщение Мурик »

urry писал(а):Свой вариант в 1 потоке я показал в начале ветки, ваш ?
Что за детский сад?
Как это поможет ТС?
Я писал выше что по возможности работать с сетью лучше из одного потока. И это был ответ на ваше ИМХО сбивающее столку высказывание.
urry писал(а):Каждый новый сокет обмена открывается в своем потоке - это правило хорошего тона
Если вы считаете что правило хорошего тона, это работа каждым соединением в отдельном параллельном потоке, плиз встудию линки на авторитетные источники где это доказано.
Ответить

Вернуться в «Интеграция с ПК»